1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19 20 21 22 23 24 25 26 27 28 29 30 31 32 33 34 35 36 37 38 39 40 41 42 43 44 45 46 47 48 49 50 51 52 53 54 55 56 57 58 59 60 61 62 63 64 65 66 67 68 69 70 71 72 73 74 75 76 77 78 79 80 81 82 83 84 85 86 87 88 89 90 91 92 93 94 95 96 97 98 99 100 101 102 103 104 105 106 107 108 109 110 111 112 113 114 115
use euclid::{Angle, Point2D, Vector2D}; use std::time::Duration; /// A point inside the game arena, in terms of pixels. See [`euclid` documentation] /// for its API, but you can assume all the basic linear algebra operations are /// supported e.g. addition, subtraction, and interpolation (aka `lerp`). /// /// [`euclid` documentation]: https://docs.rs/euclid/0.19.6/euclid/struct.TypedPoint2D.html pub type Point = Point2D<f32>; /// A vector inside the game arena, in terms of pixels. It's mostly used to /// represent a velocity. See [`euclid` documentation] for its API, but you can /// assume all the basic linear algebra operations are supported e.g. addition, /// subtraction, magnitude (aka `length`), angle conversion (aka /// `angle_from_x_axis`), dot and cross product. /// /// [`euclid` documentation]: https://docs.rs/euclid/0.19.6/euclid/struct.TypedVector2D.html pub type Vector = Vector2D<f32>; /// The game server expects angles to be in radians. See [`euclid` documentation] /// for its API, but you'll mostly need `new` to create and `get` to retrieve /// radians. `Radian::degrees` method crates `Radian` from a value in degrees, which may /// be handy. `Radian::positive` may also be useful if you want to normalize the /// radian to be [0, 2PI). /// /// [`euclid` documentation]: https://docs.rs/euclid/0.19.6/euclid/struct.Angle.html pub type Radian = Angle<f32>; trait AsSecsF32 { fn as_secs_f32(&self) -> f32; } impl AsSecsF32 for Duration { fn as_secs_f32(&self) -> f32 { self.as_nanos() as f32 / 1e9 } } /// Extension methods for the `Point` type alias. pub trait PointExt { fn point(&self) -> &Point; /// Returns the distance between this and the given points. fn distance(&self, other: &PointExt) -> f32 { (*other.point() - *self.point()).length() } /// Returns the angle of the line connecting this point to the given point. fn angle_to(&self, other: &PointExt) -> Radian { (*other.point() - *self.point()).angle_from_x_axis() } /// Returns the velocity at which one travels from this point to the given /// point for the amount of time `dt`. fn velocity_to(&self, other: &PointExt, dt: Duration) -> Vector { (*other.point() - *self.point()) / dt.as_secs_f32() } /// Returns the projection of this position along the given `velocity` /// (pixels-per-second) for the amount of time `dt`. fn project(&self, velocity: &Vector, dt: Duration) -> Point { *self.point() + *velocity * dt.as_secs_f32() } } impl PointExt for Point { fn point(&self) -> &Point { self } } /// Extension methods for the `Vector` type alias. pub trait VectorExt { fn vector(&self) -> &Vector; /// Creates a new `Vector` from an angle, from the X axis. fn with_angle(angle: Radian) -> Vector { let sin_cos = angle.sin_cos(); Vector::new(sin_cos.1, sin_cos.0) } /// Returns an angle that is tangent to this `Vector`. Maybe useful for your /// dodging behavior. fn tangent(&self) -> Radian { (self.vector().angle_from_x_axis() + Radian::frac_pi_2()).positive() } } impl VectorExt for Vector { fn vector(&self) -> &Vector { self } } /// Extension methods for the `Radian` type alias. pub trait RadianExt { fn radian(&self) -> &Radian; /// Creates a new `Radian` based on a raw value in radians. fn new(radians: f32) -> Radian { Radian::radians(radians) } /// Returns a `Radian` whose radian value is `abs()`ed. Not to be confused /// with `positive()` method, which is for normalization. fn abs(&self) -> Radian { Radian::radians(self.radian().radians.abs()) } } impl RadianExt for Radian { fn radian(&self) -> &Radian { self } }