mirror of
https://github.com/thilo-behnke/wasm-pong.git
synced 2026-07-11 02:29:25 +00:00
refactoring
This commit is contained in:
140
src/lib.rs
140
src/lib.rs
@@ -1,8 +1,8 @@
|
||||
mod utils;
|
||||
|
||||
use wasm_bindgen::prelude::*;
|
||||
use serde::{Serialize, Deserialize};
|
||||
use serde::{Deserialize, Serialize};
|
||||
use serde_json::json;
|
||||
use wasm_bindgen::prelude::*;
|
||||
|
||||
extern crate serde_json;
|
||||
extern crate web_sys;
|
||||
@@ -32,31 +32,82 @@ pub struct Field {
|
||||
#[repr(u8)]
|
||||
#[derive(Clone, Copy, Debug, PartialEq, Eq)]
|
||||
pub enum Shape {
|
||||
Rect = 0, Circle = 1
|
||||
Rect = 0,
|
||||
Circle = 1,
|
||||
}
|
||||
|
||||
#[derive(Debug, PartialEq, Eq)]
|
||||
pub struct GameObject {
|
||||
pub id: u16,
|
||||
pub x: u16,
|
||||
pub y: u16,
|
||||
pub shape: Shape,
|
||||
pub shape_params: Vec<u16>,
|
||||
}
|
||||
|
||||
#[wasm_bindgen]
|
||||
#[repr(packed)]
|
||||
#[derive(Clone, Copy, Debug, PartialEq, Eq, Serialize)]
|
||||
pub struct GameObject {
|
||||
pub struct GameObjectDTO {
|
||||
pub id: u16,
|
||||
pub x: u16,
|
||||
pub y: u16,
|
||||
pub shape: u16,
|
||||
}
|
||||
|
||||
#[wasm_bindgen]
|
||||
#[derive(Clone, Copy, Debug, PartialEq, Eq)]
|
||||
impl GameObjectDTO {
|
||||
pub fn from(obj: &GameObject) -> GameObjectDTO {
|
||||
return GameObjectDTO {
|
||||
id: obj.id,
|
||||
x: obj.x,
|
||||
y: obj.y,
|
||||
shape: match obj.shape_params[..] {
|
||||
[p1] => p1 << 8,
|
||||
[p1, p2] | [p1, p2, ..] => p1 << 8 | p2,
|
||||
_ => 0
|
||||
},
|
||||
};
|
||||
}
|
||||
}
|
||||
|
||||
#[derive(Debug, PartialEq, Eq)]
|
||||
pub struct Player {
|
||||
pub obj: GameObject,
|
||||
}
|
||||
|
||||
#[wasm_bindgen]
|
||||
#[derive(Clone, Copy, Debug, PartialEq, Eq)]
|
||||
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],
|
||||
},
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
#[derive(Debug, PartialEq, Eq)]
|
||||
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 / 50],
|
||||
},
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
#[wasm_bindgen]
|
||||
#[derive(Clone, Copy, Debug, PartialEq, Eq, Serialize, Deserialize)]
|
||||
pub enum InputType {
|
||||
@@ -77,23 +128,18 @@ impl Field {
|
||||
let width = 800;
|
||||
let height = 600;
|
||||
|
||||
Field {
|
||||
let mut field = Field {
|
||||
width,
|
||||
height,
|
||||
players: vec![
|
||||
Player {
|
||||
obj: GameObject { id: 0, x: 0 + width / 20, y: height / 2, shape: (width / 25) << 8 | (height / 5) },
|
||||
},
|
||||
Player {
|
||||
obj: GameObject { id: 1, x: width - width / 20, y: height / 2, shape: (width / 25) << 8 | (height / 5)},
|
||||
}
|
||||
],
|
||||
balls: vec![
|
||||
Ball {
|
||||
obj: GameObject {id: 2, x: width / 2, y: height / 2, shape: (width / 50) << 8}
|
||||
}
|
||||
],
|
||||
}
|
||||
players: vec![],
|
||||
balls: vec![]
|
||||
};
|
||||
|
||||
field.add_player(0, 0 + width / 20, height / 2);
|
||||
field.add_player(1, width - width / 20, height / 2);
|
||||
field.add_ball(2, width / 2, height / 2);
|
||||
|
||||
return field;
|
||||
}
|
||||
|
||||
pub fn tick(&mut self, inputs_js: &JsValue) {
|
||||
@@ -101,48 +147,68 @@ impl Field {
|
||||
self.tick_inner(inputs);
|
||||
}
|
||||
|
||||
pub fn objects(&self) -> *const GameObject {
|
||||
pub fn objects(&self) -> *const GameObjectDTO {
|
||||
let mut objs = vec![];
|
||||
objs.append(
|
||||
&mut self
|
||||
.balls
|
||||
.iter()
|
||||
.map(|ball| ball.obj)
|
||||
.collect::<Vec<GameObject>>(),
|
||||
.map(|ball| GameObjectDTO::from(&ball.obj))
|
||||
.collect::<Vec<GameObjectDTO>>(),
|
||||
);
|
||||
objs.append(
|
||||
&mut self
|
||||
.players
|
||||
.iter()
|
||||
.map(|player| player.obj)
|
||||
.collect::<Vec<GameObject>>(),
|
||||
.map(|player| GameObjectDTO::from(&player.obj))
|
||||
.collect::<Vec<GameObjectDTO>>(),
|
||||
);
|
||||
objs.as_ptr()
|
||||
}
|
||||
|
||||
pub fn get_state(&self) -> String {
|
||||
let json = json!(GameObject {shape: 0, x: 10, y: 10, id: 1});
|
||||
let json = json!(GameObjectDTO {
|
||||
shape: 0,
|
||||
x: 10,
|
||||
y: 10,
|
||||
id: 1
|
||||
});
|
||||
serde_json::to_string(&json).unwrap()
|
||||
}
|
||||
}
|
||||
|
||||
impl Field {
|
||||
pub fn mock(width: u16, height: u16, players: Vec<Player>, balls: Vec<Ball>) -> Field {
|
||||
pub fn mock(width: u16, height: u16) -> Field {
|
||||
Field {
|
||||
width, height, players, balls
|
||||
width,
|
||||
height,
|
||||
players: vec![],
|
||||
balls: vec![]
|
||||
}
|
||||
}
|
||||
|
||||
pub fn add_player(&mut self, id: u16, x: u16, y: u16) {
|
||||
self.players.push(Player::new(id, x, y, &self));
|
||||
}
|
||||
|
||||
pub fn add_ball(&mut self, id: u16, x: u16, y: u16) {
|
||||
self.balls.push(Ball::new(id, x, y, &self));
|
||||
}
|
||||
|
||||
pub fn tick_inner(&mut self, inputs: Vec<Input>) {
|
||||
for input in inputs.iter() {
|
||||
let obj_opt = self.players.iter_mut().find(|p| p.obj.id == input.obj_id);
|
||||
if let None = obj_opt {
|
||||
log!("Could not find player with id {} with players: {:?}", input.obj_id, self.players);
|
||||
log!(
|
||||
"Could not find player with id {} with players: {:?}",
|
||||
input.obj_id,
|
||||
self.players
|
||||
);
|
||||
continue;
|
||||
}
|
||||
let player = obj_opt.unwrap();
|
||||
let mut player_obj = &mut player.obj;
|
||||
let half_box = (player_obj.shape & 255) / 2;
|
||||
let half_box = player_obj.shape_params[1] / 2;
|
||||
match input.input {
|
||||
InputType::UP => {
|
||||
let shape_vert_bound = player_obj.y + half_box;
|
||||
@@ -152,16 +218,16 @@ impl Field {
|
||||
} else {
|
||||
player_obj.y = player_obj.y + 5
|
||||
}
|
||||
},
|
||||
}
|
||||
InputType::DOWN => {
|
||||
let shape_vert_bound = player_obj.y - half_box;
|
||||
let shape_vert_bound = player_obj.y.checked_sub(half_box).map_or(0, |val| val);
|
||||
let next_iter = shape_vert_bound.checked_sub(5);
|
||||
if let Some(res) = next_iter {
|
||||
player_obj.y = res + half_box;
|
||||
} else {
|
||||
player_obj.y = half_box;
|
||||
}
|
||||
},
|
||||
}
|
||||
};
|
||||
}
|
||||
}
|
||||
@@ -170,5 +236,3 @@ impl Field {
|
||||
&self.players
|
||||
}
|
||||
}
|
||||
|
||||
|
||||
|
||||
@@ -1,4 +1,3 @@
|
||||
|
||||
#[cfg(test)]
|
||||
mod game_field_tests {
|
||||
use rust_wasm::{Field, GameObject, Input, InputType, Player};
|
||||
@@ -6,13 +5,12 @@ mod game_field_tests {
|
||||
#[test]
|
||||
fn player_input_update_pos__up() {
|
||||
let height = 1000;
|
||||
let players = vec![
|
||||
Player {obj: GameObject {id: 1, x: 10, y: height / 2, shape: 10 << 8 | 5}}
|
||||
];
|
||||
let mut field = Field::mock(
|
||||
1000, 1000, players, vec![]
|
||||
);
|
||||
let inputs = vec![Input {input: InputType::UP, obj_id: 1}];
|
||||
let mut field = Field::mock(1000, height);
|
||||
field.add_player(1, 10, height / 2);
|
||||
let inputs = vec![Input {
|
||||
input: InputType::UP,
|
||||
obj_id: 1,
|
||||
}];
|
||||
field.tick_inner(inputs);
|
||||
let player = field.players().first().unwrap();
|
||||
assert_eq!(player.obj.y, height / 2 + 5);
|
||||
@@ -21,13 +19,12 @@ mod game_field_tests {
|
||||
#[test]
|
||||
fn player_input_update_pos__down() {
|
||||
let height = 1000;
|
||||
let players = vec![
|
||||
Player {obj: GameObject {id: 1, x: 10, y: height / 2, shape: 10 << 8 | 5}}
|
||||
];
|
||||
let mut field = Field::mock(
|
||||
1000, 1000, players, vec![]
|
||||
);
|
||||
let inputs = vec![Input {input: InputType::DOWN, obj_id: 1}];
|
||||
let mut field = Field::mock(1000, height);
|
||||
field.add_player(1, 10, height / 2);
|
||||
let inputs = vec![Input {
|
||||
input: InputType::DOWN,
|
||||
obj_id: 1,
|
||||
}];
|
||||
field.tick_inner(inputs);
|
||||
let player = field.players().first().unwrap();
|
||||
assert_eq!(player.obj.y, height / 2 - 5);
|
||||
@@ -36,30 +33,28 @@ mod game_field_tests {
|
||||
#[test]
|
||||
fn player_input_update_out_of_bounds__up() {
|
||||
let height = 1000;
|
||||
let players = vec![
|
||||
Player {obj: GameObject {id: 1, x: 10, y: height - 6, shape: 10 << 8 | 5}}
|
||||
];
|
||||
let mut field = Field::mock(
|
||||
1000, 1000, players, vec![]
|
||||
);
|
||||
let inputs = vec![Input {input: InputType::UP, obj_id: 1}];
|
||||
let mut field = Field::mock(1000, height);
|
||||
field.add_player(1, 10, height - 6);
|
||||
let inputs = vec![Input {
|
||||
input: InputType::UP,
|
||||
obj_id: 1,
|
||||
}];
|
||||
field.tick_inner(inputs);
|
||||
let player = field.players().first().unwrap();
|
||||
assert_eq!(player.obj.y, 998);
|
||||
assert_eq!(player.obj.y, height - field.players().first().unwrap().obj.shape_params[1] / 2);
|
||||
}
|
||||
|
||||
#[test]
|
||||
fn player_input_update_out_of_bounds__down() {
|
||||
let height = 1000;
|
||||
let players = vec![
|
||||
Player {obj: GameObject {id: 1, x: 10, y: 0 + 6, shape: 10 << 8 | 5}}
|
||||
];
|
||||
let mut field = Field::mock(
|
||||
1000, 1000, players, vec![]
|
||||
);
|
||||
let inputs = vec![Input {input: InputType::DOWN, obj_id: 1}];
|
||||
let mut field = Field::mock(1000, height);
|
||||
field.add_player(1, 10, 6);
|
||||
let inputs = vec![Input {
|
||||
input: InputType::DOWN,
|
||||
obj_id: 1,
|
||||
}];
|
||||
field.tick_inner(inputs);
|
||||
let player = field.players().first().unwrap();
|
||||
assert_eq!(player.obj.y, 2);
|
||||
assert_eq!(player.obj.y, field.players().first().unwrap().obj.shape_params[1] / 2);
|
||||
}
|
||||
}
|
||||
|
||||
Reference in New Issue
Block a user