0.3.0-0-pre.3
This commit is contained in:
13
crates/apps/game-snake-poc-wasm/src/lib.rs
Normal file
13
crates/apps/game-snake-poc-wasm/src/lib.rs
Normal file
@@ -0,0 +1,13 @@
|
||||
// file: crates/apps/game-snake-poc-wasm/src/lib.rs
|
||||
// version: 1
|
||||
|
||||
//! WebAssembly adapter facade for the Snake POC.
|
||||
|
||||
#![forbid(unsafe_code)]
|
||||
#![deny(unreachable_pub)]
|
||||
#![warn(missing_docs)]
|
||||
|
||||
mod runtime;
|
||||
|
||||
/// Re-export of the Snake WebAssembly runtime adapter.
|
||||
pub use self::runtime::SnakeWasmGame;
|
||||
188
crates/apps/game-snake-poc-wasm/src/runtime.rs
Normal file
188
crates/apps/game-snake-poc-wasm/src/runtime.rs
Normal file
@@ -0,0 +1,188 @@
|
||||
// file: crates/apps/game-snake-poc-wasm/src/runtime.rs
|
||||
// version: 1
|
||||
|
||||
const FIXED_STEP_MILLIS: u64 = 16;
|
||||
|
||||
/// WebAssembly-owned Snake game state consumed by the direct browser host.
|
||||
#[wasm_bindgen::prelude::wasm_bindgen]
|
||||
pub struct SnakeWasmGame {
|
||||
pending_input: engine_v1_common::InputState,
|
||||
runner: engine_v1_common::FixedStepRunner,
|
||||
state: game_snake_poc::SnakeState,
|
||||
}
|
||||
|
||||
#[wasm_bindgen::prelude::wasm_bindgen]
|
||||
impl SnakeWasmGame {
|
||||
/// Creates a fresh Snake POC session using the shared gameplay crate.
|
||||
#[wasm_bindgen::prelude::wasm_bindgen(constructor)]
|
||||
pub fn new() -> Self {
|
||||
return Self {
|
||||
pending_input: engine_v1_common::InputState::none(),
|
||||
runner: engine_v1_common::FixedStepRunner::new(std::time::Duration::from_millis(FIXED_STEP_MILLIS)),
|
||||
state: game_snake_poc::SnakeState::new(),
|
||||
};
|
||||
}
|
||||
|
||||
/// Queues a logical left direction for the next deterministic update.
|
||||
pub fn left(&mut self) {
|
||||
self.queue_direction(engine_v1_common::GameAction::Left);
|
||||
return;
|
||||
}
|
||||
|
||||
/// Queues a logical right direction for the next deterministic update.
|
||||
pub fn right(&mut self) {
|
||||
self.queue_direction(engine_v1_common::GameAction::Right);
|
||||
return;
|
||||
}
|
||||
|
||||
/// Queues a logical upward direction for the next deterministic update.
|
||||
pub fn up(&mut self) {
|
||||
self.queue_direction(engine_v1_common::GameAction::Up);
|
||||
return;
|
||||
}
|
||||
|
||||
/// Queues a logical downward direction for the next deterministic update.
|
||||
pub fn down(&mut self) {
|
||||
self.queue_direction(engine_v1_common::GameAction::Down);
|
||||
return;
|
||||
}
|
||||
|
||||
/// Advances one deterministic update and consumes the queued direction.
|
||||
pub fn tick(&mut self) {
|
||||
let input = self.pending_input;
|
||||
self.pending_input = engine_v1_common::InputState::none();
|
||||
self.runner.tick(&mut self.state, input);
|
||||
return;
|
||||
}
|
||||
|
||||
/// Returns the current gameplay score.
|
||||
pub fn score(&self) -> u32 {
|
||||
return self.state.score().min(u32::MAX as u64) as u32;
|
||||
}
|
||||
|
||||
/// Returns the current Snake length.
|
||||
pub fn length(&self) -> u32 {
|
||||
return self.state.length().min(u32::MAX as usize) as u32;
|
||||
}
|
||||
|
||||
/// Returns the current scene background red channel.
|
||||
pub fn background_red(&self) -> u8 {
|
||||
return self.scene().background().red();
|
||||
}
|
||||
|
||||
/// Returns the current scene background green channel.
|
||||
pub fn background_green(&self) -> u8 {
|
||||
return self.scene().background().green();
|
||||
}
|
||||
|
||||
/// Returns the current scene background blue channel.
|
||||
pub fn background_blue(&self) -> u8 {
|
||||
return self.scene().background().blue();
|
||||
}
|
||||
|
||||
/// Returns the number of occupied rectangle slots in the current scene.
|
||||
pub fn rectangle_count(&self) -> u32 {
|
||||
let scene = self.scene();
|
||||
let mut count = 0_u32;
|
||||
for slot in scene.rectangles() {
|
||||
if slot.is_some() {
|
||||
count = count.saturating_add(1);
|
||||
}
|
||||
}
|
||||
return count;
|
||||
}
|
||||
|
||||
/// Returns one rectangle's normalized left coordinate or `-1.0` if absent.
|
||||
pub fn rectangle_x(&self, index: u32) -> f32 {
|
||||
return match self.rectangle(index) {
|
||||
Some(rectangle) => rectangle.rect().x(),
|
||||
None => -1.0,
|
||||
};
|
||||
}
|
||||
|
||||
/// Returns one rectangle's normalized top coordinate or `-1.0` if absent.
|
||||
pub fn rectangle_y(&self, index: u32) -> f32 {
|
||||
return match self.rectangle(index) {
|
||||
Some(rectangle) => rectangle.rect().y(),
|
||||
None => -1.0,
|
||||
};
|
||||
}
|
||||
|
||||
/// Returns one rectangle's normalized width or `0.0` if absent.
|
||||
pub fn rectangle_width(&self, index: u32) -> f32 {
|
||||
return match self.rectangle(index) {
|
||||
Some(rectangle) => rectangle.rect().width(),
|
||||
None => 0.0,
|
||||
};
|
||||
}
|
||||
|
||||
/// Returns one rectangle's normalized height or `0.0` if absent.
|
||||
pub fn rectangle_height(&self, index: u32) -> f32 {
|
||||
return match self.rectangle(index) {
|
||||
Some(rectangle) => rectangle.rect().height(),
|
||||
None => 0.0,
|
||||
};
|
||||
}
|
||||
|
||||
/// Returns one rectangle's red channel or zero if absent.
|
||||
pub fn rectangle_red(&self, index: u32) -> u8 {
|
||||
return match self.rectangle(index) {
|
||||
Some(rectangle) => rectangle.color().red(),
|
||||
None => 0,
|
||||
};
|
||||
}
|
||||
|
||||
/// Returns one rectangle's green channel or zero if absent.
|
||||
pub fn rectangle_green(&self, index: u32) -> u8 {
|
||||
return match self.rectangle(index) {
|
||||
Some(rectangle) => rectangle.color().green(),
|
||||
None => 0,
|
||||
};
|
||||
}
|
||||
|
||||
/// Returns one rectangle's blue channel or zero if absent.
|
||||
pub fn rectangle_blue(&self, index: u32) -> u8 {
|
||||
return match self.rectangle(index) {
|
||||
Some(rectangle) => rectangle.color().blue(),
|
||||
None => 0,
|
||||
};
|
||||
}
|
||||
}
|
||||
|
||||
impl Default for SnakeWasmGame {
|
||||
fn default() -> Self {
|
||||
return Self::new();
|
||||
}
|
||||
}
|
||||
|
||||
impl SnakeWasmGame {
|
||||
fn queue_direction(&mut self, action: engine_v1_common::GameAction) {
|
||||
self.pending_input = engine_v1_common::InputState::none().with_action(action, true);
|
||||
return;
|
||||
}
|
||||
|
||||
fn scene(&self) -> engine_v1_common::EngineScene {
|
||||
return engine_v1_common::EngineGame::scene(&self.state);
|
||||
}
|
||||
|
||||
fn rectangle(&self, requested_index: u32) -> Option<engine_v1_common::RenderRect> {
|
||||
let scene = self.scene();
|
||||
let mut occupied_index = 0_u32;
|
||||
for slot in scene.rectangles() {
|
||||
match slot {
|
||||
Some(rectangle) => {
|
||||
if occupied_index == requested_index {
|
||||
return Some(*rectangle);
|
||||
}
|
||||
occupied_index = occupied_index.saturating_add(1);
|
||||
},
|
||||
None => {},
|
||||
}
|
||||
}
|
||||
return None;
|
||||
}
|
||||
}
|
||||
|
||||
#[cfg(test)]
|
||||
#[path = "../unit_tests/runtime.rs"]
|
||||
mod tests;
|
||||
Reference in New Issue
Block a user