@ -8,11 +8,11 @@
//! use engine::actions::*;
//! use engine::actions::*;
//! use engine::*; // bevy prelude
//! use engine::*; // bevy prelude
//!
//!
//! // 1. Your game's actions, with each variant's kind declared inline.
//! // 1. Your game's actions. `#[action_kind]` defaults to `instant`, so a bare
//! // variant is an instant action; annotate only the others.
//! #[derive(Copy, Clone, Eq, PartialEq, Hash, GameAction)]
//! #[derive(Copy, Clone, Eq, PartialEq, Hash, GameAction)]
//! enum Action {
//! enum Action {
//! #[action_kind(instant)] // fires for one frame
//! Jump, // instant (the default — no attribute needed)
//! Jump,
//! #[action_kind(toggle)] // stays on/off
//! #[action_kind(toggle)] // stays on/off
//! Grid,
//! Grid,
//! #[action_kind(axis)] // carries a Vec2
//! #[action_kind(axis)] // carries a Vec2
@ -105,6 +105,32 @@
//! axis/scalar. [`ActionsPlugin`] registers them when you add it.
//! axis/scalar. [`ActionsPlugin`] registers them when you add it.
//! * **[`AppActionExt::on_action`]** — `app.on_action(Update, Action::Jump, jump)`,
//! * **[`AppActionExt::on_action`]** — `app.on_action(Update, Action::Jump, jump)`,
//! the explicit, no-macro form that keeps registration visible in `main`.
//! the explicit, no-macro form that keeps registration visible in `main`.
//!
//! ## Multiple action sets
//!
//! The whole API is generic over the action type, so a game is **not** limited to
//! one enum. Add an [`ActionsPlugin<T>`] per set to separate concerns — gameplay,
//! menu, audio, debug — each with its own bindings and handlers:
//!
//! ```rust,ignore
//! app.add_plugins(ActionsPlugin::<GameplayAction>::new().bind(/* .. */))
//! .add_plugins(ActionsPlugin::<MenuAction>::new().bind(/* .. */))
//! .add_plugins(ActionsPlugin::<AudioAction>::new().bind(/* .. */));
//! ```
//!
//! Each set gets its **own** independent [`ActionState<T>`], [`InputMap<T>`],
//! fan-in systems, and observers; [`on_action`], [`action_value`], and
//! [`ActionSource<T>`] are all keyed by the set's type, so sets never collide.
//! (Deriving [`GameAction`](macro@GameAction) generates a distinct set of impls
//! per enum, and each `ActionsPlugin::<T>` is a distinct plugin type, so adding
//! several is fine.)
//!
//! Bindings are read **independently** per set — there is no cross-set input
//! consumption or priority — which is exactly right for concerns that are
//! genuinely separate (audio vs debug vs gameplay). To make two sets *mutually
//! exclusive* (menu vs gameplay), gate their handlers with `run_if(in_state(..))`:
//! Bevy states are already exclusive, so only the active set's handlers run, even
//! when the same key is bound in both.
use core ::hash ::Hash ;
use core ::hash ::Hash ;
use core ::marker ::PhantomData ;
use core ::marker ::PhantomData ;
@ -201,13 +227,14 @@ impl ActionValue {
}
}
/// Derive macro for [`GameAction`]: annotate each variant with
/// Derive macro for [`GameAction`]: annotate each variant with
/// `#[action_kind(...)]` — `instant`, `toggle`, `axis`, or `scalar`.
/// `#[action_kind(...)]` — `instant`, `toggle`, `axis`, or `scalar`. The
/// attribute is optional and defaults to `instant`, so bare variants are instant
/// actions.
///
///
/// ```rust,ignore
/// ```rust,ignore
/// #[derive(Copy, Clone, Eq, PartialEq, Hash, GameAction)]
/// #[derive(Copy, Clone, Eq, PartialEq, Hash, GameAction)]
/// enum Action {
/// enum Action {
/// #[action_kind(instant)]
/// Jump, // instant (default)
/// Jump,
/// #[action_kind(toggle)]
/// #[action_kind(toggle)]
/// Grid,
/// Grid,
/// }
/// }