mirror of
https://github.com/thilo-behnke/wasm-pong.git
synced 2026-07-11 02:29:25 +00:00
different approach: register collision handlers
This commit is contained in:
@@ -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<dyn GameObject>, &mut Box<dyn GameObject>)>
|
||||
}
|
||||
|
||||
impl CollisionHandler {
|
||||
pub fn new() -> CollisionHandler {
|
||||
CollisionHandler {}
|
||||
}
|
||||
pub fn handle(&self, obj_a: &mut Box<dyn GameObject>, obj_b: &Box<dyn GameObject>) {
|
||||
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<dyn GameObject>, &mut Box<dyn GameObject>)) {
|
||||
self.handlers.insert(mapping, callback);
|
||||
}
|
||||
|
||||
pub fn handle(&self, obj_a: &mut Box<dyn GameObject>, obj_b: &mut Box<dyn GameObject>) {
|
||||
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<dyn GameObject>, obj_b: &Box<dyn GameObject>) {
|
||||
// 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);
|
||||
// }
|
||||
}
|
||||
}
|
||||
|
||||
@@ -103,52 +103,52 @@ impl Field {
|
||||
ball.obj.update_pos()
|
||||
}
|
||||
|
||||
let mut objs: Vec<&Box<dyn GameObject>> = vec![];
|
||||
objs.extend(
|
||||
self.players
|
||||
.clone()
|
||||
.into_iter()
|
||||
.map(|p| &p.obj)
|
||||
.collect::<Vec<&Box<dyn GameObject>>>(),
|
||||
);
|
||||
objs.extend(
|
||||
self.balls
|
||||
.clone()
|
||||
.into_iter()
|
||||
.map(|b| &b.obj)
|
||||
.collect::<Vec<&Box<dyn GameObject>>>(),
|
||||
);
|
||||
objs.extend(
|
||||
self.bounds.objs
|
||||
.clone()
|
||||
.into_iter()
|
||||
.collect::<Vec<&Box<dyn GameObject>>>()
|
||||
);
|
||||
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<dyn GameObject>> = vec![];
|
||||
// objs.extend(
|
||||
// self.players
|
||||
// .clone()
|
||||
// .into_iter()
|
||||
// .map(|p| &p.obj)
|
||||
// .collect::<Vec<&Box<dyn GameObject>>>(),
|
||||
// );
|
||||
// objs.extend(
|
||||
// self.balls
|
||||
// .clone()
|
||||
// .into_iter()
|
||||
// .map(|b| &b.obj)
|
||||
// .collect::<Vec<&Box<dyn GameObject>>>(),
|
||||
// );
|
||||
// objs.extend(
|
||||
// self.bounds.objs
|
||||
// .clone()
|
||||
// .into_iter()
|
||||
// .collect::<Vec<&Box<dyn GameObject>>>()
|
||||
// );
|
||||
// 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)
|
||||
)),
|
||||
|
||||
@@ -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<dyn GeomComp>,
|
||||
physics: Box<dyn PhysicsComp>
|
||||
}
|
||||
|
||||
impl DefaultGameObject {
|
||||
pub fn new(id: u16, geom: Box<dyn GeomComp>, physics: Box<dyn PhysicsComp>) -> DefaultGameObject {
|
||||
DefaultGameObject {id, geom, physics}
|
||||
pub fn new(id: u16, obj_type: String, geom: Box<dyn GeomComp>, physics: Box<dyn PhysicsComp>) -> 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()
|
||||
}
|
||||
|
||||
@@ -64,12 +64,12 @@ use pong::geom::shape::Shape;
|
||||
)]
|
||||
pub fn should_handle_collision(
|
||||
#[case] mut obj_a: Box<dyn GameObject>,
|
||||
#[case] obj_b: Box<dyn GameObject>,
|
||||
#[case] mut obj_b: Box<dyn GameObject>,
|
||||
#[case] expected_a: Box<dyn GameObject>,
|
||||
#[case] expected_b: Box<dyn GameObject>,
|
||||
) {
|
||||
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<dyn GameObject> {
|
||||
Box::new(DefaultGameObject::new(
|
||||
id,
|
||||
"obj".to_string(),
|
||||
Box::new(DefaultGeomComp::new(
|
||||
Shape::rect(Vector::zero(), orientation, 20., 20.)
|
||||
)),
|
||||
|
||||
@@ -69,6 +69,11 @@ impl GameObject for MockGameObject {
|
||||
self.id
|
||||
}
|
||||
|
||||
fn obj_type(&self) -> &str {
|
||||
todo!()
|
||||
}
|
||||
|
||||
|
||||
fn shape(&self) -> &ShapeType {
|
||||
todo!()
|
||||
}
|
||||
|
||||
@@ -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.)
|
||||
)),
|
||||
|
||||
Reference in New Issue
Block a user