Keyboard shortcuts

Press or to navigate between chapters

Press S or / to search in the book

Press ? to show this help

Press Esc to hide this help

Input System

Input state is aggregated each frame into world.resources.input. Keyboard, mouse, gamepad, and touch all funnel into the same resource. There are two ways to read it. Polling, where a system checks "is this key currently held," and event-driven, where the system drains an event queue of state transitions.

Polling Input

Polling reads the current state. It tells you what is true right now, without history. Polling is the right choice for continuous controls like WASD movement, mouse look, or holding a fire button.

#![allow(unused)]
fn main() {
fn run_systems(&mut self, world: &mut World) {
    if world.resources.input.keyboard.is_key_pressed(KeyCode::KeyW) {
        move_forward(world);
    }

    let mouse_pos = world.resources.input.mouse.position;

    if world.resources.input.mouse.state.contains(MouseState::LEFT_JUST_PRESSED) {
        shoot(world);
    }
}
}

The JUST_PRESSED and JUST_RELEASED flags fire on the single frame that the transition happens. They are how polling-style code detects edges without keeping its own history.

Event-Driven Input

Events are state transitions. The engine pushes them onto world.resources.input.events as AppEvent values, and the application drains the queue inside run_systems. Use events for discrete actions like toggling a menu, selecting a weapon slot, or any input where the transition matters more than the held state.

#![allow(unused)]
fn main() {
fn on_keyboard_input(&mut self, world: &mut World, key_code: KeyCode, key_state: ElementState) {
    if key_state == ElementState::Pressed {
        match key_code {
            KeyCode::Escape => self.paused = !self.paused,
            KeyCode::F11 => toggle_fullscreen(world),
            _ => {}
        }
    }
}

fn on_mouse_input(&mut self, world: &mut World, state: ElementState, button: MouseButton) {
    if state == ElementState::Pressed && button == MouseButton::Left {
        self.shoot(world);
    }
}
}

Built-in Systems

Three input-driven systems ship with the engine. None of them run automatically. Call them from run_systems when the game wants the behavior.

#![allow(unused)]
fn main() {
fn run_systems(&mut self, world: &mut World) {
    fly_camera_system(world);

    escape_key_exit_system(world);

    pan_orbit_camera_system(world);
}
}

fly_camera_system reads WASD plus mouse look and writes to the active camera's transform. escape_key_exit_system exits the application when Escape is pressed. pan_orbit_camera_system reads middle-mouse drag and scroll wheel to orbit and zoom the active camera. The fly camera and pan-orbit camera are mutually exclusive on the same entity, and fly_camera_system skips entities that also have the PAN_ORBIT_CAMERA marker.

Chapters