From 2aff2713d3c4fad7cf2c4c86aa7ec22a495c91a0 Mon Sep 17 00:00:00 2001 From: Thilo Behnke Date: Mon, 25 Apr 2022 23:57:40 +0200 Subject: [PATCH] using refcells? --- pong/src/collision.rs | 29 +- pong/src/game_field.rs | 385 +++++++++++++-------------- pong/src/game_object.rs | 44 +-- pong/src/geom.rs | 55 ++-- pong/src/lib.rs | 2 +- pong/src/utils.rs | 4 +- pong/tests/bounding_box_tests.rs | 2 +- pong/tests/collision_handler_test.rs | 24 +- pong/tests/collision_tests.rs | 39 ++- pong/tests/game_field_test.rs | 24 +- pong/tests/game_object_tests.rs | 23 +- pong/tests/vector_tests.rs | 19 +- src/lib.rs | 54 ++-- 13 files changed, 342 insertions(+), 362 deletions(-) diff --git a/pong/src/collision.rs b/pong/src/collision.rs index 60352b2..ac2b0c9 100644 --- a/pong/src/collision.rs +++ b/pong/src/collision.rs @@ -1,9 +1,10 @@ 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; + use std::alloc::handle_alloc_error; + use std::cell::{Ref, RefCell}; + use std::collections::HashMap; + use std::fmt::Debug; pub struct CollisionDetector {} @@ -12,18 +13,21 @@ pub mod collision { CollisionDetector {} } - pub fn detect_collisions(&self, objs: &Vec<&Box>) -> Box { + pub fn detect_collisions( + &self, + objs: Vec<&RefCell>>, + ) -> Box { if objs.is_empty() { return Box::new(Collisions::new(vec![])); } let mut collisions: Vec = vec![]; let mut i = 0; loop { - let obj = objs[i]; + let obj = objs[i].borrow(); i += 1; let rest = &objs[i..]; - for other in rest.iter() { + for other in rest.iter().map(|o| o.borrow()) { let has_collision = obj.bounding_box().overlaps(&other.bounding_box()); if !has_collision { continue; @@ -39,7 +43,7 @@ pub mod collision { } } - pub trait CollisionRegistry : Debug { + pub trait CollisionRegistry: Debug { fn get_collisions(&self) -> Vec<&Collision>; fn get_collisions_by_id(&self, id: u16) -> Vec<&Collision>; } @@ -70,18 +74,23 @@ pub mod collision { #[derive(Debug, Eq, PartialEq)] pub struct Collision(pub u16, pub u16); + #[derive(Clone)] pub struct CollisionHandler { - handlers: HashMap<(String, String), fn(&mut Box, &mut Box)> + handlers: HashMap<(String, String), fn(&mut Box, &mut Box)>, } impl CollisionHandler { pub fn new() -> CollisionHandler { CollisionHandler { - handlers: HashMap::new() + handlers: HashMap::new(), } } - pub fn register(&mut self, mapping: (String, String), callback: fn(&mut Box, &mut Box)) { + pub fn register( + &mut self, + mapping: (String, String), + callback: fn(&mut Box, &mut Box), + ) { self.handlers.insert(mapping, callback); } diff --git a/pong/src/game_field.rs b/pong/src/game_field.rs index 5fd52be..7b29a3a 100644 --- a/pong/src/game_field.rs +++ b/pong/src/game_field.rs @@ -1,9 +1,15 @@ -use crate::collision::collision::{Collision, CollisionDetector, CollisionHandler, CollisionRegistry, Collisions}; +use std::borrow::{Borrow, BorrowMut}; +use crate::collision::collision::{ + Collision, CollisionDetector, CollisionHandler, CollisionRegistry, Collisions, +}; use crate::game_object::components::{DefaultGeomComp, DefaultPhysicsComp}; use crate::game_object::game_object::{DefaultGameObject, GameObject}; use crate::geom::geom::Vector; use crate::geom::shape::{Shape, ShapeType}; use crate::utils::utils::{Logger, NoopLogger}; +use std::cell::{Cell, RefCell, RefMut}; +use std::collections::HashMap; +use std::ops::Deref; #[derive(Clone, Copy, Debug, PartialEq, Eq)] pub enum InputType { @@ -21,11 +27,9 @@ pub struct Field { pub logger: Box, pub width: u16, pub height: u16, - pub players: Vec, - pub balls: Vec, - pub bounds: Bounds, + pub objs: HashMap>>, pub collisions: Box, - collision_handler: CollisionHandler + collision_handler: CollisionHandler, } impl Field { @@ -37,36 +41,40 @@ impl Field { logger, width, height, - players: vec![], - balls: vec![], - bounds: Bounds::new(width, height), + objs: DefaultGameObject::bounds(width, height), collisions: Box::new(Collisions::new(vec![])), - collision_handler: CollisionHandler::new() + collision_handler: CollisionHandler::new(), }; field.add_player(0, 0 + width / 20, height / 2); field.add_player(1, width - width / 20, height / 2); field.add_ball(2, width / 2, height / 2); - field.collision_handler.register((String::from("ball"), String::from("player")), |ball, player| { - // reflect - ball.vel_mut().reflect(&player.orientation()); - // use vel of player obj - if *player.vel() != Vector::zero() { - let mut adjusted = player.vel().clone(); - adjusted.normalize(); - ball.vel_mut().add(&adjusted); - } - // move out of collision - let mut b_to_a = ball.pos().clone(); - b_to_a.sub(&player.pos()); - b_to_a.normalize(); - ball.pos_mut().add(&b_to_a); - }); + field.collision_handler.register( + (String::from("ball"), String::from("player")), + |ball, player| { + // reflect + ball.vel_mut().reflect(&player.orientation()); + // use vel of player obj + if *player.vel() != Vector::zero() { + let mut adjusted = player.vel().clone(); + adjusted.normalize(); + ball.vel_mut().add(&adjusted); + } + // move out of collision + let mut b_to_a = ball.pos().clone(); + b_to_a.sub(&player.pos()); + b_to_a.normalize(); + ball.pos_mut().add(&b_to_a); + }, + ); - field.collision_handler.register((String::from("ball"), String::from("bound")), |ball, bound| { - ball.vel_mut().reflect(&bound.orientation()); - }); + field.collision_handler.register( + (String::from("ball"), String::from("bound")), + |ball, bound| { + ball.vel_mut().reflect(&bound.orientation()); + }, + ); return field; } @@ -76,64 +84,77 @@ impl Field { logger: Box::new(NoopLogger {}), width, height, - players: vec![], - balls: vec![], - bounds: Bounds::new(width, height), + objs: DefaultGameObject::bounds(width, height), collisions: Box::new(Collisions::new(vec![])), - collision_handler: CollisionHandler::new() + collision_handler: CollisionHandler::new(), } } pub fn add_player(&mut self, id: u16, x: u16, y: u16) { - self.players.push(Player::new(id, x, y, &self)); + let player = DefaultGameObject::player(id, x, y, &self); + self.objs.insert(player.id(), RefCell::new(player)); } pub fn add_ball(&mut self, id: u16, x: u16, y: u16) { - let ball = Ball::new(id, x, y, &self); - self.balls.push(ball); + let ball = DefaultGameObject::ball(id, x, y, &self); + self.objs.insert(ball.id(), RefCell::new(ball)); } pub fn tick(&mut self, inputs: Vec) { - for ball in self.balls.iter_mut() { - if *ball.obj.vel() == Vector::zero() { - ball.obj.vel_mut().add(&Vector::new(-2.0, 0.)) + { + for (_, obj) in self.objs.iter() { + let mut obj_mut = obj.borrow_mut(); + if obj_mut.obj_type() != "ball" { + continue; + } + if *obj_mut.vel() == Vector::zero() { + obj_mut.vel_mut().add(&Vector::new(-2.0, 0.)) + } } } - for player in self.players.iter_mut() { - let input_opt = inputs.iter().find(|input| player.obj.id() == input.obj_id); - if let None = input_opt { - player.obj.vel_mut().y = 0.; - continue; + { + for (_, obj) in self.objs.iter() { + let mut obj_mut = obj.borrow_mut(); + if obj_mut.obj_type() != "player" { + continue; + } + let input_opt = inputs.iter().find(|i| i.obj_id == obj_mut.id()); + if let None = input_opt { + obj_mut.vel_mut().y = 0.; + continue; + } + let input = input_opt.unwrap(); + match input.input { + InputType::UP => { + let updated_vel_y = (obj_mut.vel().y + 1.).min(5.); + obj_mut.vel_mut().y = updated_vel_y; + } + InputType::DOWN => { + let updated_vel_y = (obj_mut.vel().y - 1.).max(-5.); + obj_mut.vel_mut().y = updated_vel_y; + } + }; } - let input = input_opt.unwrap(); - match input.input { - InputType::UP => { - let updated_vel_y = (player.obj.vel().y + 1.).min(5.); - player.obj.vel_mut().y = updated_vel_y; - } - InputType::DOWN => { - let updated_vel_y = (player.obj.vel().y - 1.).max(-5.); - player.obj.vel_mut().y = updated_vel_y; - } - }; } - for player in self.players.iter_mut() { - player.obj.update_pos() - } - for ball in self.balls.iter_mut() { - ball.obj.update_pos() + { + for (_, obj) in self.objs.iter() { + let mut obj_mut = obj.borrow_mut(); + obj_mut.update_pos(); + } } let collisions = self.get_collisions(); + let collision_handler = self.collision_handler.clone(); for collision in collisions.get_collisions().iter() { - // self.handle_collision(c); - let objs_mut = self.objs_mut(); - let obj_a = objs_mut.iter().find(|o| o.id() == collision.0).unwrap(); - let obj_b = objs_mut.iter().find(|o| o.id() == collision.1).unwrap(); - self.collision_handler.handle(*obj_a, *obj_b) + // TODO: This is fine because an obj will not collide with itself - better abstraction? + // let idx + // let (obj_a, obj_b) = self.objs.split_at_mut(); + // let obj_a = self.get_obj(collision.0, self.objs.borrow_mut()); + // let obj_b = self.get_obj(collision.1, self.objs.borrow_mut()); + // collision_handler.handle(obj_a, obj_b) } // // for ball in self.balls.iter_mut() { @@ -160,165 +181,117 @@ impl Field { } fn get_collisions(&self) -> Box { - let objs = self.objs(); + let objs = self.objs.iter().map(|(_, o)| o).collect(); let collision_detector = CollisionDetector::new(); - collision_detector.detect_collisions(&objs) + collision_detector.detect_collisions(objs) } - fn handle_collision(&mut self, collision: &Collision) { - let objs_mut = self.objs_mut(); - let obj_a = objs_mut.iter().find(|o| o.id() == collision.0).unwrap(); - let obj_b = objs_mut.iter().find(|o| o.id() == collision.1).unwrap(); - self.collision_handler.handle(*obj_a, *obj_b) - } - - pub fn players(&self) -> Vec<&Player> { - self.players.iter().collect() - } - - pub fn balls(&self) -> Vec<&Ball> { - self.balls.iter().collect() - } - - fn objs(&self) -> Vec<&Box> { - let mut objs: Vec<&Box> = vec![]; - objs.extend( - self.players - .iter() - .map(|p| &p.obj) - .collect::>>(), - ); - objs.extend( - self.balls - .iter() - .map(|b| &b.obj) - .collect::>>(), - ); - objs.extend( - self.bounds.objs - .iter() - .collect::>>() - ); - objs - } - - fn objs_mut(&mut self) -> Vec<&mut Box> { - let mut objs: Vec<&mut Box> = vec![]; - objs.extend( - self.players - .iter_mut() - .map(|p| &mut p.obj) - .collect::>>(), - ); - objs.extend( - self.balls - .iter_mut() - .map(|b| &mut b.obj) - .collect::>>(), - ); - objs.extend( - self.bounds.objs - .iter_mut() - .collect::>>() - ); - objs + fn get_obj<'a>(&self, id: u16, mut objs: &'a RefMut>>) -> &'a mut Box { + objs.iter_mut().find(|o| o.id() == id).unwrap() } } -// #[derive(Clone, Debug, PartialEq)] -#[derive(Debug)] -pub struct Player { - pub obj: Box, -} - -impl Player { - pub fn new(id: u16, x: u16, y: u16, field: &Field) -> Player { - Player { - obj: Box::new(DefaultGameObject::new( +impl DefaultGameObject { + pub fn player(id: u16, x: u16, y: u16, field: &Field) -> Box { + 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.) - )), - Box::new(DefaultPhysicsComp::new( - Vector::zero(), - true - )) - )) - } + 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., + ))), + Box::new(DefaultPhysicsComp::new(Vector::zero(), true)), + )) } } -// #[derive(Clone, Debug, PartialEq)] -#[derive(Debug)] -pub struct Ball { - pub obj: Box, -} - -impl Ball { - pub fn new(id: u16, x: u16, y: u16, field: &Field) -> Ball { - Ball { - obj: Box::new(DefaultGameObject::new( +impl DefaultGameObject { + pub fn ball(id: u16, x: u16, y: u16, field: &Field) -> Box { + 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.) - )), - Box::new(DefaultPhysicsComp::new( + Box::new(DefaultGeomComp::new(Shape::circle( + Vector { + x: x as f64, + y: y as f64, + }, Vector::zero(), - false - )) - )) - } + (field.width as f64) / 80., + ))), + Box::new(DefaultPhysicsComp::new(Vector::zero(), false)), + )) } } -#[derive(Debug)] -pub struct Bounds { - pub objs: Vec>, -} - -impl Bounds { - pub fn new(width: u16, height: u16) -> Bounds { - Bounds { - objs: vec![ - // 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.) - )), - Box::new(DefaultPhysicsComp::new_static()) - )), - // 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.) - )), - Box::new(DefaultPhysicsComp::new_static()) - )), - // 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) - )), - Box::new(DefaultPhysicsComp::new_static()) - )), - // 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) - )), - Box::new(DefaultPhysicsComp::new_static()) - )) - ], - } +impl DefaultGameObject { + pub fn bounds(width: u16, height: u16) -> HashMap>> { + let bounds = vec![ + // 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., + ))), + Box::new(DefaultPhysicsComp::new_static()), + )), + // 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., + ))), + Box::new(DefaultPhysicsComp::new_static()), + )), + // 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, + ))), + Box::new(DefaultPhysicsComp::new_static()), + )), + // 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, + ))), + Box::new(DefaultPhysicsComp::new_static()), + )), + ]; + bounds.iter().map(|o| (o.id, RefCell::new(o))).collect() } } diff --git a/pong/src/game_object.rs b/pong/src/game_object.rs index 8814772..3b15a47 100644 --- a/pong/src/game_object.rs +++ b/pong/src/game_object.rs @@ -1,10 +1,10 @@ pub mod game_object { - use std::fmt::Debug; use crate::game_object::components::{GeomComp, PhysicsComp}; use crate::geom::geom::{BoundingBox, Vector}; use crate::geom::shape::{Shape, ShapeType}; + use std::fmt::Debug; - pub trait GameObject : Debug { + pub trait GameObject: Debug { fn id(&self) -> u16; fn obj_type(&self) -> &str; fn shape(&self) -> &ShapeType; @@ -24,12 +24,22 @@ pub mod game_object { pub id: u16, pub obj_type: String, geom: Box, - physics: Box + physics: Box, } impl DefaultGameObject { - pub fn new(id: u16, obj_type: String, geom: Box, physics: Box) -> DefaultGameObject { - DefaultGameObject {id, obj_type, geom, physics} + pub fn new( + id: u16, + obj_type: String, + geom: Box, + physics: Box, + ) -> DefaultGameObject { + DefaultGameObject { + id, + obj_type, + geom, + physics, + } } } @@ -92,11 +102,14 @@ pub mod game_object { } pub mod components { - use std::fmt::Debug; use crate::geom::geom::{BoundingBox, Vector}; - use crate::geom::shape::{get_bounding_box, get_center, get_center_mut, get_orientation, get_orientation_mut, Shape, ShapeType}; + use crate::geom::shape::{ + get_bounding_box, get_center, get_center_mut, get_orientation, get_orientation_mut, Shape, + ShapeType, + }; + use std::fmt::Debug; - pub trait GeomComp : Debug { + pub trait GeomComp: Debug { fn shape(&self) -> &ShapeType; fn orientation(&self) -> &Vector; fn orientation_mut(&mut self) -> &mut Vector; @@ -107,12 +120,12 @@ pub mod components { #[derive(Debug)] pub struct DefaultGeomComp { - shape: ShapeType + shape: ShapeType, } impl DefaultGeomComp { pub fn new(shape: ShapeType) -> DefaultGeomComp { - DefaultGeomComp {shape} + DefaultGeomComp { shape } } } @@ -142,7 +155,7 @@ pub mod components { } } - pub trait PhysicsComp : Debug { + pub trait PhysicsComp: Debug { fn vel(&self) -> &Vector; fn vel_mut(&mut self) -> &mut Vector; fn is_static(&self) -> bool; @@ -151,18 +164,15 @@ pub mod components { #[derive(Debug)] pub struct DefaultPhysicsComp { vel: Vector, - is_static: bool + is_static: bool, } impl DefaultPhysicsComp { pub fn new(vel: Vector, is_static: bool) -> DefaultPhysicsComp { - DefaultPhysicsComp {vel, is_static} + DefaultPhysicsComp { vel, is_static } } pub fn new_static() -> DefaultPhysicsComp { - DefaultPhysicsComp::new( - Vector::zero(), - true - ) + DefaultPhysicsComp::new(Vector::zero(), true) } } impl PhysicsComp for DefaultPhysicsComp { diff --git a/pong/src/geom.rs b/pong/src/geom.rs index 20ca72d..44804d8 100644 --- a/pong/src/geom.rs +++ b/pong/src/geom.rs @@ -17,9 +17,7 @@ pub mod geom { } pub fn new(x: f64, y: f64) -> Vector { - Vector { - x, y - } + Vector { x, y } } pub fn normalize(&mut self) { @@ -68,7 +66,7 @@ pub mod geom { } pub fn dot(&self, other: &Vector) -> f64 { - return self.x * other.x + self.y * other.y + return self.x * other.x + self.y * other.y; } pub fn angle(&self, other: &Vector) -> f64 { @@ -130,8 +128,8 @@ pub mod geom { impl PartialEq for Vector { fn eq(&self, other: &Self) -> bool { - (self.x * 1000.).round() == (other.x * 1000.).round() && - (self.y * 1000.).round() == (other.y * 1000.).round() + (self.x * 1000.).round() == (other.x * 1000.).round() + && (self.y * 1000.).round() == (other.y * 1000.).round() } } @@ -208,13 +206,9 @@ pub mod geom { impl Range { pub fn new(a: f64, b: f64) -> Range { if a <= b { - return Range { - min: a, max: b - } - } - return Range { - min: b, max: a + return Range { min: a, max: b }; } + return Range { min: b, max: a }; } pub fn overlaps(&self, other: &Range) -> bool { @@ -240,8 +234,8 @@ pub mod geom { } pub mod shape { - use std::fmt::Debug; use crate::geom::geom::{BoundingBox, Vector}; + use std::fmt::Debug; #[derive(Clone, Debug, PartialEq)] pub enum ShapeType { @@ -252,20 +246,29 @@ pub mod shape { #[derive(Clone, Debug, PartialEq)] pub struct Shape { center: Vector, - orientation: Vector + orientation: Vector, } impl Shape { pub fn rect(center: Vector, orientation: Vector, width: f64, height: f64) -> ShapeType { - ShapeType::Rect(Shape { - center, orientation - }, width, height) + ShapeType::Rect( + Shape { + center, + orientation, + }, + width, + height, + ) } pub fn circle(center: Vector, orientation: Vector, radius: f64) -> ShapeType { - ShapeType::Circle(Shape { - center, orientation - }, radius) + ShapeType::Circle( + Shape { + center, + orientation, + }, + radius, + ) } fn center(&self) -> &Vector { @@ -288,35 +291,37 @@ pub mod shape { pub fn get_center(shape: &ShapeType) -> &Vector { match shape { ShapeType::Rect(ref s, _, _) => &s.center, - ShapeType::Circle(ref s, _) => &s.center + ShapeType::Circle(ref s, _) => &s.center, } } pub fn get_center_mut(shape: &mut ShapeType) -> &mut Vector { match shape { ShapeType::Rect(ref mut s, _, _) => &mut s.center, - ShapeType::Circle(ref mut s, _) => &mut s.center + ShapeType::Circle(ref mut s, _) => &mut s.center, } } pub fn get_orientation(shape: &ShapeType) -> &Vector { match shape { ShapeType::Rect(s, _, _) => &s.orientation, - ShapeType::Circle(s, _) => &s.orientation + ShapeType::Circle(s, _) => &s.orientation, } } pub fn get_orientation_mut(shape: &mut ShapeType) -> &mut Vector { match shape { ShapeType::Rect(ref mut s, _, _) => &mut s.orientation, - ShapeType::Circle(ref mut s, _) => &mut s.orientation + ShapeType::Circle(ref mut s, _) => &mut s.orientation, } } pub fn get_bounding_box(shape: &ShapeType) -> BoundingBox { match shape { ShapeType::Rect(s, width, height) => BoundingBox::create(&s.center, *width, *height), - ShapeType::Circle(s, radius) => BoundingBox::create(&s.center, *radius * 2., *radius * 2.) + ShapeType::Circle(s, radius) => { + BoundingBox::create(&s.center, *radius * 2., *radius * 2.) + } } } } diff --git a/pong/src/lib.rs b/pong/src/lib.rs index 7879674..0faaf63 100644 --- a/pong/src/lib.rs +++ b/pong/src/lib.rs @@ -1,5 +1,5 @@ pub mod collision; +pub mod game_field; pub mod game_object; pub mod geom; -pub mod game_field; pub mod utils; diff --git a/pong/src/utils.rs b/pong/src/utils.rs index f281ec5..9aff964 100644 --- a/pong/src/utils.rs +++ b/pong/src/utils.rs @@ -1,4 +1,3 @@ - pub mod utils { pub trait Logger { fn log(&self, msg: &str); @@ -6,7 +5,6 @@ pub mod utils { pub struct NoopLogger {} impl Logger for NoopLogger { - fn log(&self, msg: &str) { - } + fn log(&self, msg: &str) {} } } diff --git a/pong/tests/bounding_box_tests.rs b/pong/tests/bounding_box_tests.rs index 5716de5..2a9d21f 100644 --- a/pong/tests/bounding_box_tests.rs +++ b/pong/tests/bounding_box_tests.rs @@ -1,5 +1,5 @@ -use rstest::rstest; use pong::geom::geom::{BoundingBox, Vector}; +use rstest::rstest; #[rstest] #[case(BoundingBox::create(&Vector::new(10., 10.), 5., 5.), Vector::new(10., 10.), true)] diff --git a/pong/tests/collision_handler_test.rs b/pong/tests/collision_handler_test.rs index 596d11f..64ba736 100644 --- a/pong/tests/collision_handler_test.rs +++ b/pong/tests/collision_handler_test.rs @@ -1,9 +1,9 @@ -use rstest::rstest; use pong::collision::collision::CollisionHandler; use pong::game_object::components::{DefaultGeomComp, DefaultPhysicsComp}; use pong::game_object::game_object::{DefaultGameObject, GameObject}; use pong::geom::geom::Vector; use pong::geom::shape::Shape; +use rstest::rstest; #[rstest] #[case( @@ -76,15 +76,21 @@ pub fn should_handle_collision( assert_eq!(obj_b.vel(), expected_b.vel()); } -fn create_game_obj(id: u16, vel: Vector, orientation: Vector, is_static: bool) -> Box { +fn create_game_obj( + id: u16, + vel: Vector, + orientation: Vector, + is_static: bool, +) -> Box { Box::new(DefaultGameObject::new( id, - "obj".to_string(), - Box::new(DefaultGeomComp::new( - Shape::rect(Vector::zero(), orientation, 20., 20.) - )), - Box::new(DefaultPhysicsComp::new( - vel, is_static - )) + "obj".to_string(), + Box::new(DefaultGeomComp::new(Shape::rect( + Vector::zero(), + orientation, + 20., + 20., + ))), + Box::new(DefaultPhysicsComp::new(vel, is_static)), )) } diff --git a/pong/tests/collision_tests.rs b/pong/tests/collision_tests.rs index 3a814d3..7404511 100644 --- a/pong/tests/collision_tests.rs +++ b/pong/tests/collision_tests.rs @@ -1,46 +1,46 @@ -use rstest::rstest; +use std::cell::{Ref, RefCell}; use pong::collision::collision::{Collision, CollisionDetector}; use pong::game_object::game_object::GameObject; use pong::geom::geom::{BoundingBox, Vector}; use pong::geom::shape::ShapeType; - +use rstest::rstest; #[rstest] -#[case(vec![], vec![])] +#[case(RefCell::new(vec![]), vec![])] #[case( - vec![ + RefCell::new(vec![ MockGameObject::new(1, BoundingBox::create(&Vector{x: 50., y: 50.}, 20., 20.)), MockGameObject::new(2, BoundingBox::create(&Vector{x: 50., y: 50.}, 20., 20.)) - ], + ]), vec![Collision(1, 2)] )] #[case( - vec![ + RefCell::new(vec![ MockGameObject::new(1, BoundingBox::create(&Vector{x: 60., y: 65.}, 20., 20.)), MockGameObject::new(2, BoundingBox::create(&Vector{x: 50., y: 50.}, 20., 20.)), - ], + ]), vec![Collision(1, 2)] )] #[case( - vec![ + RefCell::new(vec![ MockGameObject::new(1, BoundingBox::create(&Vector{x: 50., y: 50.}, 20., 20.)), MockGameObject::new(2, BoundingBox::create(&Vector{x: 80., y: 80.}, 20., 20.)), - ], + ]), vec![] )] #[case( - vec![ + RefCell::new(vec![ MockGameObject::new(1, BoundingBox::create(&Vector{x: 50., y: 50.}, 50., 50.)), MockGameObject::new(2, BoundingBox::create(&Vector{x: 500., y: 50.}, 50., 50.)), - ], + ]), vec![] )] pub fn should_detect_collisions( - #[case] objs: Vec>, + #[case] objs: RefCell>>, #[case] expected_collisions: Vec, ) { let detector = CollisionDetector::new(); - let res = detector.detect_collisions(&objs.iter().collect()); + let res = detector.detect_collisions(objs.borrow()); assert_eq!( res.get_collisions(), expected_collisions.iter().collect::>() @@ -51,16 +51,16 @@ pub fn should_detect_collisions( pub struct MockGameObject { id: u16, bounding_box: BoundingBox, - zero_vec: Vector + zero_vec: Vector, } impl MockGameObject { pub fn new(id: u16, bounding_box: BoundingBox) -> Box { - Box::new( - MockGameObject { - id, bounding_box, zero_vec: Vector::zero() - } - ) + Box::new(MockGameObject { + id, + bounding_box, + zero_vec: Vector::zero(), + }) } } @@ -73,7 +73,6 @@ impl GameObject for MockGameObject { todo!() } - fn shape(&self) -> &ShapeType { todo!() } diff --git a/pong/tests/game_field_test.rs b/pong/tests/game_field_test.rs index cb85dc6..c4de6c1 100644 --- a/pong/tests/game_field_test.rs +++ b/pong/tests/game_field_test.rs @@ -12,9 +12,9 @@ mod game_field_tests { obj_id: 1, }]; field.tick(inputs); - let players = field.players(); - let player = players.first().unwrap(); - assert_eq!(player.obj.pos().y, height as f64 / 2. + 1.); + let objs = field.objs.borrow(); + let player = objs.iter().find(|o| o.obj_type() == "player").unwrap(); + assert_eq!(player.pos().y, height as f64 / 2. + 1.); } #[test] @@ -27,9 +27,9 @@ mod game_field_tests { obj_id: 1, }]; field.tick(inputs); - let players = field.players(); - let player = players.first().unwrap(); - assert_eq!(player.obj.pos().y, height as f64 / 2. - 1.); + let objs = field.objs.borrow(); + let player = objs.iter().find(|o| o.obj_type() == "player").unwrap(); + assert_eq!(player.pos().y, height as f64 / 2. - 1.); } #[test] @@ -42,9 +42,9 @@ mod game_field_tests { obj_id: 1, }]; field.tick(inputs); - let players = field.players(); - let player = players.first().unwrap(); - assert_eq!(player.obj.pos().y, height as f64 - height as f64 / 5. / 2.); + let objs = field.objs.borrow(); + let player = objs.iter().find(|o| o.obj_type() == "player").unwrap(); + assert_eq!(player.pos().y, height as f64 - height as f64 / 5. / 2.); } #[test] @@ -57,8 +57,8 @@ mod game_field_tests { obj_id: 1, }]; field.tick(inputs); - let players = field.players(); - let player = players.first().unwrap(); - assert_eq!(player.obj.pos().y, height as f64 / 5. / 2.); + let objs = field.objs.borrow(); + let player = objs.iter().find(|o| o.obj_type() == "player").unwrap(); + assert_eq!(player.pos().y, height as f64 / 5. / 2.); } } diff --git a/pong/tests/game_object_tests.rs b/pong/tests/game_object_tests.rs index d89a796..784baef 100644 --- a/pong/tests/game_object_tests.rs +++ b/pong/tests/game_object_tests.rs @@ -1,21 +1,26 @@ -use rstest::rstest; use pong::game_object::components::{DefaultGeomComp, DefaultPhysicsComp}; use pong::game_object::game_object::{DefaultGameObject, GameObject}; -use pong::geom::geom::{Vector}; +use pong::geom::geom::Vector; use pong::geom::shape::Shape; +use rstest::rstest; #[rstest] #[case(Vector::new(100., 100.), Vector::new(-1., 1.), Vector::new(99., 101.))] -pub fn should_update_pos(#[case] start_pos: Vector, #[case] vel: Vector, #[case] expected_pos: Vector) { +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.) - )), - Box::new(DefaultPhysicsComp::new( - vel, false - )) + Box::new(DefaultGeomComp::new(Shape::rect( + Vector::new(start_pos.x as f64, start_pos.y as f64), + Vector::new(1., 0.), + 0., + 0., + ))), + Box::new(DefaultPhysicsComp::new(vel, false)), ); obj.update_pos(); assert_eq!(*obj.pos(), expected_pos); diff --git a/pong/tests/vector_tests.rs b/pong/tests/vector_tests.rs index 691eb72..e8fc097 100644 --- a/pong/tests/vector_tests.rs +++ b/pong/tests/vector_tests.rs @@ -1,8 +1,8 @@ -use rstest::rstest; use pong::geom::geom::Vector; -use std::f64::consts::PI; +use rstest::rstest; use std::f64::consts::FRAC_PI_2; use std::f64::consts::FRAC_PI_4; +use std::f64::consts::PI; #[rstest] #[case(1., 0., 1.)] @@ -39,7 +39,7 @@ pub fn should_normalize_correctly( pub fn should_calculate_angle_correctly( #[case] vector_a: Vector, #[case] vector_b: Vector, - #[case] expected_angle: f64 + #[case] expected_angle: f64, ) { let res = vector_a.angle(&vector_b); assert_eq!(res, expected_angle); @@ -49,10 +49,7 @@ pub fn should_calculate_angle_correctly( #[case(Vector::new(1., 0.), Vector::new(0., -1.))] #[case(Vector::new(0., 1.), Vector::new(1., 0.))] #[case(Vector::new(7., 7.), Vector::new(7., -7.))] -pub fn should_get_orthogonal_clockwise( - #[case] mut vector: Vector, - #[case] expected: Vector -) { +pub fn should_get_orthogonal_clockwise(#[case] mut vector: Vector, #[case] expected: Vector) { vector.orthogonal_clockwise(); assert_eq!(vector, expected); } @@ -63,7 +60,7 @@ pub fn should_get_orthogonal_clockwise( #[case(Vector::new(7., 7.), Vector::new(-7., 7.))] pub fn should_get_orthogonal_counter_clockwise( #[case] mut vector: Vector, - #[case] expected: Vector + #[case] expected: Vector, ) { vector.orthogonal_counter_clockwise(); assert_eq!(vector, expected); @@ -74,7 +71,7 @@ pub fn should_get_orthogonal_counter_clockwise( pub fn should_correctly_rotate( #[case] mut vector: Vector, #[case] radians: f64, - #[case] expected: Vector + #[case] expected: Vector, ) { vector.rotate(radians); assert_eq!(vector, expected); @@ -87,8 +84,7 @@ pub fn should_correctly_rotate( pub fn should_calculate_dot_product( #[case] mut vector: Vector, #[case] mut other: Vector, - #[case] expected: f64 - + #[case] expected: f64, ) { let dot = vector.dot(&other); assert_eq!(dot, expected); @@ -134,4 +130,3 @@ pub fn should_reflect_vector( vector.reflect(&onto); assert_eq!(vector, expected); } - diff --git a/src/lib.rs b/src/lib.rs index b0f51ac..661ceeb 100644 --- a/src/lib.rs +++ b/src/lib.rs @@ -1,15 +1,15 @@ mod utils; +use pong::collision::collision::{Collision, CollisionDetector}; +use pong::game_field::{Field, Input, InputType}; +use pong::game_object::game_object::GameObject; +use pong::geom::geom::Vector; +use pong::geom::shape::ShapeType; +use pong::utils::utils::Logger; use serde::{Deserialize, Serialize}; use serde_json::json; use std::cmp::{max, min}; use wasm_bindgen::prelude::*; -use pong::collision::collision::{Collision, CollisionDetector}; -use pong::game_field::{Field, Input, InputType}; -use pong::game_object::game_object::{GameObject}; -use pong::geom::geom::Vector; -use pong::geom::shape::ShapeType; -use pong::utils::utils::Logger; extern crate serde_json; extern crate web_sys; @@ -48,11 +48,11 @@ impl GameObjectDTO { y: pos.y as u16, shape_param_1: match shape { ShapeType::Rect(_, width, _) => *width as u16, - ShapeType::Circle(_, radius) => *radius as u16 + ShapeType::Circle(_, radius) => *radius as u16, }, shape_param_2: match shape { ShapeType::Rect(_, _, height) => *height as u16, - ShapeType::Circle(_, _) => 0 + ShapeType::Circle(_, _) => 0, }, }; } @@ -69,7 +69,7 @@ impl InputTypeDTO { pub fn to_input_type(&self) -> InputType { match self { InputTypeDTO::UP => InputType::UP, - InputTypeDTO::DOWN => InputType::DOWN + InputTypeDTO::DOWN => InputType::DOWN, } } } @@ -86,22 +86,20 @@ impl InputDTO { return Input { input: self.input.to_input_type(), obj_id: self.obj_id, - } + }; } } #[wasm_bindgen] pub struct FieldWrapper { - field: Field + field: Field, } #[wasm_bindgen] impl FieldWrapper { pub fn new() -> FieldWrapper { let field = Field::new(Box::new(WasmLogger {})); - FieldWrapper { - field - } + FieldWrapper { field } } pub fn width(&self) -> u16 { @@ -114,34 +112,16 @@ impl FieldWrapper { pub fn tick(&mut self, inputs_js: &JsValue) { let input_dtos: Vec = inputs_js.into_serde().unwrap(); - let inputs = input_dtos.into_iter().map(|i| i.to_input()).collect::>(); + let inputs = input_dtos + .into_iter() + .map(|i| i.to_input()) + .collect::>(); self.field.tick(inputs); log!("{:?}", self.field.collisions); } pub fn objects(&self) -> *const GameObjectDTO { - let mut objs = vec![]; - objs.append( - &mut self.field - .balls - .iter() - .map(|ball| GameObjectDTO::from(&ball.obj)) - .collect::>(), - ); - objs.append( - &mut self.field - .players - .iter() - .map(|player| GameObjectDTO::from(&player.obj)) - .collect::>(), - ); - objs.append( - &mut self.field - .bounds.objs - .iter() - .map(|bound| GameObjectDTO::from(&bound)) - .collect::>() - ); + let mut objs = self.field.objs.borrow().iter().map(|o| GameObjectDTO::from(o)).collect::>(); objs.as_ptr() }