From 5d484e4d6a0b3aadcea8888d9fb4fa96c41760a0 Mon Sep 17 00:00:00 2001 From: Thilo Behnke Date: Mon, 2 May 2022 11:53:26 +0200 Subject: [PATCH] collision handler integration --- pong/src/collision.rs | 78 ++++++++++++++++++++++++++++++++++++------ pong/src/game_field.rs | 18 +++++++--- 2 files changed, 80 insertions(+), 16 deletions(-) diff --git a/pong/src/collision.rs b/pong/src/collision.rs index 228a1fa..c3f62f8 100644 --- a/pong/src/collision.rs +++ b/pong/src/collision.rs @@ -2,13 +2,39 @@ pub mod collision { use crate::game_object::game_object::GameObject; use crate::geom::geom::Vector; use std::alloc::handle_alloc_error; + use std::any::Any; use std::cell::{Ref, RefCell, RefMut}; use std::collections::HashMap; use std::fmt::Debug; use std::rc::Rc; use crate::utils::utils::{Logger, LoggerFactory}; + pub struct CollisionDetectorConfig { + groups: Vec + } + + impl CollisionDetectorConfig { + pub fn new() -> CollisionDetectorConfig { + CollisionDetectorConfig { + groups: vec![] + } + } + + pub fn matches_any_group(&self, type_a: &str, type_b: &str) -> bool { + self.groups.iter().any(|g| g.matches(type_a, type_b)) + } + } + + pub struct CollisionGroup(pub String, pub String); + + impl CollisionGroup { + pub fn matches(&self, type_a: &str, type_b: &str) -> bool { + self.0 == type_a && self.1 == type_b || self.0 == type_b && self.1 == type_a + } + } + pub struct CollisionDetector { + config: CollisionDetectorConfig, logger: Box } @@ -16,10 +42,15 @@ pub mod collision { pub fn new(logger_factory: &Box) -> CollisionDetector { let logger = logger_factory.get("collision_detector"); CollisionDetector { + config: CollisionDetectorConfig::new(), logger } } + pub fn set_groups(&mut self, groups: Vec) { + self.config.groups = groups; + } + pub fn detect_collisions( &self, objs: Vec>>>, @@ -36,6 +67,9 @@ pub mod collision { let rest = &objs[i..]; for other in rest.iter().map(|o| o.borrow()) { + if !self.config.matches_any_group(obj.obj_type(), other.obj_type()) { + continue; + } let has_collision = obj.bounding_box().overlaps(&other.bounding_box()); if !has_collision { continue; @@ -79,12 +113,39 @@ pub mod collision { } } + pub struct CollisionHandlerRegistry { + handlers: HashMap<(String, String), fn(Rc>>, Rc>>)> + } + + type CollisionCallback = fn(Rc>>, Rc>>); + + impl CollisionHandlerRegistry { + pub fn new() -> CollisionHandlerRegistry { + CollisionHandlerRegistry {handlers: HashMap::new()} + } + + pub fn add(&mut self, mapping: (String, String), callback: CollisionCallback) { + if self.handlers.contains_key(&mapping) { + panic!( + "Collision handler for mapping {:?} is already registered.", + mapping + ) + } + self.handlers.insert((mapping.1.clone(), mapping.0.clone()), callback); + self.handlers.insert(mapping, callback); + } + + pub fn get(&self, mapping: &(String, String)) -> Option<&CollisionCallback> { + return self.handlers.get(mapping); + } + } + #[derive(Debug, Eq, PartialEq)] pub struct Collision(pub u16, pub u16); pub struct CollisionHandler { logger: Box, - handlers: HashMap<(String, String), fn(Rc>>, Rc>>)> + handlers: CollisionHandlerRegistry } impl CollisionHandler { @@ -92,7 +153,7 @@ pub mod collision { let logger = logger_factory.get("collision_handler"); CollisionHandler { logger, - handlers: HashMap::new(), + handlers: CollisionHandlerRegistry::new(), } } @@ -101,13 +162,7 @@ pub mod collision { mapping: (String, String), callback: fn(Rc>>, Rc>>), ) { - if self.handlers.contains_key(&mapping) { - panic!( - "Collision handler for mapping {:?} is already registered.", - mapping - ) - } - self.handlers.insert(mapping, callback); + self.handlers.add(mapping, callback) } pub fn handle( @@ -116,14 +171,15 @@ pub mod collision { obj_b: Rc>>, ) -> bool { let key = (RefCell::borrow(&obj_a).obj_type().to_string(), RefCell::borrow(&obj_b).obj_type().to_string()); - if !self.handlers.contains_key(&key) { + let handler_opt = self.handlers.get(&key); + if let None = handler_opt { self.logger.log(&*format!("Found no matching collision handler: {:?}", key)); return false; } + let handler = handler_opt.unwrap(); self.logger.log(&*format!("Handling collision between {:?} and {:?}", obj_a, obj_b)); self.logger.log(&*format!("Handling collision using handler {:?}", key)); - let handler = self.handlers[&key]; handler(obj_a, obj_b); return true; } diff --git a/pong/src/game_field.rs b/pong/src/game_field.rs index 3404d44..790d0fe 100644 --- a/pong/src/game_field.rs +++ b/pong/src/game_field.rs @@ -1,6 +1,4 @@ -use crate::collision::collision::{ - Collision, CollisionDetector, CollisionHandler, CollisionRegistry, Collisions, -}; +use crate::collision::collision::{Collision, CollisionDetector, CollisionGroup, CollisionHandler, CollisionRegistry, Collisions}; use crate::game_object::components::{DefaultGeomComp, DefaultPhysicsComp}; use crate::game_object::game_object::{DefaultGameObject, GameObject}; use crate::geom::geom::Vector; @@ -32,6 +30,7 @@ pub struct Field { pub height: u16, pub collisions: Box, objs: Vec>>>, + collision_detector: CollisionDetector, collision_handler: CollisionHandler, } @@ -49,6 +48,7 @@ impl Field { .map(|b| Rc::new(RefCell::new(b.inner()))) .collect(), collisions: Box::new(Collisions::new(vec![])), + collision_detector: CollisionDetector::new(&logger_factory), collision_handler: CollisionHandler::new(&logger_factory), logger_factory }; @@ -72,6 +72,14 @@ impl Field { handle_ball_bounds_collision, ); + field.collision_detector.set_groups( + vec![ + CollisionGroup(String::from("player"), String::from("ball")), + CollisionGroup(String::from("player"), String::from("bounds")), + CollisionGroup(String::from("ball"), String::from("bounds")), + ] + ); + return field; } @@ -86,6 +94,7 @@ impl Field { .map(|b| Rc::new(RefCell::new(b.inner()))) .collect(), collisions: Box::new(Collisions::new(vec![])), + collision_detector: CollisionDetector::new(&logger_factory), collision_handler: CollisionHandler::new(&logger_factory), logger_factory, } @@ -159,8 +168,7 @@ impl Field { fn get_collisions(&self) -> Box { let objs = self.objs.iter().map(|o| o.clone()).collect(); - let collision_detector = CollisionDetector::new(&self.logger_factory); - collision_detector.detect_collisions(objs) + self.collision_detector.detect_collisions(objs) } pub fn objs(&self) -> Vec<&Rc>>> {