refactoring

This commit is contained in:
Thilo Behnke
2022-04-18 22:42:49 +02:00
parent 52ed27e16f
commit deb0eb9af4
3 changed files with 206 additions and 197 deletions

56
src/game_object.rs Normal file
View File

@@ -0,0 +1,56 @@
use crate::{BoundingBox, Vector};
#[derive(Clone, Debug, PartialEq)]
pub enum Shape {
Rect = 0,
Circle = 1,
}
#[derive(Clone, Debug, PartialEq)]
pub struct GameObject {
pub id: u16,
pub x: u16,
pub y: u16,
pub shape: Shape,
pub shape_params: Vec<u16>,
pub vel: Vector,
pub is_static: bool
}
impl GameObject {
pub fn update_pos(&mut self, field_width: u16, field_height: u16) {
let updated_x = self.x.wrapping_add(self.vel.x as u16);
let updated_y = self.y.wrapping_add(self.vel.y as u16);
let updated_bounding_box = self.bounding_box_from(updated_x, updated_y);
if updated_bounding_box.points().iter().any(|p| p.x < 0 || p.x > field_width as i16 || p.y < 0 || p.y > field_height as i16) {
return;
}
self.x = updated_x;
self.y = updated_y;
}
pub fn set_vel_x(&mut self, x: i32) {
self.vel.x = x
}
pub fn set_vel_y(&mut self, y: i32) {
self.vel.y = y
}
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])
},
Shape::Circle => {
BoundingBox::create(x, y, self.shape_params[0] * 2, self.shape_params[0] * 2)
}
}
}
}

77
src/geom.rs Normal file
View File

@@ -0,0 +1,77 @@
pub mod geom {
#[derive(Debug, Clone, PartialEq)]
pub struct Vector {
pub x: i32,
pub y: i32
}
impl Vector {
pub fn zero() -> Vector {
Vector {x: 0, y: 0}
}
pub fn unit() -> Vector {
Vector {x: 1, y: 1}
}
pub fn normalize(&mut self) {
let length = self.len();
self.x /= length;
self.y /= length;
}
pub fn invert(&mut self) {
self.x = self.x * -1;
self.y = self.y * -1;
}
pub fn len(&self) -> i32 {
let distance = self.x.pow(2) + self.y.pow(2);
return (distance as f32).sqrt() as i32;
}
}
pub struct BoundingBox {
top_left: Point,
top_right: Point,
bottom_left: Point,
bottom_right: Point
}
impl BoundingBox {
pub fn create(center_x: u16, center_y: u16, width: u16, height: u16) -> BoundingBox {
let top_left = Point {x: center_x as i16 - (width / 2) as i16, y: center_y as i16 + (height / 2) as i16};
let top_right = Point {x: center_x as i16 + (width / 2) as i16, y: center_y as i16 + (height / 2) as i16};
let bottom_left = Point {x: center_x as i16 - (width / 2) as i16, y: center_y as i16 - (height / 2) as i16};
let bottom_right = Point {x: center_x as i16 + (width / 2) as i16, y: center_y as i16 - (height / 2) as i16};
BoundingBox {
top_left, top_right, bottom_left, bottom_right
}
}
pub fn points(&self) -> Vec<&Point> {
return vec![
&self.top_left, &self.top_right, &self.bottom_left, &self.bottom_right
]
}
pub fn overlaps(&self, other: &BoundingBox) -> bool {
return other.points().iter().any(|p| self.is_point_within(p))
}
pub fn is_point_within(&self, point: &Point) -> bool {
return point.x >= self.top_left.x && point.y <= self.top_left.y && point.y >= self.bottom_left.y
}
}
pub struct Point {
pub x: i16,
pub y: i16
}
impl Point {
pub fn create(x: i16, y: i16) -> Point {
Point { x, y }
}
}
}

View File

@@ -1,10 +1,14 @@
mod utils;
mod geom;
mod game_object;
use std::borrow::BorrowMut;
use std::cmp::{max, min};
use serde::{Deserialize, Serialize};
use serde_json::json;
use wasm_bindgen::prelude::*;
use crate::game_object::{GameObject, Shape};
use crate::geom::geom::{BoundingBox, Vector};
extern crate serde_json;
extern crate web_sys;
@@ -22,142 +26,6 @@ macro_rules! log {
#[global_allocator]
static ALLOC: wee_alloc::WeeAlloc = wee_alloc::WeeAlloc::INIT;
#[wasm_bindgen]
pub struct Field {
pub width: u16,
pub height: u16,
players: Vec<Player>,
balls: Vec<Ball>,
}
#[derive(Debug, Clone, PartialEq)]
pub struct Vector {
pub x: i32,
pub y: i32
}
impl Vector {
pub fn zero() -> Vector {
Vector {x: 0, y: 0}
}
pub fn normalize(&mut self) {
let length = self.len();
self.x /= length;
self.y /= length;
}
pub fn invert(&mut self) {
self.x = self.x * -1;
self.y = self.y * -1;
}
pub fn len(&self) -> i32 {
let distance = self.x.pow(2) + self.y.pow(2);
return (distance as f32).sqrt() as i32;
}
}
#[wasm_bindgen]
#[repr(u8)]
#[derive(Clone, Debug, PartialEq)]
pub enum Shape {
Rect = 0,
Circle = 1,
}
#[derive(Clone, Debug, PartialEq)]
pub struct GameObject {
pub id: u16,
pub x: u16,
pub y: u16,
pub shape: Shape,
pub shape_params: Vec<u16>,
pub vel: Vector,
pub is_static: bool
}
impl GameObject {
pub fn update_pos(&mut self, field_width: u16, field_height: u16) {
let updated_x = self.x.wrapping_add(self.vel.x as u16);
let updated_y = self.y.wrapping_add(self.vel.y as u16);
let updated_bounding_box = self.bounding_box_from(updated_x, updated_y);
if updated_bounding_box.points().iter().any(|p| p.x < 0 || p.x > field_width as i16 || p.y < 0 || p.y > field_height as i16) {
return;
}
self.x = updated_x;
self.y = updated_y;
}
pub fn set_vel_x(&mut self, x: i32) {
self.vel.x = x
}
pub fn set_vel_y(&mut self, y: i32) {
self.vel.y = y
}
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])
},
Shape::Circle => {
BoundingBox::create(x, y, self.shape_params[0] * 2, self.shape_params[0] * 2)
}
}
}
}
pub struct BoundingBox {
top_left: Point,
top_right: Point,
bottom_left: Point,
bottom_right: Point
}
impl BoundingBox {
pub fn create(center_x: u16, center_y: u16, width: u16, height: u16) -> BoundingBox {
let top_left = Point {x: center_x as i16 - (width / 2) as i16, y: center_y as i16 + (height / 2) as i16};
let top_right = Point {x: center_x as i16 + (width / 2) as i16, y: center_y as i16 + (height / 2) as i16};
let bottom_left = Point {x: center_x as i16 - (width / 2) as i16, y: center_y as i16 - (height / 2) as i16};
let bottom_right = Point {x: center_x as i16 + (width / 2) as i16, y: center_y as i16 - (height / 2) as i16};
BoundingBox {
top_left, top_right, bottom_left, bottom_right
}
}
pub fn points(&self) -> Vec<&Point> {
return vec![
&self.top_left, &self.top_right, &self.bottom_left, &self.bottom_right
]
}
pub fn overlaps(&self, other: &BoundingBox) -> bool {
return other.points().iter().any(|p| self.is_point_within(p))
}
pub fn is_point_within(&self, point: &Point) -> bool {
return point.x >= self.top_left.x && point.y <= self.top_left.y && point.y >= self.bottom_left.y
}
}
pub struct Point {
x: i16,
y: i16
}
impl Point {
pub fn create(x: i16, y: i16) -> Point {
Point { x, y }
}
}
#[wasm_bindgen]
#[repr(packed)]
#[derive(Clone, Copy, Debug, PartialEq, Eq, Serialize)]
@@ -183,48 +51,6 @@ impl GameObjectDTO {
}
}
#[derive(Clone, Debug, PartialEq)]
pub struct Player {
pub obj: GameObject,
}
impl Player {
pub fn new(id: u16, x: u16, y: u16, field: &Field) -> Player {
Player {
obj: GameObject {
id,
x,
y,
shape: Shape::Rect,
shape_params: vec![field.width / 25, field.height / 5],
vel: Vector::zero(),
is_static: true
},
}
}
}
#[derive(Clone, Debug, PartialEq)]
pub struct Ball {
pub obj: GameObject,
}
impl Ball {
pub fn new(id: u16, x: u16, y: u16, field: &Field) -> Ball {
Ball {
obj: GameObject {
id,
x,
y,
shape: Shape::Circle,
shape_params: vec![field.width / 80],
vel: Vector::zero(),
is_static: false
},
}
}
}
#[wasm_bindgen]
#[derive(Clone, Copy, Debug, PartialEq, Eq, Serialize, Deserialize)]
pub enum InputType {
@@ -239,6 +65,14 @@ pub struct Input {
pub obj_id: u16,
}
#[wasm_bindgen]
pub struct Field {
pub width: u16,
pub height: u16,
players: Vec<Player>,
balls: Vec<Ball>,
}
#[wasm_bindgen]
impl Field {
pub fn new() -> Field {
@@ -349,34 +183,34 @@ impl Field {
let players = &self.players;
let balls = &self.balls;
// TODO: Find obj by id.
if !collision.obj_a.is_static {
collision.obj_a.vel.invert();
}
if !collision.obj_b.is_static {
collision.obj_b.vel.invert();
}
// if !collision.obj_a.is_static {
// collision.obj_a.vel.invert();
// }
// if !collision.obj_b.is_static {
// collision.obj_b.vel.invert();
// }
}
}
fn detect_collisions(&mut self) -> Vec<Collision> {
let balls = self.balls();
let players = self.players();
// let balls = self.balls();
// let players = self.players();
//
let mut collisions = vec![];
for ball in balls.into_iter() {
let collision_opt = players.into_iter().find(|p| p.obj.bounding_box().overlaps(&ball.obj.bounding_box()));
if let None = collision_opt {
continue;
}
let player = collision_opt.unwrap();
// TODO: This can cause multiple mutable refs of the same player/ball object and therefore does not compile.
collisions.push(Collision {obj_a: player.obj.id, obj_b: ball.obj.id});
}
// for ball in balls.into_iter() {
// let collision_opt = players.into_iter().find(|p| p.obj.bounding_box().overlaps(&ball.obj.bounding_box()));
// if let None = collision_opt {
// continue;
// }
// let player = collision_opt.unwrap();
// // TODO: This can cause multiple mutable refs of the same player/ball object and therefore does not compile.
// collisions.push(Collision {obj_a: player.obj.id, obj_b: ball.obj.id});
// }
collisions
}
pub fn players(&self) -> Vec<&Player> {
self.players().iter().collect()
self.players.iter().collect()
}
pub fn balls(&self) -> Vec<&Ball> {
@@ -384,6 +218,48 @@ impl Field {
}
}
#[derive(Clone, Debug, PartialEq)]
pub struct Player {
pub obj: GameObject,
}
impl Player {
pub fn new(id: u16, x: u16, y: u16, field: &Field) -> Player {
Player {
obj: GameObject {
id,
x,
y,
shape: Shape::Rect,
shape_params: vec![field.width / 25, field.height / 5],
vel: Vector::zero(),
is_static: true
},
}
}
}
#[derive(Clone, Debug, PartialEq)]
pub struct Ball {
pub obj: GameObject,
}
impl Ball {
pub fn new(id: u16, x: u16, y: u16, field: &Field) -> Ball {
Ball {
obj: GameObject {
id,
x,
y,
shape: Shape::Circle,
shape_params: vec![field.width / 80],
vel: Vector::zero(),
is_static: false
},
}
}
}
#[derive(Debug)]
pub struct Collision {
obj_a: u16,