object composition really right approach? would be much simpler to just copy the game objs if needed

This commit is contained in:
Thilo Behnke
2022-05-01 18:33:54 +02:00
parent 967e13545d
commit 213ea54509
6 changed files with 51 additions and 56 deletions

View File

@@ -2,7 +2,7 @@ pub mod collision {
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::cell::{Ref, RefCell, RefMut};
use std::collections::HashMap;
use std::fmt::Debug;
use std::rc::Rc;
@@ -78,7 +78,7 @@ pub mod collision {
#[derive(Clone)]
pub struct CollisionHandler {
handlers: HashMap<(String, String), fn(&mut Box<dyn GameObject>, &mut Box<dyn GameObject>)>,
handlers: HashMap<(String, String), fn(Rc<RefCell<Box<dyn GameObject>>>, Rc<RefCell<Box<dyn GameObject>>>)>
}
impl CollisionHandler {
@@ -91,7 +91,7 @@ pub mod collision {
pub fn register(
&mut self,
mapping: (String, String),
callback: fn(&mut Box<dyn GameObject>, &mut Box<dyn GameObject>),
callback: fn(Rc<RefCell<Box<dyn GameObject>>>, Rc<RefCell<Box<dyn GameObject>>>),
) {
if self.handlers.contains_key(&mapping) {
panic!(
@@ -104,10 +104,10 @@ pub mod collision {
pub fn handle(
&self,
obj_a: &mut Box<dyn GameObject>,
obj_b: &mut Box<dyn GameObject>,
obj_a: Rc<RefCell<Box<dyn GameObject>>>,
obj_b: Rc<RefCell<Box<dyn GameObject>>>,
) -> bool {
let key = (obj_a.obj_type().to_string(), obj_b.obj_type().to_string());
let key = (RefCell::borrow(&obj_a).obj_type().to_string(), RefCell::borrow(&obj_b).obj_type().to_string());
if !self.handlers.contains_key(&key) {
return false;
}

View File

@@ -136,6 +136,7 @@ impl Field {
{
for obj in self.objs.iter() {
let mut obj_mut = RefCell::borrow_mut(obj);
self.logger.log("update player");
obj_mut.update_pos();
}
}
@@ -144,35 +145,12 @@ impl Field {
let collision_handler = self.collision_handler.clone();
for collision in collisions.get_collisions().iter() {
// 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)
let objs = &self.objs;
let obj_a = objs.iter().find(|o| RefCell::borrow(o).id() == collision.0).unwrap().clone();
let obj_b = objs.iter().find(|o| RefCell::borrow(o).id() == collision.1).unwrap().clone();
self.logger.log(&*format!("Handling collision between {:?} and {:?}", obj_a, obj_b));
collision_handler.handle(obj_a, obj_b);
}
//
// for ball in self.balls.iter_mut() {
// let collisions = self.collisions.get_collisions_by_id(ball.obj.id());
// if collisions.is_empty() {
// continue;
// }
// let other = match collisions[0] {
// Collision(obj_a_id, obj_b_id) if *obj_a_id == ball.obj.id() => {
// objs.iter().find(|o| o.id() == *obj_b_id).unwrap()
// }
// collision => objs.iter().find(|o| o.id() == collision.0).unwrap(),
// };
//
// self.logger.log("### BEFORE COLLISION ###");
// self.logger.log(&*format!("{:?}", ball.obj));
// self.logger.log(&*format!("{:?}", other));
// collision_handler.handle(&mut ball.obj, other);
// self.logger.log("### AFTER COLLISION ###");
// self.logger.log(&*format!("{:?}", ball.obj));
// self.logger.log(&*format!("{:?}", other));
// self.logger.log("### DONE ###");
// }
}
fn get_collisions(&self) -> Box<dyn CollisionRegistry> {

View File

@@ -1,14 +1,18 @@
pub mod pong_collisions {
use std::cell::{RefCell, RefMut};
use std::ops::Add;
use std::rc::Rc;
use crate::game_object::game_object::GameObject;
use crate::geom::geom::Vector;
use crate::geom::shape::ShapeType;
pub fn handle_player_ball_collision(
ball: &mut Box<dyn GameObject>,
player: &mut Box<dyn GameObject>,
ball: Rc<RefCell<Box<dyn GameObject>>>,
player: Rc<RefCell<Box<dyn GameObject>>>,
) {
// reflect
let mut ball = RefCell::borrow_mut(&ball);
let player = player.borrow();
ball.vel_mut().reflect(&player.orientation());
// use vel of player obj
if *player.vel() != Vector::zero() {
@@ -24,16 +28,20 @@ pub mod pong_collisions {
}
pub fn handle_ball_bounds_collision(
ball: &mut Box<dyn GameObject>,
bound: &mut Box<dyn GameObject>,
ball: Rc<RefCell<Box<dyn GameObject>>>,
bound: Rc<RefCell<Box<dyn GameObject>>>,
) {
let mut ball = RefCell::borrow_mut(&ball);
let bound = RefCell::borrow(&bound);
ball.vel_mut().reflect(&bound.orientation());
}
pub fn handle_player_bound_collision(
player: &mut Box<dyn GameObject>,
bound: &mut Box<dyn GameObject>,
player: Rc<RefCell<Box<dyn GameObject>>>,
bound: Rc<RefCell<Box<dyn GameObject>>>,
) {
let mut player = RefCell::borrow_mut(&player);
let bound = RefCell::borrow(&bound);
let shape = player.shape().clone();
let player_orientation = player.orientation().clone();
let height = match shape {

View File

@@ -90,6 +90,10 @@ impl GameObject for MockGameObject {
todo!()
}
fn orientation_mut(&mut self) -> &mut Vector {
todo!()
}
fn update_pos(&mut self) {
todo!()
}

View File

@@ -1,3 +1,5 @@
use std::cell::RefCell;
use std::rc::Rc;
use rstest::rstest;
use pong::game_field::{Bound, Field};
use pong::game_object::game_object::{DefaultGameObject, GameObject};
@@ -47,29 +49,29 @@ use pong::utils::utils::NoopLogger;
get_bound(Bound::TOP)
)]
pub fn should_correctly_handle_player_bounds_collision(
#[case] mut player: Box<dyn GameObject>,
#[case] mut bounds: Box<dyn GameObject>,
#[case] mut player_expected: Box<dyn GameObject>,
#[case] mut bounds_expected: Box<dyn GameObject>
#[case] mut player: Rc<RefCell<Box<dyn GameObject>>>,
#[case] mut bounds: Rc<RefCell<Box<dyn GameObject>>>,
#[case] mut player_expected: Rc<RefCell<Box<dyn GameObject>>>,
#[case] mut bounds_expected: Rc<RefCell<Box<dyn GameObject>>>
) {
handle_player_bound_collision(&mut player, &mut bounds);
assert_eq!(player_expected.pos(), player.pos());
assert_eq!(bounds_expected.pos(), bounds.pos());
handle_player_bound_collision(player.clone(), bounds.clone());
assert_eq!(player_expected.borrow().pos(), player.borrow().pos());
assert_eq!(bounds_expected.borrow().pos(), bounds.borrow().pos());
}
fn create_player(id: u16, x: u16, y: u16, orientation: Vector) -> Box<dyn GameObject> {
fn create_player(id: u16, x: u16, y: u16, orientation: Vector) -> Rc<RefCell<Box<dyn GameObject>>> {
let field = Field::new(Box::new(NoopLogger{}));
let mut player = DefaultGameObject::player(id, x, y, &field);
let player_orientation = player.orientation_mut();
player_orientation.x = orientation.x;
player_orientation.y = orientation.y;
player
Rc::new(RefCell::new(player))
}
fn get_bound(bound: Bound) -> Box<dyn GameObject> {
fn get_bound(bound: Bound) -> Rc<RefCell<Box<dyn GameObject>>> {
let field = Field::new(Box::new(NoopLogger{}));
let bounds = DefaultGameObject::bounds(field.width, field.height);
return bounds.into_iter().find(|b| {
return Rc::new(RefCell::new(bounds.into_iter().find(|b| {
b.0 == bound
}).unwrap().inner();
}).unwrap().inner()));
}

View File

@@ -1,5 +1,6 @@
mod utils;
use std::cell::RefCell;
use pong::collision::collision::{Collision, CollisionDetector};
use pong::game_field::{Field, Input, InputType};
use pong::game_object::game_object::GameObject;
@@ -9,6 +10,7 @@ use pong::utils::utils::Logger;
use serde::{Deserialize, Serialize};
use serde_json::json;
use std::cmp::{max, min};
use std::rc::Rc;
use wasm_bindgen::prelude::*;
extern crate serde_json;
@@ -39,7 +41,9 @@ pub struct GameObjectDTO {
}
impl GameObjectDTO {
pub fn from(obj: &Box<dyn GameObject>) -> GameObjectDTO {
pub fn from(obj: &Rc<RefCell<Box<dyn GameObject>>>) -> GameObjectDTO {
let obj = RefCell::borrow(obj);
let pos = obj.pos();
let shape = obj.shape();
return GameObjectDTO {
@@ -123,9 +127,8 @@ impl FieldWrapper {
pub fn objects(&self) -> *const GameObjectDTO {
let mut objs = self
.field
.objs
.borrow()
.iter()
.objs()
.into_iter()
.map(|o| GameObjectDTO::from(o))
.collect::<Vec<GameObjectDTO>>();
objs.as_ptr()