mirage-engine 0.2.0

Mirage, an immediate-mode 3D engine for simple games on desktop and the browser
Documentation
//! The action vocabularies a game reads its input through, and the three
//! kinds they split into.

use core::fmt;

use crate::Seats;
use crate::input::binding::{Axis2Binding, AxisBinding, ButtonBinding, Key};
use crate::input::table::sealed::Binding as Persisted;

/// Trait every action vocabulary implements, written by
/// [`InputButtonAction`](crate::InputButtonAction),
/// [`InputAxisAction`](crate::InputAxisAction) and
/// [`InputAxis2Action`](crate::InputAxis2Action).
///
/// Required if you want to rebind or read an action generically; the kind
/// traits are what a game implements by hand.
pub trait InputAction: Copy + 'static {
    /// Binding type for an action of this kind, which is what makes a
    /// mis-kinded [`rebind`](crate::FrameContext::rebind) fail to compile.
    type Binding: Persisted + fmt::Display;

    /// Default controls this action is bound to, before a player changes
    /// anything.
    fn defaults(&self) -> Vec<Self::Binding>;

    /// Every action of this vocabulary, which startup materializes into the
    /// table a player rebinds; one this leaves out reads through nothing.
    fn all() -> Vec<Self>;

    /// Name this action is known by in code; also the name the store
    /// keeps a rebind under.
    fn name(&self) -> &'static str;

    /// The action of this name, or `None` where the vocabulary has none.
    fn from_name(name: &str) -> Option<Self>;
}

/// An action that reads back `true` while it is held.
///
/// Required if you want a verb with two states: a jump, a shot, a pause.
pub trait InputButtonAction: InputAction<Binding = ButtonBinding> {
    /// The controls this action starts out bound to; they are
    /// alternatives, and any one of them holds it down.
    fn bindings(&self) -> Vec<ButtonBinding>;
}

/// An action that reads back a number in `-1..=1`, or, bound to a
/// [`PointerDelta`](crate::PointerDelta) or
/// [`WheelDelta`](crate::WheelDelta) lane, how far it moved.
///
/// Required if you want a verb with a strength and a direction: a throttle,
/// a lean, a turn.
pub trait InputAxisAction: InputAction<Binding = AxisBinding> {
    /// The controls this action starts out bound to; the one pushed
    /// furthest is the one it reads.
    fn bindings(&self) -> Vec<AxisBinding>;
}

/// An action that reads back a vector no longer than `1`, or, bound to
/// [`Axis2Binding::pointer`](crate::Axis2Binding::pointer), how far the
/// pointer moved.
///
/// Required if you want a verb with a direction in the plane: a walk, a
/// look, a cursor.
pub trait InputAxis2Action: InputAction<Binding = Axis2Binding> {
    /// The controls this action starts out bound to; the one pushed
    /// furthest is the one it reads.
    fn bindings(&self) -> Vec<Axis2Binding>;
}

/// The three vocabularies one game plays with, named together as
/// [`Game::InputActions`](crate::Game::InputActions).
///
/// Fill a kind a game has no verbs of with [`NoInputButtons`],
/// [`NoInputAxes`] or [`NoInputAxes2`].
pub trait InputActions {
    /// The vocabulary whose actions read back as held or not.
    type Button: InputButtonAction;
    /// The vocabulary whose actions read back a number.
    type Axis: InputAxisAction;
    /// The vocabulary whose actions read back a vector.
    type Axis2: InputAxis2Action;
}

impl<S: InputActions> Seats<S::Button, ButtonBinding> for S {}
impl<S: InputActions> Seats<S::Axis, AxisBinding> for S {}
impl<S: InputActions> Seats<S::Axis2, Axis2Binding> for S {}

/// The input action set of a game that reads no input at all.
///
/// No value of it exists, so such a game reads no action.
#[derive(Clone, Copy, Debug, Eq, Hash, PartialEq)]
pub enum NoInputActions {}

impl InputActions for NoInputActions {
    type Button = NoInputButtons;
    type Axis = NoInputAxes;
    type Axis2 = NoInputAxes2;
}

/// The empty vocabulary of one kind: no value of it exists, so a game with
/// no verb of that kind reads none.
macro_rules! empty {
    ($name:ident, $kind:ident, $binding:ident, $noun:literal) => {
        #[doc = concat!("The vocabulary of a game with no ", $noun, " actions of its own.")]
        ///
        /// No value of it exists, so it fills the empty slot and nothing
        /// else.
        #[derive(Clone, Copy, Debug, Eq, Hash, PartialEq)]
        pub enum $name {}

        impl InputAction for $name {
            type Binding = $binding;

            fn defaults(&self) -> Vec<$binding> {
                match *self {}
            }

            fn all() -> Vec<Self> {
                Vec::new()
            }

            fn name(&self) -> &'static str {
                match *self {}
            }

            fn from_name(_name: &str) -> Option<Self> {
                None
            }
        }

        impl $kind for $name {
            fn bindings(&self) -> Vec<$binding> {
                match *self {}
            }
        }
    };
}

empty!(NoInputButtons, InputButtonAction, ButtonBinding, "button");
empty!(NoInputAxes, InputAxisAction, AxisBinding, "number");
empty!(NoInputAxes2, InputAxis2Action, Axis2Binding, "vector");

impl InputAction for Key {
    type Binding = ButtonBinding;

    fn defaults(&self) -> Vec<ButtonBinding> {
        <Self as InputButtonAction>::bindings(self)
    }

    fn all() -> Vec<Self> {
        Self::ALL.to_vec()
    }

    fn name(&self) -> &'static str {
        self.token()
    }

    fn from_name(name: &str) -> Option<Self> {
        Self::from_token(name)
    }
}

/// A key is its own action, bound to itself: the vocabulary a prototype
/// reads through before it has declared what the player does.
impl InputButtonAction for Key {
    fn bindings(&self) -> Vec<ButtonBinding> {
        vec![ButtonBinding::Key(*self)]
    }
}

impl InputActions for Key {
    type Button = Key;
    type Axis = NoInputAxes;
    type Axis2 = NoInputAxes2;
}