diff --git a/pong/src/collision.rs b/pong/src/collision.rs index 201272c..60352b2 100644 --- a/pong/src/collision.rs +++ b/pong/src/collision.rs @@ -1,4 +1,6 @@ pub mod collision { + use std::alloc::handle_alloc_error; + use std::collections::HashMap; use std::fmt::Debug; use crate::game_object::game_object::GameObject; use crate::geom::geom::Vector; @@ -68,25 +70,46 @@ pub mod collision { #[derive(Debug, Eq, PartialEq)] pub struct Collision(pub u16, pub u16); - pub struct CollisionHandler {} + pub struct CollisionHandler { + handlers: HashMap<(String, String), fn(&mut Box, &mut Box)> + } impl CollisionHandler { pub fn new() -> CollisionHandler { - CollisionHandler {} - } - pub fn handle(&self, obj_a: &mut Box, obj_b: &Box) { - if !obj_a.is_static() { - obj_a.vel_mut().reflect(&obj_b.orientation()); - if *obj_b.vel() != Vector::zero() { - let mut adjusted = obj_b.vel().clone(); - adjusted.normalize(); - obj_a.vel_mut().add(&adjusted); - } + CollisionHandler { + handlers: HashMap::new() } - let mut b_to_a = obj_a.pos().clone(); - b_to_a.sub(&obj_b.pos()); - b_to_a.normalize(); - obj_a.pos_mut().add(&b_to_a); } + + pub fn register(&mut self, mapping: (String, String), callback: fn(&mut Box, &mut Box)) { + self.handlers.insert(mapping, callback); + } + + pub fn handle(&self, obj_a: &mut Box, obj_b: &mut Box) { + let key = (obj_a.obj_type().to_string(), obj_b.obj_type().to_string()); + if !self.handlers.contains_key(&key) { + return; + } + let handler = self.handlers[&key]; + handler(obj_a, obj_b); + } + + // pub fn new() -> CollisionHandler { + // CollisionHandler {} + // } + // pub fn handle(&self, obj_a: &mut Box, obj_b: &Box) { + // if !obj_a.is_static() { + // obj_a.vel_mut().reflect(&obj_b.orientation()); + // if *obj_b.vel() != Vector::zero() { + // let mut adjusted = obj_b.vel().clone(); + // adjusted.normalize(); + // obj_a.vel_mut().add(&adjusted); + // } + // } + // let mut b_to_a = obj_a.pos().clone(); + // b_to_a.sub(&obj_b.pos()); + // b_to_a.normalize(); + // obj_a.pos_mut().add(&b_to_a); + // } } } diff --git a/pong/src/game_field.rs b/pong/src/game_field.rs index 6bc9103..dcbd4be 100644 --- a/pong/src/game_field.rs +++ b/pong/src/game_field.rs @@ -103,52 +103,52 @@ impl Field { ball.obj.update_pos() } - let mut objs: Vec<&Box> = vec![]; - objs.extend( - self.players - .clone() - .into_iter() - .map(|p| &p.obj) - .collect::>>(), - ); - objs.extend( - self.balls - .clone() - .into_iter() - .map(|b| &b.obj) - .collect::>>(), - ); - objs.extend( - self.bounds.objs - .clone() - .into_iter() - .collect::>>() - ); - let collision_detector = CollisionDetector::new(); - let collision_handler = CollisionHandler::new(); - self.collisions = collision_detector.detect_collisions(&objs); - - for ball in self.balls.iter_mut() { - let collisions = self.collisions.get_collisions_by_id(ball.obj.id()); - if collisions.is_empty() { - continue; - } - let other = match collisions[0] { - Collision(obj_a_id, obj_b_id) if *obj_a_id == ball.obj.id() => { - objs.iter().find(|o| o.id() == *obj_b_id).unwrap() - } - collision => objs.iter().find(|o| o.id() == collision.0).unwrap(), - }; - - self.logger.log("### BEFORE COLLISION ###"); - self.logger.log(&*format!("{:?}", ball.obj)); - self.logger.log(&*format!("{:?}", other)); - collision_handler.handle(&mut ball.obj, other); - self.logger.log("### AFTER COLLISION ###"); - self.logger.log(&*format!("{:?}", ball.obj)); - self.logger.log(&*format!("{:?}", other)); - self.logger.log("### DONE ###"); - } + // let mut objs: Vec<&Box> = vec![]; + // objs.extend( + // self.players + // .clone() + // .into_iter() + // .map(|p| &p.obj) + // .collect::>>(), + // ); + // objs.extend( + // self.balls + // .clone() + // .into_iter() + // .map(|b| &b.obj) + // .collect::>>(), + // ); + // objs.extend( + // self.bounds.objs + // .clone() + // .into_iter() + // .collect::>>() + // ); + // let collision_detector = CollisionDetector::new(); + // let collision_handler = CollisionHandler::new(); + // self.collisions = collision_detector.detect_collisions(&objs); + // + // for ball in self.balls.iter_mut() { + // let collisions = self.collisions.get_collisions_by_id(ball.obj.id()); + // if collisions.is_empty() { + // continue; + // } + // let other = match collisions[0] { + // Collision(obj_a_id, obj_b_id) if *obj_a_id == ball.obj.id() => { + // objs.iter().find(|o| o.id() == *obj_b_id).unwrap() + // } + // collision => objs.iter().find(|o| o.id() == collision.0).unwrap(), + // }; + // + // self.logger.log("### BEFORE COLLISION ###"); + // self.logger.log(&*format!("{:?}", ball.obj)); + // self.logger.log(&*format!("{:?}", other)); + // collision_handler.handle(&mut ball.obj, other); + // self.logger.log("### AFTER COLLISION ###"); + // self.logger.log(&*format!("{:?}", ball.obj)); + // self.logger.log(&*format!("{:?}", other)); + // self.logger.log("### DONE ###"); + // } } pub fn players(&self) -> Vec<&Player> { @@ -171,6 +171,7 @@ impl Player { Player { obj: Box::new(DefaultGameObject::new( id, + "player".to_string(), Box::new(DefaultGeomComp::new( Shape::rect(Vector { x: x as f64, y: y as f64 }, Vector::new(0., 1.), (field.width as f64) / 25., (field.height as f64) / 5.) )), @@ -194,6 +195,7 @@ impl Ball { Ball { obj: Box::new(DefaultGameObject::new( id, + "ball".to_string(), Box::new(DefaultGeomComp::new( Shape::circle(Vector { x: x as f64, y: y as f64 }, Vector::zero(), (field.width as f64) / 80.) )), @@ -218,6 +220,7 @@ impl Bounds { // top Box::new(DefaultGameObject::new( 90, + "bound".to_string(), Box::new(DefaultGeomComp::new( Shape::rect(Vector {x: (width / 2) as f64, y: 0 as f64}, Vector::new(1., 0.), width as f64, 2.) )), @@ -226,6 +229,7 @@ impl Bounds { // bottom Box::new(DefaultGameObject::new( 91, + "bound".to_string(), Box::new(DefaultGeomComp::new( Shape::rect(Vector {x: (width / 2) as f64, y: height as f64}, Vector::new(-1., 0.), width as f64, 2.) )), @@ -234,6 +238,7 @@ impl Bounds { // left Box::new(DefaultGameObject::new( 92, + "bound".to_string(), Box::new(DefaultGeomComp::new( Shape::rect(Vector {x: 0 as f64, y: (height / 2) as f64}, Vector::new(0., 1.), 2., height as f64) )), @@ -242,6 +247,7 @@ impl Bounds { // right Box::new(DefaultGameObject::new( 93, + "bound".to_string(), Box::new(DefaultGeomComp::new( Shape::rect(Vector {x: width as f64, y: (height / 2) as f64}, Vector::new(0., -1.), 2., height as f64) )), diff --git a/pong/src/game_object.rs b/pong/src/game_object.rs index 219c895..8814772 100644 --- a/pong/src/game_object.rs +++ b/pong/src/game_object.rs @@ -4,8 +4,9 @@ pub mod game_object { use crate::geom::geom::{BoundingBox, Vector}; use crate::geom::shape::{Shape, ShapeType}; - pub trait GameObject : Debug + Clone { + pub trait GameObject : Debug { fn id(&self) -> u16; + fn obj_type(&self) -> &str; fn shape(&self) -> &ShapeType; fn pos(&self) -> &Vector; fn pos_mut(&mut self) -> &mut Vector; @@ -18,16 +19,17 @@ pub mod game_object { } // #[derive(Clone, Debug, PartialEq)] - #[derive(Debug, Clone)] + #[derive(Debug)] pub struct DefaultGameObject { pub id: u16, + pub obj_type: String, geom: Box, physics: Box } impl DefaultGameObject { - pub fn new(id: u16, geom: Box, physics: Box) -> DefaultGameObject { - DefaultGameObject {id, geom, physics} + pub fn new(id: u16, obj_type: String, geom: Box, physics: Box) -> DefaultGameObject { + DefaultGameObject {id, obj_type, geom, physics} } } @@ -36,6 +38,10 @@ pub mod game_object { self.id } + fn obj_type(&self) -> &str { + &self.obj_type + } + fn shape(&self) -> &ShapeType { self.geom.shape() } diff --git a/pong/tests/collision_handler_test.rs b/pong/tests/collision_handler_test.rs index acdb243..596d11f 100644 --- a/pong/tests/collision_handler_test.rs +++ b/pong/tests/collision_handler_test.rs @@ -64,12 +64,12 @@ use pong::geom::shape::Shape; )] pub fn should_handle_collision( #[case] mut obj_a: Box, - #[case] obj_b: Box, + #[case] mut obj_b: Box, #[case] expected_a: Box, #[case] expected_b: Box, ) { - let handler = CollisionHandler {}; - handler.handle(&mut obj_a, &obj_b); + let handler = CollisionHandler::new(); + handler.handle(&mut obj_a, &mut obj_b); assert_eq!(obj_a.pos(), expected_a.pos()); assert_eq!(obj_a.vel(), expected_a.vel()); assert_eq!(obj_b.pos(), expected_b.pos()); @@ -79,6 +79,7 @@ pub fn should_handle_collision( fn create_game_obj(id: u16, vel: Vector, orientation: Vector, is_static: bool) -> Box { Box::new(DefaultGameObject::new( id, + "obj".to_string(), Box::new(DefaultGeomComp::new( Shape::rect(Vector::zero(), orientation, 20., 20.) )), diff --git a/pong/tests/collision_tests.rs b/pong/tests/collision_tests.rs index 07548af..3a814d3 100644 --- a/pong/tests/collision_tests.rs +++ b/pong/tests/collision_tests.rs @@ -69,6 +69,11 @@ impl GameObject for MockGameObject { self.id } + fn obj_type(&self) -> &str { + todo!() + } + + fn shape(&self) -> &ShapeType { todo!() } diff --git a/pong/tests/game_object_tests.rs b/pong/tests/game_object_tests.rs index 71f7c5c..d89a796 100644 --- a/pong/tests/game_object_tests.rs +++ b/pong/tests/game_object_tests.rs @@ -9,6 +9,7 @@ use pong::geom::shape::Shape; pub fn should_update_pos(#[case] start_pos: Vector, #[case] vel: Vector, #[case] expected_pos: Vector) { let mut obj = DefaultGameObject::new( 1, + "obj".to_string(), Box::new(DefaultGeomComp::new( Shape::rect(Vector::new(start_pos.x as f64, start_pos.y as f64), Vector::new(1., 0.), 0., 0.) )),