From cf170d40e7c5220022421980d9487ce42d8805bc Mon Sep 17 00:00:00 2001 From: Thilo Behnke Date: Sat, 23 Apr 2022 12:01:55 +0200 Subject: [PATCH] more tests for reflection --- pong/src/collision.rs | 14 ++++++++ pong/src/game_field.rs | 30 +++++++++-------- pong/src/geom.rs | 6 ++++ pong/tests/collision_handler_test.rs | 49 ++++++++++++++++++++++++++++ pong/tests/collision_tests.rs | 16 ++++----- pong/tests/game_object_tests.rs | 1 + pong/tests/vector_tests.rs | 13 ++++++++ 7 files changed, 107 insertions(+), 22 deletions(-) create mode 100644 pong/tests/collision_handler_test.rs diff --git a/pong/src/collision.rs b/pong/src/collision.rs index 82307a6..1c5d1f2 100644 --- a/pong/src/collision.rs +++ b/pong/src/collision.rs @@ -66,4 +66,18 @@ pub mod collision { #[derive(Debug, Eq, PartialEq)] pub struct Collision(pub u16, pub u16); + + pub struct CollisionHandler {} + + impl CollisionHandler { + pub fn new() -> CollisionHandler { + CollisionHandler {} + } + pub fn handle(&self, obj_a: &mut GameObject, obj_b: &GameObject) { + if obj_a.is_static { + return; + } + obj_a.vel.reflect(&obj_b.orientation) + } + } } diff --git a/pong/src/game_field.rs b/pong/src/game_field.rs index 3c3af13..bf6177f 100644 --- a/pong/src/game_field.rs +++ b/pong/src/game_field.rs @@ -1,5 +1,5 @@ use std::f64::consts::{FRAC_PI_2, FRAC_PI_4}; -use crate::collision::collision::{Collision, CollisionDetector, CollisionRegistry, Collisions}; +use crate::collision::collision::{Collision, CollisionDetector, CollisionHandler, CollisionRegistry, Collisions}; use crate::game_object::game_object::{GameObject, Shape}; use crate::geom::geom::Vector; @@ -118,6 +118,7 @@ impl Field { .collect::>() ); let collision_detector = CollisionDetector::new(); + let collision_handler = CollisionHandler::new(); self.collisions = collision_detector.detect_collisions(objs.iter().collect()); for ball in self.balls.iter_mut() { @@ -132,19 +133,20 @@ impl Field { collision => objs.iter().find(|o| o.id == collision.0).unwrap(), }; - if other.vel == Vector::zero() { - let dot = ball.obj.vel.dot(&other.orientation); - if dot >= - 0.000001 && dot <= 0.000001 { - ball.obj.vel.invert(); - } else { - let angle = ball.obj.vel.angle(&other.orientation); - ball.obj.vel.rotate(FRAC_PI_2 - angle); - ball.obj.vel.invert(); - } - } else { - ball.obj.vel.add(&other.vel); - ball.obj.vel.invert(); - } + collision_handler.handle(&mut ball.obj, other); + // if other.vel == Vector::zero() { + // let dot = ball.obj.vel.dot(&other.orientation); + // if dot >= - 0.000001 && dot <= 0.000001 { + // ball.obj.vel.invert(); + // } else { + // let angle = ball.obj.vel.angle(&other.orientation); + // ball.obj.vel.rotate(FRAC_PI_2 - angle); + // ball.obj.vel.invert(); + // } + // } else { + // ball.obj.vel.add(&other.vel); + // ball.obj.vel.invert(); + // } } } diff --git a/pong/src/geom.rs b/pong/src/geom.rs index 2608d35..3b2c94f 100644 --- a/pong/src/geom.rs +++ b/pong/src/geom.rs @@ -80,6 +80,12 @@ pub mod geom { (acos_res * 100.0).round() / 100.0 } + pub fn reflect(&mut self, onto: &Vector) { + let mut orthogonal = self.get_opposing_orthogonal(onto); + orthogonal.scalar_multiplication(2.); + self.add(&orthogonal); + } + pub fn get_projection(&self, onto: &Vector) -> Vector { let mut onto_normalized = onto.clone(); onto_normalized.normalize(); diff --git a/pong/tests/collision_handler_test.rs b/pong/tests/collision_handler_test.rs new file mode 100644 index 0000000..dccff32 --- /dev/null +++ b/pong/tests/collision_handler_test.rs @@ -0,0 +1,49 @@ +use rstest::rstest; +use pong::collision::collision::CollisionHandler; +use pong::game_object::game_object::{GameObject, Shape}; +use pong::geom::geom::Vector; + +#[rstest] +#[case( + // given + GameObject {id: 1, pos: Vector::zero(), vel: Vector::new(1., 0.), shape: Shape::Rect, shape_params: vec![], is_static: true, orientation: Vector::new(1., 0.)}, + GameObject {id: 1, pos: Vector::zero(), vel: Vector::new(0., 1.), shape: Shape::Rect, shape_params: vec![], is_static: true, orientation: Vector::new(0., 1.)}, + // expected + GameObject {id: 1, pos: Vector::zero(), vel: Vector::new(1., 0.), shape: Shape::Rect, shape_params: vec![], is_static: true, orientation: Vector::new(1., 0.)}, + GameObject {id: 1, pos: Vector::zero(), vel: Vector::new(0., 1.), shape: Shape::Rect, shape_params: vec![], is_static: true, orientation: Vector::new(0., 1.)}, +)] +#[case( +// given +GameObject {id: 1, pos: Vector::zero(), vel: Vector::new(1., 0.), shape: Shape::Rect, shape_params: vec![], is_static: false, orientation: Vector::new(1., 0.)}, + GameObject {id: 1, pos: Vector::zero(), vel: Vector::new(0., 1.), shape: Shape::Rect, shape_params: vec![], is_static: true, orientation: Vector::new(0., 1.)}, + // expected + GameObject {id: 1, pos: Vector::zero(), vel: Vector::new(-1., 0.), shape: Shape::Rect, shape_params: vec![], is_static: false, orientation: Vector::new(1., 0.)}, + GameObject {id: 1, pos: Vector::zero(), vel: Vector::new(0., 1.), shape: Shape::Rect, shape_params: vec![], is_static: true, orientation: Vector::new(0., 1.)}, +)] +#[case( + // given + GameObject {id: 1, pos: Vector::zero(), vel: Vector::new(-1., 0.), shape: Shape::Rect, shape_params: vec![], is_static: false, orientation: Vector::new(-1., 0.)}, + GameObject {id: 1, pos: Vector::zero(), vel: Vector::new(0., 1.), shape: Shape::Rect, shape_params: vec![], is_static: true, orientation: Vector::new(0., 1.)}, + // expected + GameObject {id: 1, pos: Vector::zero(), vel: Vector::new(1., 0.), shape: Shape::Rect, shape_params: vec![], is_static: false, orientation: Vector::new(-1., 0.)}, + GameObject {id: 1, pos: Vector::zero(), vel: Vector::new(0., 1.), shape: Shape::Rect, shape_params: vec![], is_static: true, orientation: Vector::new(0., 1.)}, +)] +#[case( +// given + GameObject {id: 1, pos: Vector::zero(), vel: Vector::new(1., 1.), shape: Shape::Rect, shape_params: vec![], is_static: false, orientation: Vector::new(1., 1.)}, + GameObject {id: 1, pos: Vector::zero(), vel: Vector::new(0., 1.), shape: Shape::Rect, shape_params: vec![], is_static: true, orientation: Vector::new(0., 1.)}, + // expected + GameObject {id: 1, pos: Vector::zero(), vel: Vector::new(-1., 1.), shape: Shape::Rect, shape_params: vec![], is_static: false, orientation: Vector::new(1., 1.)}, + GameObject {id: 1, pos: Vector::zero(), vel: Vector::new(0., 1.), shape: Shape::Rect, shape_params: vec![], is_static: true, orientation: Vector::new(0., 1.)}, +)] +pub fn should_handle_collision( + #[case] mut obj_a: GameObject, + #[case] obj_b: GameObject, + #[case] expected_a: GameObject, + #[case] expected_b: GameObject, +) { + let handler = CollisionHandler {}; + handler.handle(&mut obj_a, &obj_b); + assert_eq!(obj_a, expected_a); + assert_eq!(obj_b, expected_b); +} diff --git a/pong/tests/collision_tests.rs b/pong/tests/collision_tests.rs index 65a032b..8cd9c3c 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, 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} + GameObject{id: 1, pos: Vector{x: 50., y: 50.}, shape: Shape::Rect, shape_params: vec![20, 20], vel: Vector::zero(), is_static: false, orientation: Vector::new(1., 1.)}, + GameObject{id: 2, pos: Vector{x: 50., y: 50.}, shape: Shape::Rect, shape_params: vec![20, 20], vel: Vector::zero(), is_static: false, orientation: Vector::new(1., 1.)} ], vec![Collision(1, 2)] )] #[case( vec![ - 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} + GameObject{id: 1, pos: Vector{x: 60., y: 65.}, shape: Shape::Rect, shape_params: vec![20, 20], vel: Vector::zero(), is_static: false, orientation: Vector::new(1., 1.)}, + GameObject{id: 2, pos: Vector{x: 50., y: 50.}, shape: Shape::Rect, shape_params: vec![20, 20], vel: Vector::zero(), is_static: false, orientation: Vector::new(1., 1.)} ], vec![Collision(1, 2)] )] #[case( vec![ - 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} + GameObject{id: 1, pos: Vector{x: 50., y: 50.}, shape: Shape::Rect, shape_params: vec![20, 20], vel: Vector::zero(), is_static: false, orientation: Vector::new(1., 1.)}, + GameObject{id: 2, pos: Vector{x: 80., y: 80.}, shape: Shape::Rect, shape_params: vec![20, 20], vel: Vector::zero(), is_static: false, orientation: Vector::new(1., 1.)} ], vec![] )] #[case( vec![ - 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} + GameObject{id: 1, pos: Vector{x: 50., y: 50.}, shape: Shape::Rect, shape_params: vec![50, 50], vel: Vector::zero(), is_static: false, orientation: Vector::new(1., 1.)}, + GameObject{id: 2, pos: Vector{x: 500., y: 50.}, shape: Shape::Rect, shape_params: vec![50, 50], vel: Vector::zero(), is_static: false, orientation: Vector::new(1., 1.)} ], vec![] )] diff --git a/pong/tests/game_object_tests.rs b/pong/tests/game_object_tests.rs index f652770..077c4f3 100644 --- a/pong/tests/game_object_tests.rs +++ b/pong/tests/game_object_tests.rs @@ -12,6 +12,7 @@ pub fn should_update_pos(#[case] start_pos: Vector, #[case] vel: Vector, #[case] shape: Shape::Rect, shape_params: vec![], is_static: false, + orientation: Vector::new(1., 0.) }; obj.update_pos(); assert_eq!(obj.pos, expected_pos); diff --git a/pong/tests/vector_tests.rs b/pong/tests/vector_tests.rs index 650af3b..691eb72 100644 --- a/pong/tests/vector_tests.rs +++ b/pong/tests/vector_tests.rs @@ -121,4 +121,17 @@ pub fn should_get_opposing_orthogonal( assert_eq!(orthogonal, expected); } +#[rstest] +#[case(Vector::new(1., 1.), Vector::new(1., 0.), Vector::new(1., -1.))] +#[case(Vector::new(-1., 1.), Vector::new(1., 0.), Vector::new(-1., -1.))] +#[case(Vector::new(1., -1.), Vector::new(0., 1.), Vector::new(-1., -1.))] +#[case(Vector::new(-1., -1.), Vector::new(0., 1.), Vector::new(1., -1.))] +pub fn should_reflect_vector( + #[case] mut vector: Vector, + #[case] onto: Vector, + #[case] expected: Vector, +) { + vector.reflect(&onto); + assert_eq!(vector, expected); +}