diff --git a/src/lib.rs b/src/lib.rs index d6bfb17..0854783 100644 --- a/src/lib.rs +++ b/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, } #[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::>(), + .map(|ball| GameObjectDTO::from(&ball.obj)) + .collect::>(), ); objs.append( &mut self .players .iter() - .map(|player| player.obj) - .collect::>(), + .map(|player| GameObjectDTO::from(&player.obj)) + .collect::>(), ); 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, balls: Vec) -> 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) { 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 } } - - diff --git a/tests/game_field_test.rs b/tests/game_field_test.rs index d2d5d41..21335bb 100644 --- a/tests/game_field_test.rs +++ b/tests/game_field_test.rs @@ -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); } }