From d30d1b57df45f5dc94ba37fb70cca349102fd270 Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Adolfo=20Ochagav=C3=ADa?= Date: Tue, 28 Feb 2017 09:03:20 +0100 Subject: [PATCH] Normalize line endings --- LICENSE.md | 42 +++++----- readme.md | 116 +++++++++++++------------- src/drawing/mod.rs | 32 ++++---- src/drawing/point.rs | 96 +++++++++++----------- src/drawing/size.rs | 66 +++++++-------- src/models/bullet.rs | 84 +++++++++---------- src/models/enemy.rs | 78 +++++++++--------- src/models/mod.rs | 32 ++++---- src/models/particle.rs | 80 +++++++++--------- src/models/player.rs | 100 +++++++++++------------ src/models/vector.rs | 110 ++++++++++++------------- src/models/world.rs | 90 ++++++++++----------- src/traits/mod.rs | 180 ++++++++++++++++++++--------------------- 13 files changed, 553 insertions(+), 553 deletions(-) diff --git a/LICENSE.md b/LICENSE.md index 5027c8b..e03217b 100644 --- a/LICENSE.md +++ b/LICENSE.md @@ -1,21 +1,21 @@ -The MIT License (MIT) - -Copyright (c) 2015 Adolfo Ochagavía - -Permission is hereby granted, free of charge, to any person obtaining a copy -of this software and associated documentation files (the "Software"), to deal -in the Software without restriction, including without limitation the rights -to use, copy, modify, merge, publish, distribute, sublicense, and/or sell -copies of the Software, and to permit persons to whom the Software is -furnished to do so, subject to the following conditions: - -The above copyright notice and this permission notice shall be included in -all copies or substantial portions of the Software. - -THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR -IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, -FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE -AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER -LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, -OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN -THE SOFTWARE. +The MIT License (MIT) + +Copyright (c) 2015 Adolfo Ochagavía + +Permission is hereby granted, free of charge, to any person obtaining a copy +of this software and associated documentation files (the "Software"), to deal +in the Software without restriction, including without limitation the rights +to use, copy, modify, merge, publish, distribute, sublicense, and/or sell +copies of the Software, and to permit persons to whom the Software is +furnished to do so, subject to the following conditions: + +The above copyright notice and this permission notice shall be included in +all copies or substantial portions of the Software. + +THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR +IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, +FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE +AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER +LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, +OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN +THE SOFTWARE. diff --git a/readme.md b/readme.md index c14afcf..793f13b 100644 --- a/readme.md +++ b/readme.md @@ -1,59 +1,59 @@ -Rocket -====== - -[![Travis Build Status][travis-build-status-svg]][travis-build-status] -[![AppVeyor Build Status][appveyor-build-status-svg]][appveyor-build-status] - -> Rocket is a toy game written in Rust, using the Piston library. The code is thoroughly -commented in order to help people to follow it easily. - -## Screenshots - -![Screenshot](screenshots/gameplay2.png) - -You can find more screenshots in the [screenshots] directory. - -[screenshots]: screenshots/ - -## How to play - -As you can see in the screenshots below, you are the red rocket and have to save the world from -the yellow invaders. To do so, you can use the following controls: - -Keyboard | Action ------------------------ | ------------ - | Boost - | Rotate left - | Rotate right -Space | Shoot - -## Requirements - -Rocket targets the latest stable version of Rust. - -### Running it with Cargo - -As always, it is a real pleasure to work with Cargo. You only need the following: - -``` -cargo run --release -``` - -## Why? - -After having implemented some toy games in C++ using SDL and SFML, I thought it would be a -good idea to try the same in Rust. Additionally, I had written a similar game in Haskell and -wanted to port it to see the similarities and differences between Haskell and Rust. Another -reason to program this game was to have an easy to follow Rust project that could be useful -for people learning the language. - -## License - -MIT - - -[travis-build-status]: https://travis-ci.org/aochagavia/rocket -[travis-build-status-svg]: https://travis-ci.org/aochagavia/rocket.svg - -[appveyor-build-status]: https://ci.appveyor.com/project/aochagavia/rocket +Rocket +====== + +[![Travis Build Status][travis-build-status-svg]][travis-build-status] +[![AppVeyor Build Status][appveyor-build-status-svg]][appveyor-build-status] + +> Rocket is a toy game written in Rust, using the Piston library. The code is thoroughly +commented in order to help people to follow it easily. + +## Screenshots + +![Screenshot](screenshots/gameplay2.png) + +You can find more screenshots in the [screenshots] directory. + +[screenshots]: screenshots/ + +## How to play + +As you can see in the screenshots below, you are the red rocket and have to save the world from +the yellow invaders. To do so, you can use the following controls: + +Keyboard | Action +----------------------- | ------------ + | Boost + | Rotate left + | Rotate right +Space | Shoot + +## Requirements + +Rocket targets the latest stable version of Rust. + +### Running it with Cargo + +As always, it is a real pleasure to work with Cargo. You only need the following: + +``` +cargo run --release +``` + +## Why? + +After having implemented some toy games in C++ using SDL and SFML, I thought it would be a +good idea to try the same in Rust. Additionally, I had written a similar game in Haskell and +wanted to port it to see the similarities and differences between Haskell and Rust. Another +reason to program this game was to have an easy to follow Rust project that could be useful +for people learning the language. + +## License + +MIT + + +[travis-build-status]: https://travis-ci.org/aochagavia/rocket +[travis-build-status-svg]: https://travis-ci.org/aochagavia/rocket.svg + +[appveyor-build-status]: https://ci.appveyor.com/project/aochagavia/rocket [appveyor-build-status-svg]: https://ci.appveyor.com/api/projects/status/its182aar6vol45b?svg=true \ No newline at end of file diff --git a/src/drawing/mod.rs b/src/drawing/mod.rs index b5f9039..5de898e 100644 --- a/src/drawing/mod.rs +++ b/src/drawing/mod.rs @@ -1,16 +1,16 @@ -//! Helper objects and constants - -mod point; -mod size; - -pub mod color { - pub const BLACK: [f32; 4] = [0.0, 0.0, 0.0, 1.0]; - pub const BLUE: [f32; 4] = [0.0, 0.0, 1.0, 1.0]; - pub const ORANGE: [f32; 4] = [1.0, 0.5, 0.0, 1.0]; - pub const RED: [f32; 4] = [1.0, 0.0, 0.0, 1.0]; - pub const VIOLET: [f32; 4] = [0.6, 0.0, 1.0, 1.0]; - pub const YELLOW: [f32; 4] = [1.0, 1.0, 0.0, 1.0]; -} - -pub use self::point::Point; -pub use self::size::Size; +//! Helper objects and constants + +mod point; +mod size; + +pub mod color { + pub const BLACK: [f32; 4] = [0.0, 0.0, 0.0, 1.0]; + pub const BLUE: [f32; 4] = [0.0, 0.0, 1.0, 1.0]; + pub const ORANGE: [f32; 4] = [1.0, 0.5, 0.0, 1.0]; + pub const RED: [f32; 4] = [1.0, 0.0, 0.0, 1.0]; + pub const VIOLET: [f32; 4] = [0.6, 0.0, 1.0, 1.0]; + pub const YELLOW: [f32; 4] = [1.0, 1.0, 0.0, 1.0]; +} + +pub use self::point::Point; +pub use self::size::Size; diff --git a/src/drawing/point.rs b/src/drawing/point.rs index 590db81..b4e23cc 100644 --- a/src/drawing/point.rs +++ b/src/drawing/point.rs @@ -1,48 +1,48 @@ -use rand::Rng; - -use super::Size; - -/// A `Point` represents a position in space -#[derive(Clone, Default)] -pub struct Point { - pub x: f64, - pub y: f64 -} - -impl Point { - /// Returns a new `Point` with the given coordinates - pub fn new(x: f64, y: f64) -> Point { - Point { x: x, y: y } - } - - /// Returns a random `Point` within the given bounds (exclusive) - pub fn random(rng: &mut R, bounds: Size) -> Point { - Point { - x: rng.gen_range(0.0, bounds.width), - y: rng.gen_range(0.0, bounds.height) - } - } - - /// Returns the squared distance from this point to the given one - pub fn squared_distance_to(&self, target: &Point) -> f64 { - (self.x - target.x) * (self.x - target.x) - + (self.y - target.y) * (self.y - target.y) - } - - /// Rotates the point through the origin in the given angle (radians) - pub fn rotate(mut self, radians: f64) -> Point { - let radius = (self.x * self.x + self.y * self.y).sqrt(); - let point_angle = (self.y / self.x).atan(); - let final_angle = point_angle + radians; - self.x = final_angle.cos() * radius; - self.y = final_angle.sin() * radius; - self - } - - /// Translates the point by another point - pub fn translate(mut self, other: &Point) -> Point { - self.x += other.x; - self.y += other.y; - self - } -} +use rand::Rng; + +use super::Size; + +/// A `Point` represents a position in space +#[derive(Clone, Default)] +pub struct Point { + pub x: f64, + pub y: f64 +} + +impl Point { + /// Returns a new `Point` with the given coordinates + pub fn new(x: f64, y: f64) -> Point { + Point { x: x, y: y } + } + + /// Returns a random `Point` within the given bounds (exclusive) + pub fn random(rng: &mut R, bounds: Size) -> Point { + Point { + x: rng.gen_range(0.0, bounds.width), + y: rng.gen_range(0.0, bounds.height) + } + } + + /// Returns the squared distance from this point to the given one + pub fn squared_distance_to(&self, target: &Point) -> f64 { + (self.x - target.x) * (self.x - target.x) + + (self.y - target.y) * (self.y - target.y) + } + + /// Rotates the point through the origin in the given angle (radians) + pub fn rotate(mut self, radians: f64) -> Point { + let radius = (self.x * self.x + self.y * self.y).sqrt(); + let point_angle = (self.y / self.x).atan(); + let final_angle = point_angle + radians; + self.x = final_angle.cos() * radius; + self.y = final_angle.sin() * radius; + self + } + + /// Translates the point by another point + pub fn translate(mut self, other: &Point) -> Point { + self.x += other.x; + self.y += other.y; + self + } +} diff --git a/src/drawing/size.rs b/src/drawing/size.rs index 010f8af..08dc600 100644 --- a/src/drawing/size.rs +++ b/src/drawing/size.rs @@ -1,33 +1,33 @@ -use rand::Rng; - -use super::Point; - -/// A `Size` represents a region in space -#[derive(Clone, Copy, Default)] -pub struct Size { - pub width: f64, - pub height: f64 -} - -impl Size { - /// Returns a new `Size` of the given dimensions - pub fn new(width: f64, height: f64) -> Size { - Size { width: width, height: height } - } - - /// Returns true if the `Point` is contained in this `Size` or false otherwise - pub fn contains(&self, point: Point) -> bool { - 0.0 <= point.x && point.x <= self.width - && 0.0 <= point.y && point.y <= self.height - } - - /// Returns a random x coordinate within the bounds of this `Size` - pub fn random_x(&self, rng: &mut R) -> f64 { - rng.gen_range(0.0, self.width) - } - - /// Returns a random y coordinate within the bounds of this `Size` - pub fn random_y(&self, rng: &mut R) -> f64 { - rng.gen_range(0.0, self.height) - } -} +use rand::Rng; + +use super::Point; + +/// A `Size` represents a region in space +#[derive(Clone, Copy, Default)] +pub struct Size { + pub width: f64, + pub height: f64 +} + +impl Size { + /// Returns a new `Size` of the given dimensions + pub fn new(width: f64, height: f64) -> Size { + Size { width: width, height: height } + } + + /// Returns true if the `Point` is contained in this `Size` or false otherwise + pub fn contains(&self, point: Point) -> bool { + 0.0 <= point.x && point.x <= self.width + && 0.0 <= point.y && point.y <= self.height + } + + /// Returns a random x coordinate within the bounds of this `Size` + pub fn random_x(&self, rng: &mut R) -> f64 { + rng.gen_range(0.0, self.width) + } + + /// Returns a random y coordinate within the bounds of this `Size` + pub fn random_y(&self, rng: &mut R) -> f64 { + rng.gen_range(0.0, self.height) + } +} diff --git a/src/models/bullet.rs b/src/models/bullet.rs index a9a318e..f91973c 100644 --- a/src/models/bullet.rs +++ b/src/models/bullet.rs @@ -1,42 +1,42 @@ -use drawing::color; -use super::Vector; -use traits::{Advance, Collide, Position}; - -use opengl_graphics::GlGraphics; -use piston_window::{Context, ellipse}; - -/// Bullets are spawned when the player shoots -/// -/// When an enemy is reached by a bullet, it will explode -pub struct Bullet { - vector: Vector -} - -derive_position_direction!(Bullet); - -impl Bullet { - /// Create a bullet with the given vector - pub fn new(vector: Vector) -> Bullet { - Bullet { vector: vector } - } - - /// Draw the bullet - pub fn draw(&self, c: &Context, gl: &mut GlGraphics) { - ellipse(color::BLUE, - [self.x() - self.radius(), - self.y() - self.radius(), - self.diameter(), - self.diameter()], - c.transform, - gl); - } - - /// Update the bullet's position - pub fn update(&mut self, units: f64) { - self.advance(units); - } -} - -impl Collide for Bullet { - fn radius(&self) -> f64 { 3.0 } -} +use drawing::color; +use super::Vector; +use traits::{Advance, Collide, Position}; + +use opengl_graphics::GlGraphics; +use piston_window::{Context, ellipse}; + +/// Bullets are spawned when the player shoots +/// +/// When an enemy is reached by a bullet, it will explode +pub struct Bullet { + vector: Vector +} + +derive_position_direction!(Bullet); + +impl Bullet { + /// Create a bullet with the given vector + pub fn new(vector: Vector) -> Bullet { + Bullet { vector: vector } + } + + /// Draw the bullet + pub fn draw(&self, c: &Context, gl: &mut GlGraphics) { + ellipse(color::BLUE, + [self.x() - self.radius(), + self.y() - self.radius(), + self.diameter(), + self.diameter()], + c.transform, + gl); + } + + /// Update the bullet's position + pub fn update(&mut self, units: f64) { + self.advance(units); + } +} + +impl Collide for Bullet { + fn radius(&self) -> f64 { 3.0 } +} diff --git a/src/models/enemy.rs b/src/models/enemy.rs index 3d82d2b..6640c03 100644 --- a/src/models/enemy.rs +++ b/src/models/enemy.rs @@ -1,39 +1,39 @@ -use drawing::{color, Point}; -use super::Vector; -use traits::{Advance, Collide, Position}; - -use opengl_graphics::GlGraphics; -use piston_window::{Context, ellipse}; - -/// Enemies follow the player in order to cause a collision and let him explode -pub struct Enemy { - vector: Vector -} - -derive_position_direction!(Enemy); - -impl Enemy { - /// Create a enemy with the given vector - pub fn new(vector: Vector) -> Enemy { - Enemy { vector: vector } - } - - /// Draw the enemy - pub fn draw(&self, c: &Context, gl: &mut GlGraphics) { - ellipse(color::YELLOW, - [self.x() - 10.0, self.y() - 10.0, 20.0, 20.0], - c.transform, - gl); - } - - /// Update the enemy - pub fn update(&mut self, speed: f64, player_position: Point) { - // Point to the player - self.point_to(player_position); - self.advance(speed); - } -} - -impl Collide for Enemy { - fn radius(&self) -> f64 { 10.0 } -} +use drawing::{color, Point}; +use super::Vector; +use traits::{Advance, Collide, Position}; + +use opengl_graphics::GlGraphics; +use piston_window::{Context, ellipse}; + +/// Enemies follow the player in order to cause a collision and let him explode +pub struct Enemy { + vector: Vector +} + +derive_position_direction!(Enemy); + +impl Enemy { + /// Create a enemy with the given vector + pub fn new(vector: Vector) -> Enemy { + Enemy { vector: vector } + } + + /// Draw the enemy + pub fn draw(&self, c: &Context, gl: &mut GlGraphics) { + ellipse(color::YELLOW, + [self.x() - 10.0, self.y() - 10.0, 20.0, 20.0], + c.transform, + gl); + } + + /// Update the enemy + pub fn update(&mut self, speed: f64, player_position: Point) { + // Point to the player + self.point_to(player_position); + self.advance(speed); + } +} + +impl Collide for Enemy { + fn radius(&self) -> f64 { 10.0 } +} diff --git a/src/models/mod.rs b/src/models/mod.rs index e869e1f..293fa10 100644 --- a/src/models/mod.rs +++ b/src/models/mod.rs @@ -1,16 +1,16 @@ -// macro_use needs to go first so the macro is visible for the other modules -#[macro_use] -mod vector; - -mod bullet; -mod enemy; -mod particle; -mod player; -mod world; - -pub use self::bullet::Bullet; -pub use self::enemy::Enemy; -pub use self::particle::Particle; -pub use self::player::Player; -pub use self::vector::Vector; -pub use self::world::World; +// macro_use needs to go first so the macro is visible for the other modules +#[macro_use] +mod vector; + +mod bullet; +mod enemy; +mod particle; +mod player; +mod world; + +pub use self::bullet::Bullet; +pub use self::enemy::Enemy; +pub use self::particle::Particle; +pub use self::player::Player; +pub use self::vector::Vector; +pub use self::world::World; diff --git a/src/models/particle.rs b/src/models/particle.rs index a213632..ea7c4a2 100644 --- a/src/models/particle.rs +++ b/src/models/particle.rs @@ -1,40 +1,40 @@ -use drawing::color; -use super::Vector; -use traits::{Advance, Position}; - -use opengl_graphics::GlGraphics; -use piston_window::{Context, ellipse}; - -/// A model representing a particle -/// -/// Particles are visible objects that have a time to live and move around -/// in a given direction until their time is up. They are spawned when the -/// player or an enemy is killed -pub struct Particle { - pub vector: Vector, - pub ttl: f64 -} - -derive_position_direction!(Particle); - -impl Particle { - /// Create a particle with the given vector and time to live in seconds - pub fn new(vector: Vector, ttl: f64) -> Particle { - Particle { vector: vector, ttl: ttl } - } - - /// Draw the particle - pub fn draw(&self, c: &Context, gl: &mut GlGraphics) { - let radius = 5.0 * self.ttl; - ellipse(color::VIOLET, - [self.x() - radius, self.y() - radius, radius * 2.0, radius * 2.0], - c.transform, gl); - } - - /// Update the particle - pub fn update(&mut self, elapsed_time: f64) { - self.ttl -= elapsed_time; - let speed = 500.0 * self.ttl * self.ttl; - self.advance(elapsed_time * speed); - } -} +use drawing::color; +use super::Vector; +use traits::{Advance, Position}; + +use opengl_graphics::GlGraphics; +use piston_window::{Context, ellipse}; + +/// A model representing a particle +/// +/// Particles are visible objects that have a time to live and move around +/// in a given direction until their time is up. They are spawned when the +/// player or an enemy is killed +pub struct Particle { + pub vector: Vector, + pub ttl: f64 +} + +derive_position_direction!(Particle); + +impl Particle { + /// Create a particle with the given vector and time to live in seconds + pub fn new(vector: Vector, ttl: f64) -> Particle { + Particle { vector: vector, ttl: ttl } + } + + /// Draw the particle + pub fn draw(&self, c: &Context, gl: &mut GlGraphics) { + let radius = 5.0 * self.ttl; + ellipse(color::VIOLET, + [self.x() - radius, self.y() - radius, radius * 2.0, radius * 2.0], + c.transform, gl); + } + + /// Update the particle + pub fn update(&mut self, elapsed_time: f64) { + self.ttl -= elapsed_time; + let speed = 500.0 * self.ttl * self.ttl; + self.advance(elapsed_time * speed); + } +} diff --git a/src/models/player.rs b/src/models/player.rs index fa94ed9..2c9f822 100644 --- a/src/models/player.rs +++ b/src/models/player.rs @@ -1,50 +1,50 @@ -use opengl_graphics::GlGraphics; -use piston_window::{Context, polygon, Transformed}; -use rand::Rng; - -use drawing::{color, Point, Size}; -use super::Vector; -use traits::{Advance, Collide, Position}; - -/// The `Player` is the rocket controlled by the user -#[derive(Default)] -pub struct Player { - pub vector: Vector -} - -derive_position_direction!(Player); - -/// The player is drawn as the triangle below -const POLYGON: &'static [[f64; 2]] = &[ - [0.0, -8.0], - [20.0, 0.0], - [0.0, 8.0] -]; - -impl Player { - /// Create a new `Player` with a random position and direction - pub fn random(rng: &mut R, bounds: Size) -> Player { - Player { vector: Vector::random(rng, bounds) } - } - - /// Draw the player - pub fn draw(&self, c: &Context, gl: &mut GlGraphics) { - // Set the center of the player as the origin and rotate it - let transform = c.transform.trans(self.x(), self.y()) - .rot_rad(self.direction()); - - // Draw a rectangle on the position of the player - polygon(color::RED, POLYGON, transform, gl); - } - - /// Returns the nose of the rocket - pub fn nose(&self) -> Point { - Point::new(POLYGON[1][0], POLYGON[1][1]) - .rotate(self.direction()) - .translate(&self.position()) - } -} - -impl Collide for Player { - fn radius(&self) -> f64 { 6.0 } -} +use opengl_graphics::GlGraphics; +use piston_window::{Context, polygon, Transformed}; +use rand::Rng; + +use drawing::{color, Point, Size}; +use super::Vector; +use traits::{Advance, Collide, Position}; + +/// The `Player` is the rocket controlled by the user +#[derive(Default)] +pub struct Player { + pub vector: Vector +} + +derive_position_direction!(Player); + +/// The player is drawn as the triangle below +const POLYGON: &'static [[f64; 2]] = &[ + [0.0, -8.0], + [20.0, 0.0], + [0.0, 8.0] +]; + +impl Player { + /// Create a new `Player` with a random position and direction + pub fn random(rng: &mut R, bounds: Size) -> Player { + Player { vector: Vector::random(rng, bounds) } + } + + /// Draw the player + pub fn draw(&self, c: &Context, gl: &mut GlGraphics) { + // Set the center of the player as the origin and rotate it + let transform = c.transform.trans(self.x(), self.y()) + .rot_rad(self.direction()); + + // Draw a rectangle on the position of the player + polygon(color::RED, POLYGON, transform, gl); + } + + /// Returns the nose of the rocket + pub fn nose(&self) -> Point { + Point::new(POLYGON[1][0], POLYGON[1][1]) + .rotate(self.direction()) + .translate(&self.position()) + } +} + +impl Collide for Player { + fn radius(&self) -> f64 { 6.0 } +} diff --git a/src/models/vector.rs b/src/models/vector.rs index d1b0575..6f5f853 100644 --- a/src/models/vector.rs +++ b/src/models/vector.rs @@ -1,55 +1,55 @@ -use std::f64; - -use rand::Rng; - -use drawing::{Point, Size}; - -/// A `Vector` -#[derive(Clone, Default)] -pub struct Vector { - /// The position of the vector - pub position: Point, - /// The direction angle, in radians - pub direction: f64 -} - -impl Vector { - /// Returns a new `Vector` - pub fn new(position: Point, direction: f64) -> Vector { - Vector { position: position, direction: direction } - } - - /// Returns a random `Vector` within the given bounds - pub fn random(rng: &mut R, bounds: Size) -> Vector { - Vector::new(Point::random(rng, bounds), rng.gen()) - } - - /// Consumes the vector and returns a new one with inverted direction - pub fn invert(mut self) -> Vector { - self.direction -= f64::consts::PI; - self - } -} - -/// A macro to implement `Position` and `Direction` for any type that has a field named `vector` -#[macro_export] -macro_rules! derive_position_direction { - ($t:ty) => { - impl ::traits::Position for $t { - fn x(&self) -> f64 { self.vector.position.x } - fn x_mut(&mut self) -> &mut f64 { &mut self.vector.position.x } - fn y(&self) -> f64 { self.vector.position.y } - fn y_mut(&mut self) -> &mut f64 { &mut self.vector.position.y } - } - - impl ::traits::Advance for $t { - fn direction(&self) -> f64 { - self.vector.direction - } - - fn direction_mut(&mut self) -> &mut f64 { - &mut self.vector.direction - } - } - } -} +use std::f64; + +use rand::Rng; + +use drawing::{Point, Size}; + +/// A `Vector` +#[derive(Clone, Default)] +pub struct Vector { + /// The position of the vector + pub position: Point, + /// The direction angle, in radians + pub direction: f64 +} + +impl Vector { + /// Returns a new `Vector` + pub fn new(position: Point, direction: f64) -> Vector { + Vector { position: position, direction: direction } + } + + /// Returns a random `Vector` within the given bounds + pub fn random(rng: &mut R, bounds: Size) -> Vector { + Vector::new(Point::random(rng, bounds), rng.gen()) + } + + /// Consumes the vector and returns a new one with inverted direction + pub fn invert(mut self) -> Vector { + self.direction -= f64::consts::PI; + self + } +} + +/// A macro to implement `Position` and `Direction` for any type that has a field named `vector` +#[macro_export] +macro_rules! derive_position_direction { + ($t:ty) => { + impl ::traits::Position for $t { + fn x(&self) -> f64 { self.vector.position.x } + fn x_mut(&mut self) -> &mut f64 { &mut self.vector.position.x } + fn y(&self) -> f64 { self.vector.position.y } + fn y_mut(&mut self) -> &mut f64 { &mut self.vector.position.y } + } + + impl ::traits::Advance for $t { + fn direction(&self) -> f64 { + self.vector.direction + } + + fn direction_mut(&mut self) -> &mut f64 { + &mut self.vector.direction + } + } + } +} diff --git a/src/models/world.rs b/src/models/world.rs index e6e7964..836b9c2 100644 --- a/src/models/world.rs +++ b/src/models/world.rs @@ -1,45 +1,45 @@ -use opengl_graphics::GlGraphics; -use piston_window::{Context}; -use rand::Rng; - -use drawing::Size; -use models::{Bullet, Enemy, Particle, Player}; - -/// A model that contains the other models and renders them -pub struct World { - pub player: Player, - pub particles: Vec, - pub bullets: Vec, - pub enemies: Vec, - pub size: Size -} - -impl World { - /// Returns a new world of the given size - pub fn new(rng: &mut R, size: Size) -> World { - World { - player: Player::random(rng, size), - particles: Vec::with_capacity(1000), - bullets: vec![], - enemies: vec![], - size: size - } - } - - /// Renders the world and everything in it - pub fn render(&self, c: Context, g: &mut GlGraphics) { - for particle in &self.particles { - particle.draw(&c, g); - } - - for bullet in &self.bullets { - bullet.draw(&c, g); - } - - for enemy in &self.enemies { - enemy.draw(&c, g); - } - - self.player.draw(&c, g); - } -} +use opengl_graphics::GlGraphics; +use piston_window::{Context}; +use rand::Rng; + +use drawing::Size; +use models::{Bullet, Enemy, Particle, Player}; + +/// A model that contains the other models and renders them +pub struct World { + pub player: Player, + pub particles: Vec, + pub bullets: Vec, + pub enemies: Vec, + pub size: Size +} + +impl World { + /// Returns a new world of the given size + pub fn new(rng: &mut R, size: Size) -> World { + World { + player: Player::random(rng, size), + particles: Vec::with_capacity(1000), + bullets: vec![], + enemies: vec![], + size: size + } + } + + /// Renders the world and everything in it + pub fn render(&self, c: Context, g: &mut GlGraphics) { + for particle in &self.particles { + particle.draw(&c, g); + } + + for bullet in &self.bullets { + bullet.draw(&c, g); + } + + for enemy in &self.enemies { + enemy.draw(&c, g); + } + + self.player.draw(&c, g); + } +} diff --git a/src/traits/mod.rs b/src/traits/mod.rs index 7206c9c..e4a5b43 100644 --- a/src/traits/mod.rs +++ b/src/traits/mod.rs @@ -1,90 +1,90 @@ -//! Traits used by the models - -use std::f64; - -use drawing::{Point, Size}; - -/// A trait for objects that occupy a position in space -pub trait Position { - /// Returns the x coordinate of the object - fn x(&self) -> f64; - - /// Returns a mutable reference to the x coordinate - fn x_mut(&mut self) -> &mut f64; - - /// Returns the y coordinate of the object - fn y(&self) -> f64; - - /// Returns a mutable reference to the y coordinate - fn y_mut(&mut self) -> &mut f64; - - /// Returns the position of the object - fn position(&self) -> Point { - Point::new(self.x(), self.y()) - } -} - -/// A trait for objects that have can move in a given direction -pub trait Advance: Position { - /// Returns the direction of the object, measured in radians - /// - /// Note: 0.0 points to the right and a positive number means a clockwise - /// rotation - fn direction(&self) -> f64; - - /// Returns a mutable reference to the direction of the object - fn direction_mut(&mut self) -> &mut f64; - - /// Changes the direction of the vector to point to the given target - fn point_to(&mut self, target: Point) { - let m = (self.y() - target.y) / (self.x() - target.x); - - *self.direction_mut() = if target.x > self.x() { - m.atan() - } else { - m.atan() + f64::consts::PI - }; - } - - /// Advances the object in the given amount of units, according to its direction - fn advance(&mut self, units: f64) { - *self.x_mut() += self.direction().cos() * units; - *self.y_mut() += self.direction().sin() * units; - } - - /// Similar to `Advance::advance`, but the final position will be wrapped - /// around the given bounds - fn advance_wrapping(&mut self, units: f64, bounds: Size) { - self.advance(units); - - fn wrap(k: &mut f64, bound: f64) { - if *k < 0.0 { - *k += bound; - } else if *k >= bound { - *k -= bound; - } - } - - wrap(self.x_mut(), bounds.width); - wrap(self.y_mut(), bounds.height); - } -} - -/// A trait that provides collision detection for objects with a position and a radius -/// -/// For collision purposes, all objects are treated as circles -pub trait Collide: Position { - /// Returns the radius of the object - fn radius(&self) -> f64; - - /// Returns the diameter of the objects - fn diameter(&self) -> f64 { - self.radius() * 2.0 - } - - /// Returns true if the two objects collide and false otherwise - fn collides_with(&self, other: &O) -> bool { - let radii = self.radius() + other.radius(); - self.position().squared_distance_to(&other.position()) < radii * radii - } -} +//! Traits used by the models + +use std::f64; + +use drawing::{Point, Size}; + +/// A trait for objects that occupy a position in space +pub trait Position { + /// Returns the x coordinate of the object + fn x(&self) -> f64; + + /// Returns a mutable reference to the x coordinate + fn x_mut(&mut self) -> &mut f64; + + /// Returns the y coordinate of the object + fn y(&self) -> f64; + + /// Returns a mutable reference to the y coordinate + fn y_mut(&mut self) -> &mut f64; + + /// Returns the position of the object + fn position(&self) -> Point { + Point::new(self.x(), self.y()) + } +} + +/// A trait for objects that have can move in a given direction +pub trait Advance: Position { + /// Returns the direction of the object, measured in radians + /// + /// Note: 0.0 points to the right and a positive number means a clockwise + /// rotation + fn direction(&self) -> f64; + + /// Returns a mutable reference to the direction of the object + fn direction_mut(&mut self) -> &mut f64; + + /// Changes the direction of the vector to point to the given target + fn point_to(&mut self, target: Point) { + let m = (self.y() - target.y) / (self.x() - target.x); + + *self.direction_mut() = if target.x > self.x() { + m.atan() + } else { + m.atan() + f64::consts::PI + }; + } + + /// Advances the object in the given amount of units, according to its direction + fn advance(&mut self, units: f64) { + *self.x_mut() += self.direction().cos() * units; + *self.y_mut() += self.direction().sin() * units; + } + + /// Similar to `Advance::advance`, but the final position will be wrapped + /// around the given bounds + fn advance_wrapping(&mut self, units: f64, bounds: Size) { + self.advance(units); + + fn wrap(k: &mut f64, bound: f64) { + if *k < 0.0 { + *k += bound; + } else if *k >= bound { + *k -= bound; + } + } + + wrap(self.x_mut(), bounds.width); + wrap(self.y_mut(), bounds.height); + } +} + +/// A trait that provides collision detection for objects with a position and a radius +/// +/// For collision purposes, all objects are treated as circles +pub trait Collide: Position { + /// Returns the radius of the object + fn radius(&self) -> f64; + + /// Returns the diameter of the objects + fn diameter(&self) -> f64 { + self.radius() * 2.0 + } + + /// Returns true if the two objects collide and false otherwise + fn collides_with(&self, other: &O) -> bool { + let radii = self.radius() + other.radius(); + self.position().squared_distance_to(&other.position()) < radii * radii + } +}