mirror of
https://github.com/thilo-behnke/wasm-pong.git
synced 2026-07-11 02:29:25 +00:00
collision handler integration
This commit is contained in:
@@ -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;
|
||||
}
|
||||
|
||||
@@ -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>>>> {
|
||||
|
||||
Reference in New Issue
Block a user