migrate game obj pos to float

This commit is contained in:
Thilo Behnke
2022-04-22 23:47:28 +02:00
parent 91a48cf132
commit 7a4ef75c46
8 changed files with 89 additions and 100 deletions
+8 -14
View File
@@ -90,10 +90,10 @@ impl Field {
}
for player in self.players.iter_mut() {
player.obj.update_pos(self.width, self.height)
player.obj.update_pos()
}
for ball in self.balls.iter_mut() {
ball.obj.update_pos(self.width, self.height)
ball.obj.update_pos()
}
let mut objs: Vec<GameObject> = vec![];
@@ -155,8 +155,7 @@ impl Player {
Player {
obj: GameObject {
id,
x,
y,
pos: Vector {x: x as f64, y: y as f64},
shape: Shape::Rect,
shape_params: vec![field.width / 25, field.height / 5],
vel: Vector::zero(),
@@ -176,8 +175,7 @@ impl Ball {
Ball {
obj: GameObject {
id,
x,
y,
pos: Vector {x: x as f64, y: y as f64},
shape: Shape::Circle,
shape_params: vec![field.width / 80],
vel: Vector::zero(),
@@ -198,8 +196,7 @@ impl Bounds {
objs: vec![
GameObject {
id: 90,
x: width / 2,
y: 0,
pos: Vector {x: (width / 2) as f64, y: 0 as f64},
shape: Shape::Rect,
shape_params: vec![width, 2],
is_static: true,
@@ -208,8 +205,7 @@ impl Bounds {
// bottom
GameObject {
id: 91,
x: width / 2,
y: height,
pos: Vector {x: (width / 2) as f64, y: height as f64},
shape: Shape::Rect,
shape_params: vec![width, 2],
is_static: true,
@@ -218,8 +214,7 @@ impl Bounds {
// left
GameObject {
id: 92,
x: 0,
y: height / 2,
pos: Vector {x: 0 as f64, y: (height / 2) as f64},
shape: Shape::Rect,
shape_params: vec![2, height],
is_static: true,
@@ -228,8 +223,7 @@ impl Bounds {
// right
GameObject {
id: 93,
x: width,
y: height / 2,
pos: Vector {x: width as f64, y: (height / 2) as f64},
shape: Shape::Rect,
shape_params: vec![2, height],
is_static: true,
+6 -22
View File
@@ -10,8 +10,7 @@ pub mod game_object {
#[derive(Clone, Debug, PartialEq)]
pub struct GameObject {
pub id: u16,
pub x: u16,
pub y: u16,
pub pos: Vector,
pub shape: Shape,
pub shape_params: Vec<u16>,
pub vel: Vector,
@@ -19,20 +18,9 @@ pub mod game_object {
}
impl GameObject {
// TODO: Migrate pos to f64
pub fn update_pos(&mut self, field_width: u16, field_height: u16) {
let abs_x = self.vel.x.abs() as u16;
let updated_x = match self.vel.x {
n if n >= 0. => self.x.wrapping_add(abs_x),
_ => self.x.wrapping_sub(abs_x)
};
let abs_y = self.vel.y.abs() as u16;
let updated_y = match self.vel.y {
n if n >= 0. => self.y.wrapping_add(abs_y),
_ => self.y.wrapping_sub(abs_y)
};
self.x = updated_x;
self.y = updated_y;
pub fn update_pos(&mut self) {
self.pos.add(&self.vel);
}
pub fn set_vel_x(&mut self, x: f64) {
@@ -44,16 +32,12 @@ pub mod game_object {
}
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])
BoundingBox::create(&self.pos, self.shape_params[0], self.shape_params[1])
}
Shape::Circle => {
BoundingBox::create(x, y, self.shape_params[0] * 2, self.shape_params[0] * 2)
BoundingBox::create(&self.pos, self.shape_params[0] * 2, self.shape_params[0] * 2)
}
}
}
+39 -31
View File
@@ -1,5 +1,5 @@
pub mod geom {
#[derive(Debug, Clone, PartialEq)]
#[derive(Debug, Clone)]
pub struct Vector {
pub x: f64,
pub y: f64,
@@ -54,6 +54,11 @@ pub mod geom {
self.y += other.y;
}
pub fn sub(&mut self, other: &Vector) {
self.x -= other.x;
self.y -= other.y;
}
pub fn invert(&mut self) {
self.x = self.x * -1.;
self.y = self.y * -1.;
@@ -81,30 +86,44 @@ 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()
}
}
pub struct BoundingBox {
top_left: Point,
top_right: Point,
bottom_left: Point,
bottom_right: Point,
top_left: Vector,
top_right: Vector,
bottom_left: Vector,
bottom_right: Vector,
}
impl BoundingBox {
pub fn create(center_x: u16, center_y: u16, width: u16, height: u16) -> BoundingBox {
let top_left = Point {
x: center_x as i32 - (width / 2) as i32,
y: center_y as i32 + (height / 2) as i32,
pub fn create_from_coords(x: f64, y: f64, width: u16, height: u16) -> BoundingBox {
let center = Vector::new(x, y);
return BoundingBox::create(&center, width, height)
}
pub fn create(center: &Vector, width: u16, height: u16) -> 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.),
};
let top_right = Point {
x: center_x as i32 + (width / 2) as i32,
y: center_y as i32 + (height / 2) as i32,
let top_right = Vector {
x: center_x + (width as f64 / 2.),
y: center_y + (height as f64 / 2.),
};
let bottom_left = Point {
x: center_x as i32 - (width / 2) as i32,
y: center_y as i32 - (height / 2) as i32,
let bottom_left = Vector {
x: center_x - (width as f64 / 2.),
y: center_y - (height as f64 / 2.),
};
let bottom_right = Point {
x: center_x as i32 + (width / 2) as i32,
y: center_y as i32 - (height / 2) as i32,
let bottom_right = Vector {
x: center_x + (width as f64 / 2.),
y: center_y - (height as f64 / 2.),
};
BoundingBox {
top_left,
@@ -114,7 +133,7 @@ pub mod geom {
}
}
pub fn points(&self) -> Vec<&Point> {
pub fn points(&self) -> Vec<&Vector> {
return vec![
&self.top_left,
&self.top_right,
@@ -127,22 +146,11 @@ pub mod geom {
return self.points().iter().any(|p| other.is_point_within(p)) || other.points().iter().any(|p| self.is_point_within(p));
}
pub fn is_point_within(&self, point: &Point) -> bool {
pub fn is_point_within(&self, point: &Vector) -> bool {
return point.x >= self.top_left.x
&& point.x <= self.top_right.x
&& point.y <= self.top_left.y
&& point.y >= self.bottom_left.y;
}
}
pub struct Point {
pub x: i32,
pub y: i32,
}
impl Point {
pub fn create(x: i32, y: i32) -> Point {
Point { x, y }
}
}
}
+16 -11
View File
@@ -1,13 +1,13 @@
use rstest::rstest;
use pong::geom::geom::{BoundingBox, Point};
use pong::geom::geom::{BoundingBox, Vector};
#[rstest]
#[case(BoundingBox::create(10, 10, 5, 5), Point::create(10, 10), true)]
#[case(BoundingBox::create(10, 10, 5, 5), Point::create(8, 8), true)]
#[case(BoundingBox::create(10, 10, 5, 5), Point::create(20, 20), false)]
#[case(BoundingBox::create_from_coords(10., 10., 5, 5), Vector::new(10., 10.), true)]
#[case(BoundingBox::create_from_coords(10., 10., 5, 5), Vector::new(8., 8.), true)]
#[case(BoundingBox::create_from_coords(10., 10., 5, 5), Vector::new(20., 20.), false)]
pub fn should_correctly_determine_if_point_is_within_box(
#[case] bounding_box: BoundingBox,
#[case] point: Point,
#[case] point: Vector,
#[case] expected: bool,
) {
let res = bounding_box.is_point_within(&point);
@@ -16,20 +16,25 @@ pub fn should_correctly_determine_if_point_is_within_box(
#[rstest]
#[case(
BoundingBox::create(10, 10, 5, 5),
BoundingBox::create(10, 10, 5, 5),
BoundingBox::create_from_coords(10., 10., 5, 5),
BoundingBox::create_from_coords(10., 10., 5, 5),
true
)]
#[case(
BoundingBox::create(10, 10, 5, 5),
BoundingBox::create(8, 8, 5, 5),
BoundingBox::create_from_coords(10., 10., 5, 5),
BoundingBox::create_from_coords(8., 8., 5, 5),
true
)]
#[case(
BoundingBox::create(10, 10, 5, 5),
BoundingBox::create(5, 5, 5, 5),
BoundingBox::create_from_coords(10., 10., 5, 5),
BoundingBox::create_from_coords(4.9, 4.9, 5, 5),
false
)]
#[case(
BoundingBox::create_from_coords(10., 10., 5, 5),
BoundingBox::create_from_coords(5., 5., 5, 5),
true
)]
pub fn should_correctly_determine_if_overlap(
#[case] bounding_box_a: BoundingBox,
#[case] bounding_box_b: BoundingBox,
+8 -8
View File
@@ -7,29 +7,29 @@ use pong::geom::geom::{Vector};
#[case(vec![], vec![])]
#[case(
vec![
GameObject{id: 1, x: 50, y: 50, shape: Shape::Rect, shape_params: vec![20, 20], vel: Vector::zero(), is_static: false},
GameObject{id: 2, x: 50, y: 50, shape: Shape::Rect, shape_params: vec![20, 20], vel: Vector::zero(), is_static: false}
GameObject{id: 1, pos: Vector{x: 50., y: 50.}, shape: Shape::Rect, shape_params: vec![20, 20], vel: Vector::zero(), is_static: false},
GameObject{id: 2, pos: Vector{x: 50., y: 50.}, shape: Shape::Rect, shape_params: vec![20, 20], vel: Vector::zero(), is_static: false}
],
vec![Collision(1, 2)]
)]
#[case(
vec![
GameObject{id: 1, x: 60, y: 65, shape: Shape::Rect, shape_params: vec![20, 20], vel: Vector::zero(), is_static: false},
GameObject{id: 2, x: 50, y: 50, shape: Shape::Rect, shape_params: vec![20, 20], vel: Vector::zero(), is_static: false}
GameObject{id: 1, pos: Vector{x: 60., y: 65.}, shape: Shape::Rect, shape_params: vec![20, 20], vel: Vector::zero(), is_static: false},
GameObject{id: 2, pos: Vector{x: 50., y: 50.}, shape: Shape::Rect, shape_params: vec![20, 20], vel: Vector::zero(), is_static: false}
],
vec![Collision(1, 2)]
)]
#[case(
vec![
GameObject{id: 1, x: 50, y: 50, shape: Shape::Rect, shape_params: vec![20, 20], vel: Vector::zero(), is_static: false},
GameObject{id: 2, x: 80, y: 80, shape: Shape::Rect, shape_params: vec![20, 20], vel: Vector::zero(), is_static: false}
GameObject{id: 1, pos: Vector{x: 50., y: 50.}, shape: Shape::Rect, shape_params: vec![20, 20], vel: Vector::zero(), is_static: false},
GameObject{id: 2, pos: Vector{x: 80., y: 80.}, shape: Shape::Rect, shape_params: vec![20, 20], vel: Vector::zero(), is_static: false}
],
vec![]
)]
#[case(
vec![
GameObject{id: 1, x: 50, y: 50, shape: Shape::Rect, shape_params: vec![50, 50], vel: Vector::zero(), is_static: false},
GameObject{id: 2, x: 500, y: 50, shape: Shape::Rect, shape_params: vec![50, 50], vel: Vector::zero(), is_static: false}
GameObject{id: 1, pos: Vector{x: 50., y: 50.}, shape: Shape::Rect, shape_params: vec![50, 50], vel: Vector::zero(), is_static: false},
GameObject{id: 2, pos: Vector{x: 500., y: 50.}, shape: Shape::Rect, shape_params: vec![50, 50], vel: Vector::zero(), is_static: false}
],
vec![]
)]
+4 -4
View File
@@ -14,7 +14,7 @@ mod game_field_tests {
field.tick(inputs);
let players = field.players();
let player = players.first().unwrap();
assert_eq!(player.obj.y, height / 2 + 1);
assert_eq!(player.obj.pos.y, height as f64 / 2. + 1.);
}
#[test]
@@ -29,7 +29,7 @@ mod game_field_tests {
field.tick(inputs);
let players = field.players();
let player = players.first().unwrap();
assert_eq!(player.obj.y, height / 2 - 1);
assert_eq!(player.obj.pos.y, height as f64 / 2. - 1.);
}
#[test]
@@ -44,7 +44,7 @@ mod game_field_tests {
field.tick(inputs);
let players = field.players();
let player = players.first().unwrap();
assert_eq!(player.obj.y, height - height / 5 / 2);
assert_eq!(player.obj.pos.y, height as f64 - height as f64 / 5. / 2.);
}
#[test]
@@ -59,6 +59,6 @@ mod game_field_tests {
field.tick(inputs);
let players = field.players();
let player = players.first().unwrap();
assert_eq!(player.obj.y, height / 5 / 2);
assert_eq!(player.obj.pos.y, height as f64 / 5. / 2.);
}
}
+6 -8
View File
@@ -1,20 +1,18 @@
use rstest::rstest;
use pong::game_object::game_object::{GameObject, Shape};
use pong::geom::geom::{Point, Vector};
use pong::geom::geom::{Vector};
#[rstest]
#[case(Point::create(100, 100), Vector::new(-1., 1.), Point::create(99, 101))]
pub fn should_update_pos(#[case] start_pos: Point, #[case] vel: Vector, #[case] expected_pos: Point) {
#[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) {
let mut obj = GameObject {
id: 1,
x: start_pos.x as u16,
y: start_pos.y as u16,
pos: Vector::new(start_pos.x as f64, start_pos.y as f64),
vel,
shape: Shape::Rect,
shape_params: vec![],
is_static: false,
};
obj.update_pos(1000, 1000);
assert_eq!(obj.x, expected_pos.x as u16);
assert_eq!(obj.y, expected_pos.y as u16);
obj.update_pos();
assert_eq!(obj.pos, expected_pos);
}
+2 -2
View File
@@ -40,8 +40,8 @@ impl GameObjectDTO {
pub fn from(obj: &GameObject) -> GameObjectDTO {
return GameObjectDTO {
id: obj.id,
x: obj.x,
y: obj.y,
x: obj.pos.x as u16,
y: obj.pos.y as u16,
shape_param_1: match obj.shape_params[..] {
[p1, _] => p1,
[p1] => p1,