test setup for collision tests

This commit is contained in:
Thilo Behnke
2022-04-18 23:33:04 +02:00
parent b5bae5114d
commit 04fbb6310d
4 changed files with 93 additions and 80 deletions

View File

@@ -10,23 +10,41 @@ pub mod collision {
CollisionDetector {}
}
pub fn detect_collisions(objs: Vec<GameObject>) -> Box<dyn CollisionRegistry> {
let registry = Collisions::new(HashMap::new());
pub fn detect_collisions(&self, objs: Vec<&GameObject>) -> Box<dyn CollisionRegistry> {
let mut collisions: Vec<Collision> = 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<Collision>;
}
pub struct Collisions {
state: HashMap<String, Vec<Collision>>
pub state: Vec<Collision>
}
impl Collisions {
pub fn new(collisions: HashMap<String, Vec<Collision>>) -> Collisions {
pub fn new(collisions: Vec<Collision>) -> 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);
}

View File

@@ -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<u16>,
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<u16>,
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)
}
}
}
}
}

View File

@@ -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<Collision> {
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::<Vec<&GameObject>>());
objs.extend(self.balls().iter().map(|p| &p.obj).collect::<Vec<&GameObject>>());
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

12
tests/collision_tests.rs Normal file
View File

@@ -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<Collision>) {
let detector = CollisionDetector::new();
let res = detector.detect_collisions(objs);
assert_eq!(res, expected_collisions);
}