diff --git a/pong/src/game_field.rs b/pong/src/game_field.rs index 5bff345..1efbdd0 100644 --- a/pong/src/game_field.rs +++ b/pong/src/game_field.rs @@ -1,6 +1,5 @@ -use std::f64::consts::{FRAC_PI_2, FRAC_PI_4}; use crate::collision::collision::{Collision, CollisionDetector, CollisionHandler, CollisionRegistry, Collisions}; -use crate::game_object::game_object::{GameObject, Shape}; +use crate::game_object::game_object::{GameObject, ShapeType}; use crate::geom::geom::Vector; use crate::utils::utils::{Logger, NoopLogger}; @@ -71,7 +70,7 @@ impl Field { pub fn tick(&mut self, inputs: Vec) { for ball in self.balls.iter_mut() { - if ball.obj.vel == Vector::zero() { + if ball.obj.physics.vel() == Vector::zero() { ball.obj.set_vel_x(-2.) } } @@ -85,10 +84,12 @@ impl Field { let input = input_opt.unwrap(); match input.input { InputType::UP => { - player.obj.vel.y = (player.obj.vel.y + 1.).min(5.); + let updated_vel_y = (player.obj.vel.y + 1.).min(5.); + player.obj.set_vel_y(updated_vel_y); } InputType::DOWN => { - player.obj.vel.y = (player.obj.vel.y - 1.).max(-5.); + let updated_vel_y = (player.obj.vel.y - 1.).max(-5.); + player.obj.set_vel_y(updated_vel_y); } }; } @@ -170,7 +171,7 @@ impl Player { id, pos: Vector {x: x as f64, y: y as f64}, orientation: Vector::new(0., 1.), - shape: Shape::Rect, + shape: ShapeType::Rect, shape_params: vec![field.width / 25, field.height / 5], vel: Vector::zero(), is_static: true, @@ -191,7 +192,7 @@ impl Ball { id, pos: Vector {x: x as f64, y: y as f64}, orientation: Vector::zero(), - shape: Shape::Circle, + shape: ShapeType::Circle, shape_params: vec![field.width / 80], vel: Vector::zero(), is_static: false, @@ -214,7 +215,7 @@ impl Bounds { id: 90, pos: Vector {x: (width / 2) as f64, y: 0 as f64}, orientation: Vector::new(1., 0.), - shape: Shape::Rect, + shape: ShapeType::Rect, shape_params: vec![width, 2], is_static: true, vel: Vector::zero(), @@ -224,7 +225,7 @@ impl Bounds { id: 91, pos: Vector {x: (width / 2) as f64, y: height as f64}, orientation: Vector::new(-1., 0.), - shape: Shape::Rect, + shape: ShapeType::Rect, shape_params: vec![width, 2], is_static: true, vel: Vector::zero(), @@ -234,7 +235,7 @@ impl Bounds { id: 92, pos: Vector {x: 0 as f64, y: (height / 2) as f64}, orientation: Vector::new(0., 1.), - shape: Shape::Rect, + shape: ShapeType::Rect, shape_params: vec![2, height], is_static: true, vel: Vector::zero(), @@ -244,7 +245,7 @@ impl Bounds { id: 93, pos: Vector {x: width as f64, y: (height / 2) as f64}, orientation: Vector::new(0., -1.), - shape: Shape::Rect, + shape: ShapeType::Rect, shape_params: vec![2, height], is_static: true, vel: Vector::zero(), diff --git a/pong/src/game_object.rs b/pong/src/game_object.rs index abae1ec..4454d20 100644 --- a/pong/src/game_object.rs +++ b/pong/src/game_object.rs @@ -1,53 +1,108 @@ pub mod game_object { + use crate::game_object::components::{GeomComp, PhysicsComp}; use crate::geom::geom::{BoundingBox, Vector}; - - #[derive(Clone, Debug, PartialEq)] - pub enum Shape { - Rect = 0, - Circle = 1, - } + use crate::geom::shape::ShapeType; #[derive(Clone, Debug, PartialEq)] pub struct GameObject { pub id: u16, - pub pos: Vector, - pub orientation: Vector, - pub shape: Shape, - pub shape_params: Vec, - pub vel: Vector, - pub is_static: bool, + pub geom: Box, + pub physics: Box } impl GameObject { - pub fn update_pos(&mut self) { - self.pos.add(&self.vel); + let center = self.geom.center_mut(); + center.add(&self.vel); // Keep last orientation if vel is now zero. - if self.vel == Vector::zero() { + let vel = self.physics.vel(); + if vel == Vector::zero() { return; } - let mut orientation = self.vel.clone(); + let mut orientation = vel.clone(); orientation.normalize(); self.orientation = orientation; } pub fn set_vel_x(&mut self, x: f64) { - self.vel.x = x + let vel = self.physics.vel_mut(); + vel.x = x; } pub fn set_vel_y(&mut self, y: f64) { - self.vel.y = y + let vel = self.physics.vel_mut(); + vel.y = y; } pub fn bounding_box(&self) -> BoundingBox { - match self.shape { - Shape::Rect => { - BoundingBox::create(&self.pos, self.shape_params[0], self.shape_params[1]) - } - Shape::Circle => { - BoundingBox::create(&self.pos, self.shape_params[0] * 2, self.shape_params[0] * 2) - } - } + self.geom.shape().bounding_box() + } + } +} + +pub mod components { + use crate::geom::geom::Vector; + use crate::geom::shape::Shape; + + pub trait GeomComp { + fn orientation(&self) -> &Vector; + fn orientation_mut(&mut self) -> &mut Vector; + fn center(&self) -> &Vector; + fn center_mut(&mut self) -> &mut Vector; + } + + pub struct DefaultGeomComp { + shape: Box + } + impl DefaultGeomComp { + pub fn new(shape: Box) -> DefaultGeomComp { + DefaultGeomComp {shape} + } + } + impl GeomComp for DefaultGeomComp { + fn orientation(&self) -> &Vector { + &self.shape.orientation() + } + + fn orientation_mut(&mut self) -> &mut Vector { + &mut self.shape.orientation() + } + + fn center(&self) -> &Vector { + &self.shape.center() + } + + fn center_mut(&mut self) -> &mut Vector { + &mut self.shape.center() + } + } + + pub trait PhysicsComp { + fn vel(&self) -> &Vector; + fn vel_mut(&mut self) -> &mut Vector; + fn is_static(&self) -> bool; + } + + pub struct DefaultPhysicsComp { + vel: Vector, + is_static: bool + } + impl DefaultPhysicsComp { + pub fn new(vel: Vector, is_static: bool) -> DefaultPhysicsComp { + DefaultPhysicsComp {vel, is_static} + } + } + impl PhysicsComp for DefaultPhysicsComp { + fn vel(&self) -> &Vector { + &self.vel + } + + fn vel_mut(&mut self) -> &mut Vector { + &mut self.vel + } + + fn is_static(&self) -> bool { + self.is_static } } } diff --git a/pong/src/geom.rs b/pong/src/geom.rs index 374f9c4..d78c212 100644 --- a/pong/src/geom.rs +++ b/pong/src/geom.rs @@ -143,29 +143,24 @@ pub mod geom { } impl BoundingBox { - pub fn create_from_coords(x: f64, y: f64, width: u16, height: u16) -> BoundingBox { - let center = Vector::new(x, y); - return BoundingBox::create(¢er, width, height) - } - - pub fn create(center: &Vector, width: u16, height: u16) -> BoundingBox { + pub fn create(center: &Vector, width: f64, height: f64) -> BoundingBox { let center_x = center.x; let center_y = center.y; let top_left = Vector { - x: center_x - (width as f64 / 2.), - y: center_y + (height as f64 / 2.), + x: center_x - width / 2., + y: center_y + height / 2., }; let top_right = Vector { - x: center_x + (width as f64 / 2.), - y: center_y + (height as f64 / 2.), + x: center_x + width / 2., + y: center_y + height / 2., }; let bottom_left = Vector { - x: center_x - (width as f64 / 2.), - y: center_y - (height as f64 / 2.), + x: center_x - width / 2., + y: center_y - height / 2., }; let bottom_right = Vector { - x: center_x + (width as f64 / 2.), - y: center_y - (height as f64 / 2.), + x: center_x + width / 2., + y: center_y - height / 2., }; BoundingBox { top_left, @@ -242,3 +237,85 @@ pub mod geom { } } } + +pub mod shape { + use crate::geom::geom::{BoundingBox, Vector}; + + #[derive(Clone, Debug, PartialEq)] + pub enum ShapeType { + Rect = 0, + Circle = 1, + } + + pub trait Shape { + fn center(&self) -> &Vector; + fn orientation(&self) -> &Vector; + fn shape_type(&self) -> ShapeType; + fn bounding_box(&self) -> BoundingBox; + } + + pub struct Rect { + pub width: f64, + pub height: f64, + center: Vector, + orientation: Vector + } + + impl Rect { + pub fn new(center: Vector, orientation: Vector, width: f64, height: f64) -> Rect { + Rect { + center, orientation, width, height + } + } + } + + impl Shape for Rect { + fn center(&self) -> &Vector { + &self.center + } + + fn orientation(&self) -> &Vector { + &self.orientation + } + + fn shape_type(&self) -> ShapeType { + ShapeType::Rect + } + + fn bounding_box(&self) -> BoundingBox { + BoundingBox::create(self.center(), self.width, self.height) + } + } + + pub struct Circle { + pub radius: f64, + center: Vector, + orientation: Vector, + } + + impl Circle { + pub fn new(center: Vector, orientation: Vector, radius: f64) -> Circle { + Circle { + center, orientation, radius + } + } + } + + impl Shape for Circle { + fn center(&self) -> &Vector { + &self.center + } + + fn orientation(&self) -> &Vector { + &self.orientation + } + + fn shape_type(&self) -> ShapeType { + ShapeType::Circle + } + + fn bounding_box(&self) -> BoundingBox { + BoundingBox::create(&self.center(), self.radius * 2, self.radius * 2) + } + } +} diff --git a/pong/tests/collision_handler_test.rs b/pong/tests/collision_handler_test.rs index cc60e74..04298d2 100644 --- a/pong/tests/collision_handler_test.rs +++ b/pong/tests/collision_handler_test.rs @@ -1,6 +1,6 @@ use rstest::rstest; use pong::collision::collision::CollisionHandler; -use pong::game_object::game_object::{GameObject, Shape}; +use pong::game_object::game_object::{GameObject, ShapeType}; use pong::geom::geom::Vector; #[rstest] diff --git a/pong/tests/collision_tests.rs b/pong/tests/collision_tests.rs index 8cd9c3c..fbf9b99 100644 --- a/pong/tests/collision_tests.rs +++ b/pong/tests/collision_tests.rs @@ -1,6 +1,6 @@ use rstest::rstest; use pong::collision::collision::{Collision, CollisionDetector}; -use pong::game_object::game_object::{GameObject, Shape}; +use pong::game_object::game_object::{GameObject, ShapeType}; use pong::geom::geom::{Vector}; #[rstest] diff --git a/pong/tests/game_object_tests.rs b/pong/tests/game_object_tests.rs index 077c4f3..0f35b70 100644 --- a/pong/tests/game_object_tests.rs +++ b/pong/tests/game_object_tests.rs @@ -1,5 +1,5 @@ use rstest::rstest; -use pong::game_object::game_object::{GameObject, Shape}; +use pong::game_object::game_object::{GameObject, ShapeType}; use pong::geom::geom::{Vector}; #[rstest] @@ -9,7 +9,7 @@ pub fn should_update_pos(#[case] start_pos: Vector, #[case] vel: Vector, #[case] id: 1, pos: Vector::new(start_pos.x as f64, start_pos.y as f64), vel, - shape: Shape::Rect, + shape: ShapeType::Rect, shape_params: vec![], is_static: false, orientation: Vector::new(1., 0.) diff --git a/src/lib.rs b/src/lib.rs index 8aeddd8..57020ea 100644 --- a/src/lib.rs +++ b/src/lib.rs @@ -6,7 +6,7 @@ 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, Shape}; +use pong::game_object::game_object::{GameObject, ShapeType}; use pong::geom::geom::Vector; use pong::utils::utils::Logger;