pico_engine_core/
lib.rs

1#![no_std]
2// ============================================================================
3// ENGINE MODULE
4// ============================================================================
5// Provides the game loop architecture and timing control.
6// This module ensures consistent frame timing and game state management.
7
8#![allow(unused)]
9
10pub mod components;
11pub mod game;
12
13pub use pico_ecs as ecs;
14pub use pico_ecs::camera;
15pub use pico_rendering as graphics;
16
17use pico_engine_hardware::{Hardware, Display, Timer, Input};
18
19// Re-export ECS types for convenience
20pub use ecs::component_storage::ComponentStorage;
21pub use ecs::{component, entity::Entity, world::World, MAX_ENTITIES};
22pub use game::Game;
23
24/// Game engine that runs the game loop
25pub struct Engine<H: Hardware> {
26    hardware: H,
27}
28
29impl<H: Hardware> Engine<H> {
30    /// Create a new game engine
31    pub fn new(hardware: H) -> Self {
32        Engine { hardware }
33    }
34
35    /// Run the game loop with the provided game implementation
36    pub fn run<G: Game>(&mut self, game: &mut G) -> ! {
37        // Initialize the game
38        game.init(self.hardware.display().get_screen_width() as u16, self.hardware.display().get_screen_height() as u16);
39
40        const FRAME_TIME_MS: u32 = 33; // ~30 FPS
41
42        // Main game loop
43        let mut delta_time = FRAME_TIME_MS;
44        let mut fps = 60u32;
45        
46        loop {
47            // Record frame start time
48            let frame_start = self.hardware.timer().get_counter();
49
50            // Update game state
51            self.hardware.input().update();
52            let should_continue = game.update(self.hardware.input().current_state(), delta_time);
53            if !should_continue {
54                // Game requested exit - in embedded systems we just halt
55                // In a real console, you might return to a menu or reset
56                panic!("Game exited");
57            }
58
59            // Render the frame
60            game.render(self.hardware.display(), delta_time);
61
62            /// Wait for next frame
63            let current_time = self.hardware.timer().get_counter();
64            let elapsed = (current_time - frame_start) / 1000; // Convert micros to millis
65            if elapsed < FRAME_TIME_MS as u64 {
66                self.hardware
67                    .timer()
68                    .delay_ms((FRAME_TIME_MS as u64 - elapsed) as u32);
69            }
70            let end_time = self.hardware.timer().get_counter();
71            delta_time = ((end_time - frame_start) / 1000) as u32;
72
73            
74            // Note: If frame takes longer than 17ms, we skip delay and continue
75            // This prevents timing drift while maintaining responsiveness
76        }
77    }
78}