diff --git a/src/collision.rs b/src/collision.rs index 2d562d2..3bf0cb1 100644 --- a/src/collision.rs +++ b/src/collision.rs @@ -10,23 +10,41 @@ pub mod collision { CollisionDetector {} } - pub fn detect_collisions(objs: Vec) -> Box { - let registry = Collisions::new(HashMap::new()); + pub fn detect_collisions(&self, objs: Vec<&GameObject>) -> Box { + let mut collisions: Vec = vec![]; + let mut i = 0; + loop { + let obj = objs[i]; + i += 1; + + let rest = &objs[i..]; + for other in rest.iter() { + let has_collision = obj.bounding_box().overlaps(&other.bounding_box()); + if !has_collision { + continue; + } + collisions.push(Collision(obj.id, other.id)) + } + if i >= objs.len() { + break; + } + } + let registry = Collisions::new(collisions); return Box::new(registry); } } - trait CollisionRegistry { + pub trait CollisionRegistry { fn get_collisions(&self) -> Vec<&Collision>; // fn get_collisions_by_id() -> Vec; } pub struct Collisions { - state: HashMap> + pub state: Vec } impl Collisions { - pub fn new(collisions: HashMap>) -> Collisions { + pub fn new(collisions: Vec) -> Collisions { Collisions { state: collisions } @@ -35,9 +53,10 @@ pub mod collision { impl CollisionRegistry for Collisions { fn get_collisions(&self) -> Vec<&Collision> { - self.state.values().flatten().collect() + self.state.iter().collect() } } - pub struct Collision(GameObject, GameObject); + #[derive(Debug)] + pub struct Collision(u16, u16); } diff --git a/src/game_object.rs b/src/game_object.rs index ebb4c92..d11b8c0 100644 --- a/src/game_object.rs +++ b/src/game_object.rs @@ -1,56 +1,60 @@ -use crate::{BoundingBox, Vector}; -#[derive(Clone, Debug, PartialEq)] -pub enum Shape { - Rect = 0, - Circle = 1, -} +pub mod game_object { + use crate::{BoundingBox, Vector}; -#[derive(Clone, Debug, PartialEq)] -pub struct GameObject { - pub id: u16, - pub x: u16, - pub y: u16, - pub shape: Shape, - pub shape_params: Vec, - pub vel: Vector, - pub is_static: bool -} + #[derive(Clone, Debug, PartialEq)] + pub enum Shape { + Rect = 0, + Circle = 1, + } -impl GameObject { - pub fn update_pos(&mut self, field_width: u16, field_height: u16) { - let updated_x = self.x.wrapping_add(self.vel.x as u16); - let updated_y = self.y.wrapping_add(self.vel.y as u16); + #[derive(Clone, Debug, PartialEq)] + pub struct GameObject { + pub id: u16, + pub x: u16, + pub y: u16, + pub shape: Shape, + pub shape_params: Vec, + pub vel: Vector, + pub is_static: bool + } - let updated_bounding_box = self.bounding_box_from(updated_x, updated_y); - if updated_bounding_box.points().iter().any(|p| p.x < 0 || p.x > field_width as i16 || p.y < 0 || p.y > field_height as i16) { - return; + impl GameObject { + pub fn update_pos(&mut self, field_width: u16, field_height: u16) { + let updated_x = self.x.wrapping_add(self.vel.x as u16); + let updated_y = self.y.wrapping_add(self.vel.y as u16); + + let updated_bounding_box = self.bounding_box_from(updated_x, updated_y); + if updated_bounding_box.points().iter().any(|p| p.x < 0 || p.x > field_width as i16 || p.y < 0 || p.y > field_height as i16) { + return; + } + self.x = updated_x; + self.y = updated_y; } - self.x = updated_x; - self.y = updated_y; - } - pub fn set_vel_x(&mut self, x: i32) { - self.vel.x = x - } + pub fn set_vel_x(&mut self, x: i32) { + self.vel.x = x + } - pub fn set_vel_y(&mut self, y: i32) { - self.vel.y = y - } + pub fn set_vel_y(&mut self, y: i32) { + self.vel.y = y + } - pub fn bounding_box(&self) -> BoundingBox { - self.bounding_box_from(self.x, self.y) - } + pub fn bounding_box(&self) -> BoundingBox { + self.bounding_box_from(self.x, self.y) + } - fn bounding_box_from(&self, x: u16, y: u16) -> BoundingBox { - match self.shape { - Shape::Rect => { - BoundingBox::create(x, y, self.shape_params[0], self.shape_params[1]) - }, - Shape::Circle => { - BoundingBox::create(x, y, self.shape_params[0] * 2, self.shape_params[0] * 2) + fn bounding_box_from(&self, x: u16, y: u16) -> BoundingBox { + match self.shape { + Shape::Rect => { + BoundingBox::create(x, y, self.shape_params[0], self.shape_params[1]) + }, + Shape::Circle => { + BoundingBox::create(x, y, self.shape_params[0] * 2, self.shape_params[0] * 2) + } } } } + } diff --git a/src/lib.rs b/src/lib.rs index c07201e..19a91ad 100644 --- a/src/lib.rs +++ b/src/lib.rs @@ -8,7 +8,8 @@ use std::cmp::{max, min}; use serde::{Deserialize, Serialize}; use serde_json::json; use wasm_bindgen::prelude::*; -use crate::game_object::{GameObject, Shape}; +use crate::collision::collision::{CollisionDetector}; +use crate::game_object::game_object::{GameObject, Shape}; use crate::geom::geom::{BoundingBox, Vector}; extern crate serde_json; @@ -179,35 +180,12 @@ impl Field { ball.obj.update_pos(self.width, self.height) } - let mut collisions = self.detect_collisions(); - for mut collision in collisions.iter_mut() { - let players = &self.players; - let balls = &self.balls; - // TODO: Find obj by id. - // if !collision.obj_a.is_static { - // collision.obj_a.vel.invert(); - // } - // if !collision.obj_b.is_static { - // collision.obj_b.vel.invert(); - // } - } - } - - fn detect_collisions(&mut self) -> Vec { - let balls = self.balls(); - let players = self.players(); - - let mut collisions = vec![]; - // for ball in balls.into_iter() { - // let collision_opt = players.into_iter().find(|p| p.obj.bounding_box().overlaps(&ball.obj.bounding_box())); - // if let None = collision_opt { - // continue; - // } - // let player = collision_opt.unwrap(); - // // TODO: This can cause multiple mutable refs of the same player/ball object and therefore does not compile. - // collisions.push(Collision {obj_a: player.obj.id, obj_b: ball.obj.id}); - // } - collisions + let mut objs: Vec<&GameObject> = vec![]; + objs.extend(self.players().iter().map(|p| &p.obj).collect::>()); + objs.extend(self.balls().iter().map(|p| &p.obj).collect::>()); + let collision_detector = CollisionDetector::new(); + let collision = collision_detector.detect_collisions(objs); + log!("{:?}", collision.get_collisions()); } pub fn players(&self) -> Vec<&Player> { @@ -261,7 +239,7 @@ impl Ball { } } -#[derive(Debug)] +#[derive(Debug, PartialEq, Eq)] pub struct Collision { obj_a: u16, obj_b: u16 diff --git a/tests/collision_tests.rs b/tests/collision_tests.rs new file mode 100644 index 0000000..c79841e --- /dev/null +++ b/tests/collision_tests.rs @@ -0,0 +1,12 @@ +use rstest::rstest; +use rust_wasm::GameObject; +use rust_wasm::Collision; +use rust_wasm::CollisionDetector; + +#[rstest] +#[case(vec![], vec![])] +pub fn should_detect_collisions(#[case] objs: Vec<&GameObject>, #[case] expected_collisions: Vec) { + let detector = CollisionDetector::new(); + let res = detector.detect_collisions(objs); + assert_eq!(res, expected_collisions); +}