diff --git a/pong/src/game_field.rs b/pong/src/game_field.rs index 21cf93c..dfa1914 100644 --- a/pong/src/game_field.rs +++ b/pong/src/game_field.rs @@ -90,10 +90,10 @@ impl Field { } for player in self.players.iter_mut() { - player.obj.update_pos(self.width, self.height) + player.obj.update_pos() } for ball in self.balls.iter_mut() { - ball.obj.update_pos(self.width, self.height) + ball.obj.update_pos() } let mut objs: Vec = vec![]; @@ -155,8 +155,7 @@ impl Player { Player { obj: GameObject { id, - x, - y, + pos: Vector {x: x as f64, y: y as f64}, shape: Shape::Rect, shape_params: vec![field.width / 25, field.height / 5], vel: Vector::zero(), @@ -176,8 +175,7 @@ impl Ball { Ball { obj: GameObject { id, - x, - y, + pos: Vector {x: x as f64, y: y as f64}, shape: Shape::Circle, shape_params: vec![field.width / 80], vel: Vector::zero(), @@ -198,8 +196,7 @@ impl Bounds { objs: vec![ GameObject { id: 90, - x: width / 2, - y: 0, + pos: Vector {x: (width / 2) as f64, y: 0 as f64}, shape: Shape::Rect, shape_params: vec![width, 2], is_static: true, @@ -208,8 +205,7 @@ impl Bounds { // bottom GameObject { id: 91, - x: width / 2, - y: height, + pos: Vector {x: (width / 2) as f64, y: height as f64}, shape: Shape::Rect, shape_params: vec![width, 2], is_static: true, @@ -218,8 +214,7 @@ impl Bounds { // left GameObject { id: 92, - x: 0, - y: height / 2, + pos: Vector {x: 0 as f64, y: (height / 2) as f64}, shape: Shape::Rect, shape_params: vec![2, height], is_static: true, @@ -228,8 +223,7 @@ impl Bounds { // right GameObject { id: 93, - x: width, - y: height / 2, + pos: Vector {x: width as f64, y: (height / 2) as f64}, shape: Shape::Rect, shape_params: vec![2, height], is_static: true, diff --git a/pong/src/game_object.rs b/pong/src/game_object.rs index 6e549c2..59e2290 100644 --- a/pong/src/game_object.rs +++ b/pong/src/game_object.rs @@ -10,8 +10,7 @@ pub mod game_object { #[derive(Clone, Debug, PartialEq)] pub struct GameObject { pub id: u16, - pub x: u16, - pub y: u16, + pub pos: Vector, pub shape: Shape, pub shape_params: Vec, pub vel: Vector, @@ -19,20 +18,9 @@ pub mod game_object { } impl GameObject { - // TODO: Migrate pos to f64 - pub fn update_pos(&mut self, field_width: u16, field_height: u16) { - let abs_x = self.vel.x.abs() as u16; - let updated_x = match self.vel.x { - n if n >= 0. => self.x.wrapping_add(abs_x), - _ => self.x.wrapping_sub(abs_x) - }; - let abs_y = self.vel.y.abs() as u16; - let updated_y = match self.vel.y { - n if n >= 0. => self.y.wrapping_add(abs_y), - _ => self.y.wrapping_sub(abs_y) - }; - self.x = updated_x; - self.y = updated_y; + + pub fn update_pos(&mut self) { + self.pos.add(&self.vel); } pub fn set_vel_x(&mut self, x: f64) { @@ -44,16 +32,12 @@ pub mod game_object { } pub fn bounding_box(&self) -> BoundingBox { - self.bounding_box_from(self.x, self.y) - } - - fn bounding_box_from(&self, x: u16, y: u16) -> BoundingBox { match self.shape { Shape::Rect => { - BoundingBox::create(x, y, self.shape_params[0], self.shape_params[1]) + BoundingBox::create(&self.pos, self.shape_params[0], self.shape_params[1]) } Shape::Circle => { - BoundingBox::create(x, y, self.shape_params[0] * 2, self.shape_params[0] * 2) + BoundingBox::create(&self.pos, self.shape_params[0] * 2, self.shape_params[0] * 2) } } } diff --git a/pong/src/geom.rs b/pong/src/geom.rs index 7679617..b56a4bd 100644 --- a/pong/src/geom.rs +++ b/pong/src/geom.rs @@ -1,5 +1,5 @@ pub mod geom { - #[derive(Debug, Clone, PartialEq)] + #[derive(Debug, Clone)] pub struct Vector { pub x: f64, pub y: f64, @@ -54,6 +54,11 @@ pub mod geom { self.y += other.y; } + pub fn sub(&mut self, other: &Vector) { + self.x -= other.x; + self.y -= other.y; + } + pub fn invert(&mut self) { self.x = self.x * -1.; self.y = self.y * -1.; @@ -81,30 +86,44 @@ pub mod geom { } } + impl PartialEq for Vector { + fn eq(&self, other: &Self) -> bool { + (self.x * 1000.).round() == (other.x * 1000.).round() && + (self.y * 1000.).round() == (other.y * 1000.).round() + } + } + pub struct BoundingBox { - top_left: Point, - top_right: Point, - bottom_left: Point, - bottom_right: Point, + top_left: Vector, + top_right: Vector, + bottom_left: Vector, + bottom_right: Vector, } impl BoundingBox { - pub fn create(center_x: u16, center_y: u16, width: u16, height: u16) -> BoundingBox { - let top_left = Point { - x: center_x as i32 - (width / 2) as i32, - y: center_y as i32 + (height / 2) as i32, + pub fn create_from_coords(x: f64, y: f64, width: u16, height: u16) -> BoundingBox { + let center = Vector::new(x, y); + return BoundingBox::create(¢er, width, height) + } + + pub fn create(center: &Vector, width: u16, height: u16) -> BoundingBox { + let center_x = center.x; + let center_y = center.y; + let top_left = Vector { + x: center_x - (width as f64 / 2.), + y: center_y + (height as f64 / 2.), }; - let top_right = Point { - x: center_x as i32 + (width / 2) as i32, - y: center_y as i32 + (height / 2) as i32, + let top_right = Vector { + x: center_x + (width as f64 / 2.), + y: center_y + (height as f64 / 2.), }; - let bottom_left = Point { - x: center_x as i32 - (width / 2) as i32, - y: center_y as i32 - (height / 2) as i32, + let bottom_left = Vector { + x: center_x - (width as f64 / 2.), + y: center_y - (height as f64 / 2.), }; - let bottom_right = Point { - x: center_x as i32 + (width / 2) as i32, - y: center_y as i32 - (height / 2) as i32, + let bottom_right = Vector { + x: center_x + (width as f64 / 2.), + y: center_y - (height as f64 / 2.), }; BoundingBox { top_left, @@ -114,7 +133,7 @@ pub mod geom { } } - pub fn points(&self) -> Vec<&Point> { + pub fn points(&self) -> Vec<&Vector> { return vec![ &self.top_left, &self.top_right, @@ -127,22 +146,11 @@ pub mod geom { return self.points().iter().any(|p| other.is_point_within(p)) || other.points().iter().any(|p| self.is_point_within(p)); } - pub fn is_point_within(&self, point: &Point) -> bool { + pub fn is_point_within(&self, point: &Vector) -> bool { return point.x >= self.top_left.x && point.x <= self.top_right.x && point.y <= self.top_left.y && point.y >= self.bottom_left.y; } } - - pub struct Point { - pub x: i32, - pub y: i32, - } - - impl Point { - pub fn create(x: i32, y: i32) -> Point { - Point { x, y } - } - } } diff --git a/pong/tests/bounding_box_tests.rs b/pong/tests/bounding_box_tests.rs index 4eca094..dbd5361 100644 --- a/pong/tests/bounding_box_tests.rs +++ b/pong/tests/bounding_box_tests.rs @@ -1,13 +1,13 @@ use rstest::rstest; -use pong::geom::geom::{BoundingBox, Point}; +use pong::geom::geom::{BoundingBox, Vector}; #[rstest] -#[case(BoundingBox::create(10, 10, 5, 5), Point::create(10, 10), true)] -#[case(BoundingBox::create(10, 10, 5, 5), Point::create(8, 8), true)] -#[case(BoundingBox::create(10, 10, 5, 5), Point::create(20, 20), false)] +#[case(BoundingBox::create_from_coords(10., 10., 5, 5), Vector::new(10., 10.), true)] +#[case(BoundingBox::create_from_coords(10., 10., 5, 5), Vector::new(8., 8.), true)] +#[case(BoundingBox::create_from_coords(10., 10., 5, 5), Vector::new(20., 20.), false)] pub fn should_correctly_determine_if_point_is_within_box( #[case] bounding_box: BoundingBox, - #[case] point: Point, + #[case] point: Vector, #[case] expected: bool, ) { let res = bounding_box.is_point_within(&point); @@ -16,20 +16,25 @@ pub fn should_correctly_determine_if_point_is_within_box( #[rstest] #[case( - BoundingBox::create(10, 10, 5, 5), - BoundingBox::create(10, 10, 5, 5), + BoundingBox::create_from_coords(10., 10., 5, 5), + BoundingBox::create_from_coords(10., 10., 5, 5), true )] #[case( - BoundingBox::create(10, 10, 5, 5), - BoundingBox::create(8, 8, 5, 5), + BoundingBox::create_from_coords(10., 10., 5, 5), + BoundingBox::create_from_coords(8., 8., 5, 5), true )] #[case( - BoundingBox::create(10, 10, 5, 5), - BoundingBox::create(5, 5, 5, 5), + BoundingBox::create_from_coords(10., 10., 5, 5), + BoundingBox::create_from_coords(4.9, 4.9, 5, 5), false )] +#[case( + BoundingBox::create_from_coords(10., 10., 5, 5), + BoundingBox::create_from_coords(5., 5., 5, 5), + true +)] pub fn should_correctly_determine_if_overlap( #[case] bounding_box_a: BoundingBox, #[case] bounding_box_b: BoundingBox, diff --git a/pong/tests/collision_tests.rs b/pong/tests/collision_tests.rs index 8257b18..65a032b 100644 --- a/pong/tests/collision_tests.rs +++ b/pong/tests/collision_tests.rs @@ -7,29 +7,29 @@ use pong::geom::geom::{Vector}; #[case(vec![], vec![])] #[case( vec![ - GameObject{id: 1, x: 50, y: 50, shape: Shape::Rect, shape_params: vec![20, 20], vel: Vector::zero(), is_static: false}, - GameObject{id: 2, x: 50, y: 50, shape: Shape::Rect, shape_params: vec![20, 20], vel: Vector::zero(), is_static: false} + GameObject{id: 1, pos: Vector{x: 50., y: 50.}, shape: Shape::Rect, shape_params: vec![20, 20], vel: Vector::zero(), is_static: false}, + GameObject{id: 2, pos: Vector{x: 50., y: 50.}, shape: Shape::Rect, shape_params: vec![20, 20], vel: Vector::zero(), is_static: false} ], vec![Collision(1, 2)] )] #[case( vec![ - GameObject{id: 1, x: 60, y: 65, shape: Shape::Rect, shape_params: vec![20, 20], vel: Vector::zero(), is_static: false}, - GameObject{id: 2, x: 50, y: 50, shape: Shape::Rect, shape_params: vec![20, 20], vel: Vector::zero(), is_static: false} + GameObject{id: 1, pos: Vector{x: 60., y: 65.}, shape: Shape::Rect, shape_params: vec![20, 20], vel: Vector::zero(), is_static: false}, + GameObject{id: 2, pos: Vector{x: 50., y: 50.}, shape: Shape::Rect, shape_params: vec![20, 20], vel: Vector::zero(), is_static: false} ], vec![Collision(1, 2)] )] #[case( vec![ - GameObject{id: 1, x: 50, y: 50, shape: Shape::Rect, shape_params: vec![20, 20], vel: Vector::zero(), is_static: false}, - GameObject{id: 2, x: 80, y: 80, shape: Shape::Rect, shape_params: vec![20, 20], vel: Vector::zero(), is_static: false} + GameObject{id: 1, pos: Vector{x: 50., y: 50.}, shape: Shape::Rect, shape_params: vec![20, 20], vel: Vector::zero(), is_static: false}, + GameObject{id: 2, pos: Vector{x: 80., y: 80.}, shape: Shape::Rect, shape_params: vec![20, 20], vel: Vector::zero(), is_static: false} ], vec![] )] #[case( vec![ - GameObject{id: 1, x: 50, y: 50, shape: Shape::Rect, shape_params: vec![50, 50], vel: Vector::zero(), is_static: false}, - GameObject{id: 2, x: 500, y: 50, shape: Shape::Rect, shape_params: vec![50, 50], vel: Vector::zero(), is_static: false} + GameObject{id: 1, pos: Vector{x: 50., y: 50.}, shape: Shape::Rect, shape_params: vec![50, 50], vel: Vector::zero(), is_static: false}, + GameObject{id: 2, pos: Vector{x: 500., y: 50.}, shape: Shape::Rect, shape_params: vec![50, 50], vel: Vector::zero(), is_static: false} ], vec![] )] diff --git a/pong/tests/game_field_test.rs b/pong/tests/game_field_test.rs index 98ac38d..54ce890 100644 --- a/pong/tests/game_field_test.rs +++ b/pong/tests/game_field_test.rs @@ -14,7 +14,7 @@ mod game_field_tests { field.tick(inputs); let players = field.players(); let player = players.first().unwrap(); - assert_eq!(player.obj.y, height / 2 + 1); + assert_eq!(player.obj.pos.y, height as f64 / 2. + 1.); } #[test] @@ -29,7 +29,7 @@ mod game_field_tests { field.tick(inputs); let players = field.players(); let player = players.first().unwrap(); - assert_eq!(player.obj.y, height / 2 - 1); + assert_eq!(player.obj.pos.y, height as f64 / 2. - 1.); } #[test] @@ -44,7 +44,7 @@ mod game_field_tests { field.tick(inputs); let players = field.players(); let player = players.first().unwrap(); - assert_eq!(player.obj.y, height - height / 5 / 2); + assert_eq!(player.obj.pos.y, height as f64 - height as f64 / 5. / 2.); } #[test] @@ -59,6 +59,6 @@ mod game_field_tests { field.tick(inputs); let players = field.players(); let player = players.first().unwrap(); - assert_eq!(player.obj.y, height / 5 / 2); + assert_eq!(player.obj.pos.y, height as f64 / 5. / 2.); } } diff --git a/pong/tests/game_object_tests.rs b/pong/tests/game_object_tests.rs index 6b2df73..f652770 100644 --- a/pong/tests/game_object_tests.rs +++ b/pong/tests/game_object_tests.rs @@ -1,20 +1,18 @@ use rstest::rstest; use pong::game_object::game_object::{GameObject, Shape}; -use pong::geom::geom::{Point, Vector}; +use pong::geom::geom::{Vector}; #[rstest] -#[case(Point::create(100, 100), Vector::new(-1., 1.), Point::create(99, 101))] -pub fn should_update_pos(#[case] start_pos: Point, #[case] vel: Vector, #[case] expected_pos: Point) { +#[case(Vector::new(100., 100.), Vector::new(-1., 1.), Vector::new(99., 101.))] +pub fn should_update_pos(#[case] start_pos: Vector, #[case] vel: Vector, #[case] expected_pos: Vector) { let mut obj = GameObject { id: 1, - x: start_pos.x as u16, - y: start_pos.y as u16, + pos: Vector::new(start_pos.x as f64, start_pos.y as f64), vel, shape: Shape::Rect, shape_params: vec![], is_static: false, }; - obj.update_pos(1000, 1000); - assert_eq!(obj.x, expected_pos.x as u16); - assert_eq!(obj.y, expected_pos.y as u16); + obj.update_pos(); + assert_eq!(obj.pos, expected_pos); } diff --git a/src/lib.rs b/src/lib.rs index 53a5c18..a1d87c3 100644 --- a/src/lib.rs +++ b/src/lib.rs @@ -40,8 +40,8 @@ impl GameObjectDTO { pub fn from(obj: &GameObject) -> GameObjectDTO { return GameObjectDTO { id: obj.id, - x: obj.x, - y: obj.y, + x: obj.pos.x as u16, + y: obj.pos.y as u16, shape_param_1: match obj.shape_params[..] { [p1, _] => p1, [p1] => p1,