0.1.0-0-pre.8
This commit is contained in:
@@ -1,5 +1,5 @@
|
||||
// file: crates/apps/game-android-entrypoint/src/lib.rs
|
||||
// version: 1
|
||||
// version: 2
|
||||
|
||||
#![warn(missing_docs)]
|
||||
#![deny(unreachable_pub)]
|
||||
@@ -19,6 +19,11 @@ extern "C" fn sdl_main(_argc: core::ffi::c_int, _argv: *mut *mut core::ffi::c_ch
|
||||
return run_selected_game();
|
||||
}
|
||||
|
||||
#[unsafe(export_name = "Java_com_sasedev_games_common_NativeBridge_nativeContractVersion")]
|
||||
extern "C" fn native_contract_version(_environment: *mut core::ffi::c_void, _class: *mut core::ffi::c_void) -> core::ffi::c_int {
|
||||
return 1;
|
||||
}
|
||||
|
||||
#[cfg(feature = "reflex")]
|
||||
fn run_selected_game() -> core::ffi::c_int {
|
||||
let runtime = engine_v1_sdl::SdlRuntime::new("Reflex POC", 405, 720, std::time::Duration::from_millis(16));
|
||||
|
||||
@@ -1,8 +1,13 @@
|
||||
// file: crates/apps/game-android-entrypoint/unit_tests/selection.rs
|
||||
// version: 1
|
||||
// version: 2
|
||||
|
||||
#[test]
|
||||
fn no_feature_entrypoint_has_failure_status() {
|
||||
#[cfg(not(any(feature = "reflex", feature = "snake")))]
|
||||
assert_eq!(crate::run_selected_game(), 2);
|
||||
}
|
||||
|
||||
#[test]
|
||||
fn native_bridge_contract_version_is_one() {
|
||||
assert_eq!(crate::native_contract_version(core::ptr::null_mut(), core::ptr::null_mut()), 1);
|
||||
}
|
||||
|
||||
@@ -1,8 +1,8 @@
|
||||
// file: crates/engines/engine-v1-common/src/input.rs
|
||||
// version: 2
|
||||
// version: 3
|
||||
|
||||
/// Platform-independent snapshot of logical input actions for one update.
|
||||
#[derive(Clone, Copy, Debug, Default, Eq, PartialEq)]
|
||||
#[derive(Clone, Copy, Debug, Default, PartialEq)]
|
||||
pub struct InputState {
|
||||
left: bool,
|
||||
right: bool,
|
||||
@@ -11,13 +11,23 @@ pub struct InputState {
|
||||
primary: bool,
|
||||
secondary: bool,
|
||||
pause: bool,
|
||||
pointer: crate::PointerState,
|
||||
}
|
||||
|
||||
impl InputState {
|
||||
/// Creates a snapshot with no active action.
|
||||
#[must_use]
|
||||
pub const fn none() -> Self {
|
||||
return Self { left: false, right: false, up: false, down: false, primary: false, secondary: false, pause: false };
|
||||
return Self {
|
||||
left: false,
|
||||
right: false,
|
||||
up: false,
|
||||
down: false,
|
||||
primary: false,
|
||||
secondary: false,
|
||||
pause: false,
|
||||
pointer: crate::PointerState::inactive(),
|
||||
};
|
||||
}
|
||||
|
||||
/// Returns a copy with the selected logical action set to the requested state.
|
||||
@@ -35,6 +45,13 @@ impl InputState {
|
||||
return self;
|
||||
}
|
||||
|
||||
/// Returns a copy carrying the selected normalized primary pointer state.
|
||||
#[must_use]
|
||||
pub const fn with_pointer(mut self, pointer: crate::PointerState) -> Self {
|
||||
self.pointer = pointer;
|
||||
return self;
|
||||
}
|
||||
|
||||
/// Reports whether the selected logical action is active.
|
||||
#[must_use]
|
||||
pub const fn is_active(self, action: crate::GameAction) -> bool {
|
||||
@@ -48,6 +65,12 @@ impl InputState {
|
||||
crate::GameAction::Pause => self.pause,
|
||||
};
|
||||
}
|
||||
|
||||
/// Returns the primary pointer snapshot.
|
||||
#[must_use]
|
||||
pub const fn pointer(self) -> crate::PointerState {
|
||||
return self.pointer;
|
||||
}
|
||||
}
|
||||
|
||||
#[cfg(test)]
|
||||
|
||||
@@ -1,5 +1,5 @@
|
||||
// file: crates/engines/engine-v1-common/src/lib.rs
|
||||
// version: 2
|
||||
// version: 3
|
||||
|
||||
#![warn(missing_docs)]
|
||||
#![deny(unreachable_pub)]
|
||||
@@ -11,6 +11,7 @@ mod action;
|
||||
mod frame;
|
||||
mod game_loop;
|
||||
mod input;
|
||||
mod pointer;
|
||||
|
||||
/// Re-export of the canonical logical input action used by engine V1 games.
|
||||
pub use self::action::GameAction;
|
||||
@@ -22,3 +23,5 @@ pub use self::game_loop::EngineGame;
|
||||
pub use self::game_loop::FixedStepRunner;
|
||||
/// Re-export of the platform-independent logical input snapshot.
|
||||
pub use self::input::InputState;
|
||||
/// Re-export of the normalized primary pointer snapshot.
|
||||
pub use self::pointer::PointerState;
|
||||
|
||||
52
crates/engines/engine-v1-common/src/pointer.rs
Normal file
52
crates/engines/engine-v1-common/src/pointer.rs
Normal file
@@ -0,0 +1,52 @@
|
||||
// file: crates/engines/engine-v1-common/src/pointer.rs
|
||||
// version: 1
|
||||
|
||||
/// Platform-independent normalized primary pointer state for one engine update.
|
||||
#[derive(Clone, Copy, Debug, PartialEq)]
|
||||
pub struct PointerState {
|
||||
active: bool,
|
||||
x: f32,
|
||||
y: f32,
|
||||
}
|
||||
|
||||
impl PointerState {
|
||||
/// Creates an inactive pointer at the normalized origin.
|
||||
#[must_use]
|
||||
pub const fn inactive() -> Self {
|
||||
return Self { active: false, x: 0.0, y: 0.0 };
|
||||
}
|
||||
|
||||
/// Creates a pointer state from normalized coordinates.
|
||||
#[must_use]
|
||||
pub fn normalized(active: bool, x: f32, y: f32) -> Self {
|
||||
return Self { active, x: x.clamp(0.0, 1.0), y: y.clamp(0.0, 1.0) };
|
||||
}
|
||||
|
||||
/// Reports whether the pointer is currently active.
|
||||
#[must_use]
|
||||
pub const fn active(self) -> bool {
|
||||
return self.active;
|
||||
}
|
||||
|
||||
/// Returns the normalized horizontal coordinate.
|
||||
#[must_use]
|
||||
pub const fn x(self) -> f32 {
|
||||
return self.x;
|
||||
}
|
||||
|
||||
/// Returns the normalized vertical coordinate.
|
||||
#[must_use]
|
||||
pub const fn y(self) -> f32 {
|
||||
return self.y;
|
||||
}
|
||||
}
|
||||
|
||||
impl Default for PointerState {
|
||||
fn default() -> Self {
|
||||
return Self::inactive();
|
||||
}
|
||||
}
|
||||
|
||||
#[cfg(test)]
|
||||
#[path = "../unit_tests/pointer.rs"]
|
||||
mod tests;
|
||||
@@ -1,5 +1,5 @@
|
||||
// file: crates/engines/engine-v1-common/unit_tests/input.rs
|
||||
// version: 1
|
||||
// version: 2
|
||||
|
||||
#[test]
|
||||
fn action_state_is_independent() {
|
||||
@@ -10,3 +10,11 @@ fn action_state_is_independent() {
|
||||
assert!(!input.is_active(crate::GameAction::Left));
|
||||
});
|
||||
}
|
||||
|
||||
#[test]
|
||||
fn pointer_state_is_carried_independently_from_actions() {
|
||||
let pointer = crate::PointerState::normalized(true, 0.25, 0.75);
|
||||
let input = crate::InputState::none().with_pointer(pointer);
|
||||
assert_eq!(input.pointer(), pointer);
|
||||
assert!(!input.is_active(crate::GameAction::Primary));
|
||||
}
|
||||
|
||||
10
crates/engines/engine-v1-common/unit_tests/pointer.rs
Normal file
10
crates/engines/engine-v1-common/unit_tests/pointer.rs
Normal file
@@ -0,0 +1,10 @@
|
||||
// file: crates/engines/engine-v1-common/unit_tests/pointer.rs
|
||||
// version: 1
|
||||
|
||||
#[test]
|
||||
fn normalized_pointer_clamps_coordinates() {
|
||||
let pointer = crate::PointerState::normalized(true, -0.5, 1.5);
|
||||
assert!(pointer.active());
|
||||
assert_eq!(pointer.x(), 0.0);
|
||||
assert_eq!(pointer.y(), 1.0);
|
||||
}
|
||||
@@ -1,5 +1,5 @@
|
||||
// file: crates/engines/engine-v1-sdl/src/runtime.rs
|
||||
// version: 4
|
||||
// version: 5
|
||||
|
||||
/// Minimal SDL3 runtime used by Desktop POC runners.
|
||||
pub struct SdlRuntime {
|
||||
@@ -39,9 +39,10 @@ impl SdlRuntime {
|
||||
std::result::Result::Err(error) => return std::result::Result::Err(error.to_string()),
|
||||
};
|
||||
let mut runner = engine_v1_common::FixedStepRunner::new(self.frame_duration);
|
||||
let mut pointer = engine_v1_common::PointerState::inactive();
|
||||
tracing::info!(title = %self.title, width = self.width, height = self.height, "SDL3 runtime started");
|
||||
'running: loop {
|
||||
let mut input = engine_v1_common::InputState::none();
|
||||
let mut input = engine_v1_common::InputState::none().with_pointer(pointer);
|
||||
for event in events.poll_iter() {
|
||||
match event {
|
||||
sdl3::event::Event::Quit { .. } => break 'running,
|
||||
@@ -49,9 +50,20 @@ impl SdlRuntime {
|
||||
sdl3::event::Event::KeyDown { keycode: Some(sdl3::keyboard::Keycode::Space), .. } => {
|
||||
input = input.with_action(engine_v1_common::GameAction::Primary, true);
|
||||
},
|
||||
sdl3::event::Event::FingerDown { x, y, .. } | sdl3::event::Event::FingerMotion { x, y, .. } => {
|
||||
pointer = engine_v1_common::PointerState::normalized(true, x, y);
|
||||
input = input.with_pointer(pointer).with_action(engine_v1_common::GameAction::Primary, true);
|
||||
},
|
||||
sdl3::event::Event::FingerUp { x, y, .. } | sdl3::event::Event::FingerCanceled { x, y, .. } => {
|
||||
pointer = engine_v1_common::PointerState::normalized(false, x, y);
|
||||
input = input.with_pointer(pointer);
|
||||
},
|
||||
_ => {},
|
||||
}
|
||||
}
|
||||
if pointer.active() {
|
||||
input = input.with_pointer(pointer).with_action(engine_v1_common::GameAction::Primary, true);
|
||||
}
|
||||
runner.tick(game, input);
|
||||
canvas.set_draw_color(sdl3::pixels::Color::RGB(18, 18, 24));
|
||||
canvas.clear();
|
||||
|
||||
Reference in New Issue
Block a user