mirror of
https://github.com/thilo-behnke/wasm-pong.git
synced 2026-05-17 09:26:32 +00:00
test setup for collision tests
This commit is contained in:
@@ -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);
|
||||
}
|
||||
|
||||
@@ -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)
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
}
|
||||
|
||||
|
||||
40
src/lib.rs
40
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<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
12
tests/collision_tests.rs
Normal 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);
|
||||
}
|
||||
Reference in New Issue
Block a user