nightshade-api 0.40.0

Procedural high level API for the nightshade game engine
Documentation
//! Keyboard, mouse, and time queries, plus the movement helpers every game
//! rewrites.

use nightshade::prelude::*;

/// True while `key` is held down.
#[inline]
pub fn key_down(world: &World, key: KeyCode) -> bool {
    world.resources.input.keyboard.is_key_pressed(key)
}

/// True only on the frame `key` went down.
#[inline]
pub fn key_pressed(world: &World, key: KeyCode) -> bool {
    world.resources.input.keyboard.just_pressed(key)
}

/// True while the mouse button is held down.
#[inline]
pub fn mouse_down(world: &World, button: MouseButton) -> bool {
    let state = world.resources.input.mouse.state;
    match button {
        MouseButton::Left => state.contains(MouseState::LEFT_CLICKED),
        MouseButton::Right => state.contains(MouseState::RIGHT_CLICKED),
        MouseButton::Middle => state.contains(MouseState::MIDDLE_CLICKED),
        _ => false,
    }
}

/// True only on the frame the mouse button went down.
#[inline]
pub fn mouse_clicked(world: &World, button: MouseButton) -> bool {
    let state = world.resources.input.mouse.state;
    match button {
        MouseButton::Left => state.contains(MouseState::LEFT_JUST_PRESSED),
        MouseButton::Right => state.contains(MouseState::RIGHT_JUST_PRESSED),
        MouseButton::Middle => state.contains(MouseState::MIDDLE_JUST_PRESSED),
        _ => false,
    }
}

/// The cursor position in window pixels.
#[inline]
pub fn mouse_position(world: &World) -> Vec2 {
    world.resources.input.mouse.position
}

/// How far the cursor moved this frame.
#[inline]
pub fn mouse_delta(world: &World) -> Vec2 {
    world.resources.input.mouse.position_delta
}

/// A signed 1d input: -1.0 while `negative` is held, 1.0 while `positive` is
/// held, 0.0 otherwise or when both are held.
#[inline]
pub fn axis(world: &World, negative: KeyCode, positive: KeyCode) -> f32 {
    let mut value = 0.0;
    if key_down(world, negative) {
        value -= 1.0;
    }
    if key_down(world, positive) {
        value += 1.0;
    }
    value
}

/// WASD as a camera relative movement direction on the ground plane,
/// normalized so diagonals are not faster. Returns zero when nothing is held.
/// Multiply by speed and [`delta_time`] and add to a position.
pub fn wasd(world: &World) -> Vec3 {
    let forward_input = axis(world, KeyCode::KeyS, KeyCode::KeyW);
    let strafe_input = axis(world, KeyCode::KeyA, KeyCode::KeyD);
    if forward_input == 0.0 && strafe_input == 0.0 {
        return Vec3::zeros();
    }
    let camera_forward = crate::camera::camera_forward(world);
    let mut planar_forward = Vec3::new(camera_forward.x, 0.0, camera_forward.z);
    if planar_forward.magnitude_squared() < f32::EPSILON {
        planar_forward = Vec3::new(0.0, 0.0, -1.0);
    }
    let planar_forward = planar_forward.normalize();
    let right = nalgebra_glm::cross(&planar_forward, &Vec3::y());
    (planar_forward * forward_input + right * strafe_input).normalize()
}

/// Seconds the previous frame took. Multiply rates by this for frame rate
/// independent motion.
#[inline]
pub fn delta_time(world: &World) -> f32 {
    world.resources.window.timing.delta_time
}

/// Seconds since the program started.
#[inline]
pub fn elapsed_seconds(world: &World) -> f32 {
    world.resources.window.timing.uptime_milliseconds as f32 / 1000.0
}