bugfix/avoid-player-crushing-ball-outside-of-field

This commit is contained in:
Thilo Behnke
2022-07-03 18:06:19 +02:00
parent bf0b2173b6
commit 2aca10a34a
5 changed files with 68 additions and 14 deletions

View File

@@ -242,6 +242,10 @@ pub mod handler {
handlers: CollisionHandlerRegistry,
}
pub struct FieldStats {
pub dimensions: (f64, f64)
}
impl CollisionHandler {
pub fn new(logger_factory: &Box<dyn LoggerFactory>) -> CollisionHandler {
let logger = logger_factory.get("collision_handler");
@@ -254,13 +258,14 @@ pub mod handler {
pub fn register(
&mut self,
mapping: (String, String),
callback: fn(&Rc<RefCell<Box<dyn GameObject>>>, &Rc<RefCell<Box<dyn GameObject>>>),
callback: fn(&FieldStats, &Rc<RefCell<Box<dyn GameObject>>>, &Rc<RefCell<Box<dyn GameObject>>>),
) {
self.handlers.add(mapping, callback)
}
pub fn handle(
&self,
stats: &FieldStats,
obj_a: &Rc<RefCell<Box<dyn GameObject>>>,
obj_b: &Rc<RefCell<Box<dyn GameObject>>>,
) -> bool {
@@ -268,7 +273,7 @@ pub mod handler {
RefCell::borrow(&obj_a).obj_type().to_string(),
RefCell::borrow(&obj_b).obj_type().to_string(),
);
let handler_res = self.handlers.call(&key, (&obj_a, &obj_b));
let handler_res = self.handlers.call(&key, (&stats, &obj_a, &obj_b));
if !handler_res {
self.logger
.log(&*format!("Found no matching collision handler: {:?}", key));
@@ -299,12 +304,12 @@ pub mod handler {
pub struct CollisionHandlerRegistry {
handlers: HashMap<
(String, String),
fn(&Rc<RefCell<Box<dyn GameObject>>>, &Rc<RefCell<Box<dyn GameObject>>>),
fn(&FieldStats, &Rc<RefCell<Box<dyn GameObject>>>, &Rc<RefCell<Box<dyn GameObject>>>),
>,
}
type CollisionCallback =
fn(&Rc<RefCell<Box<dyn GameObject>>>, &Rc<RefCell<Box<dyn GameObject>>>);
fn(&FieldStats, &Rc<RefCell<Box<dyn GameObject>>>, &Rc<RefCell<Box<dyn GameObject>>>);
impl CollisionHandlerRegistry {
pub fn new() -> CollisionHandlerRegistry {
@@ -327,18 +332,19 @@ pub mod handler {
&self,
mapping: &(String, String),
values: (
&FieldStats,
&Rc<RefCell<Box<dyn GameObject>>>,
&Rc<RefCell<Box<dyn GameObject>>>,
),
) -> bool {
let regular = self.handlers.get(&mapping);
if let Some(callback) = regular {
callback(values.0, values.1);
callback(values.0, values.1, values.2);
return true;
}
let inverse = self.handlers.get(&(mapping.clone().1, mapping.clone().0));
if let Some(callback) = inverse {
callback(values.1, values.0);
callback(values.0, values.2, values.1);
return true;
}
return false;
@@ -350,7 +356,7 @@ pub mod handler {
use rstest::rstest;
use std::cell::RefCell;
use std::rc::Rc;
use crate::collision::handler::CollisionHandler;
use crate::collision::handler::{CollisionHandler, FieldStats};
use crate::game_object::components::{DefaultGeomComp, DefaultPhysicsComp};
use crate::game_object::game_object::{DefaultGameObject, GameObject};
use crate::geom::shape::Shape;
@@ -392,14 +398,17 @@ pub mod handler {
) {
let logger = DefaultLoggerFactory::noop();
let mut handler = CollisionHandler::new(&logger);
handler.register((String::from("obj"), String::from("obj")), |_a, _b| {
let field_stats = FieldStats {
dimensions: (1000., 1000.)
};
handler.register((String::from("obj"), String::from("obj")), |_stats, _a, _b| {
let mut a_mut = RefCell::borrow_mut(_a);
let mut vel_inverted = a_mut.vel().clone();
vel_inverted.invert();
*a_mut.vel_mut() = vel_inverted;
});
let expected_vel_a = Vector::inverted(RefCell::borrow(&obj_a).vel());
let res = handler.handle(&obj_a, &obj_b);
let res = handler.handle(&field_stats, &obj_a, &obj_b);
assert_eq!(true, res);
assert_eq!(RefCell::borrow(&obj_a).pos(), RefCell::borrow(&obj_a).pos());
assert_eq!(RefCell::borrow(&obj_a).vel(), &expected_vel_a);

View File

@@ -6,7 +6,7 @@ use crate::collision::collision::{
CollisionRegistry, Collisions,
};
use crate::collision::detection::{CollisionDetector, CollisionGroup};
use crate::collision::handler::{CollisionHandler};
use crate::collision::handler::{CollisionHandler, FieldStats};
use crate::game_object::components::{DefaultGeomComp, DefaultPhysicsComp};
use crate::game_object::game_object::{DefaultGameObject, GameObject};
use crate::geom::shape::Shape;
@@ -193,7 +193,8 @@ impl Field {
.find(|o| RefCell::borrow(o).id() == collision.1)
.unwrap()
.clone();
collision_handler.handle(&obj_a, &obj_b);
let field_stats = FieldStats {dimensions: (self.width as f64, self.height as f64)};
collision_handler.handle(&field_stats, &obj_a, &obj_b);
}
{

View File

@@ -471,6 +471,22 @@ pub mod shape {
Circle(Shape, f64),
}
impl ShapeType {
pub fn dimensions(&self) -> Vector {
return Vector::new(self.width().clone(), self.height().clone());
}
pub fn width(&self) -> &f64 {
match self {
ShapeType::Rect(_, width, _) | ShapeType::Circle(_, width) => width,
}
}
pub fn height(&self) -> &f64 {
match self {
ShapeType::Rect(_, _, height) | ShapeType::Circle(_, height) => height,
}
}
}
#[derive(Clone, Debug, PartialEq)]
pub struct Shape {
center: Vector,

View File

@@ -6,14 +6,29 @@ pub mod pong_collisions {
use std::cmp::min;
use std::f64::consts::{FRAC_PI_2, FRAC_PI_4, PI};
use std::rc::Rc;
use crate::collision::handler::FieldStats;
use crate::utils::number_utils::is_in_range;
pub fn handle_player_ball_collision(
stats: &FieldStats,
ball: &Rc<RefCell<Box<dyn GameObject>>>,
player: &Rc<RefCell<Box<dyn GameObject>>>,
) {
let mut ball = RefCell::borrow_mut(&ball);
let player = player.borrow();
// player is crushing the ball out of bounds
let ball_pos = ball.pos().clone();
let ball_height = {
let ball_dimensions = ball.shape().dimensions();
ball_dimensions.y
};
if is_in_range(ball_pos.y, stats.dimensions.1 - ball_height / 2., stats.dimensions.1 + ball_height / 2.) || is_in_range(ball_pos.y, 0. - ball_height / 2., 0. + ball_height / 2.) {
let mut player = player.borrow_mut();
*player.vel_mut() = Vector::zero();
return;
}
let player = player.borrow();
// reflect
let ball_vel = ball.vel_mut();
let mut ball_vel_total = ball_vel.len();
@@ -48,10 +63,13 @@ pub mod pong_collisions {
}
pub fn handle_ball_bounds_collision(
_stats: &FieldStats,
ball: &Rc<RefCell<Box<dyn GameObject>>>,
bound: &Rc<RefCell<Box<dyn GameObject>>>,
) {
let mut ball = RefCell::borrow_mut(&ball);
let mut ball_dimensions = ball.shape().dimensions();
ball_dimensions.scalar_multiplication(0.5);
let bound = RefCell::borrow(&bound);
ball.vel_mut().reflect(&bound.orientation());
@@ -63,15 +81,17 @@ pub mod pong_collisions {
bound_pos.multiply(&bound_orientation);
let mut b_to_a = ball.pos().clone();
b_to_a.multiply(&bound_orientation);
b_to_a.sub(&bound_pos);
b_to_a.normalize();
b_to_a.scalar_multiplication(5.);
b_to_a.multiply(&ball_dimensions);
ball.pos_mut().add(&b_to_a);
ball.set_dirty(true);
}
pub fn handle_player_bound_collision(
_stats: &FieldStats,
player: &Rc<RefCell<Box<dyn GameObject>>>,
bound: &Rc<RefCell<Box<dyn GameObject>>>,
) {
@@ -98,6 +118,7 @@ pub mod pong_collisions {
use rstest::rstest;
use std::cell::RefCell;
use std::rc::Rc;
use crate::collision::handler::FieldStats;
use crate::game_field::{Bound, Field};
use crate::game_object::game_object::{DefaultGameObject, GameObject};
use crate::geom::vector::Vector;
@@ -144,7 +165,8 @@ pub mod pong_collisions {
#[case] player_expected: Rc<RefCell<Box<dyn GameObject>>>,
#[case] bounds_expected: Rc<RefCell<Box<dyn GameObject>>>,
) {
handle_player_bound_collision(&player, &bounds);
let stats = FieldStats {dimensions: (1000., 1000.)};
handle_player_bound_collision(&stats, &player, &bounds);
assert_eq!(player_expected.borrow().pos(), player.borrow().pos());
assert_eq!(bounds_expected.borrow().pos(), bounds.borrow().pos());
}

View File

@@ -45,3 +45,9 @@ pub mod utils {
fn log(&self, _msg: &str) {}
}
}
pub mod number_utils {
pub fn is_in_range(n: f64, from: f64, to: f64) -> bool {
return from <= n && n <= to;
}
}