collision handler integration

This commit is contained in:
Thilo Behnke
2022-05-02 11:53:26 +02:00
parent ccfe632c17
commit 5d484e4d6a
2 changed files with 80 additions and 16 deletions

View File

@@ -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<CollisionGroup>
}
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<dyn Logger>
}
@@ -16,10 +42,15 @@ pub mod collision {
pub fn new(logger_factory: &Box<dyn LoggerFactory>) -> CollisionDetector {
let logger = logger_factory.get("collision_detector");
CollisionDetector {
config: CollisionDetectorConfig::new(),
logger
}
}
pub fn set_groups(&mut self, groups: Vec<CollisionGroup>) {
self.config.groups = groups;
}
pub fn detect_collisions(
&self,
objs: Vec<Rc<RefCell<Box<dyn GameObject>>>>,
@@ -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<RefCell<Box<dyn GameObject>>>, Rc<RefCell<Box<dyn GameObject>>>)>
}
type CollisionCallback = fn(Rc<RefCell<Box<dyn GameObject>>>, Rc<RefCell<Box<dyn GameObject>>>);
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<dyn Logger>,
handlers: HashMap<(String, String), fn(Rc<RefCell<Box<dyn GameObject>>>, Rc<RefCell<Box<dyn GameObject>>>)>
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<RefCell<Box<dyn GameObject>>>, Rc<RefCell<Box<dyn GameObject>>>),
) {
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<RefCell<Box<dyn GameObject>>>,
) -> 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;
}

View File

@@ -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<dyn CollisionRegistry>,
objs: Vec<Rc<RefCell<Box<dyn GameObject>>>>,
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<dyn CollisionRegistry> {
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<RefCell<Box<dyn GameObject>>>> {