Crate bevy_sequential_actions
source ·Expand description
Bevy Sequential Actions
A Bevy library that aims to execute a queue of various actions in a sequential manner. This generally means that one action runs at a time, and when it is done, the next action will start and so on until the queue is empty.
Getting Started
Plugin
In order for everything to work, the SequentialActionsPlugin
must be added to your App
.
use bevy::prelude::*;
use bevy_sequential_actions::*;
fn main() {
App::new()
.add_plugins(DefaultPlugins)
.add_plugin(SequentialActionsPlugin)
.run();
}
Modifying Actions
An action is anything that implements the Action
trait,
and can be added to any Entity
that contains the ActionsBundle
.
An entity with actions is referred to as an agent
.
See the ModifyActions
trait for available methods.
fn setup(mut commands: Commands) {
let agent = commands.spawn(ActionsBundle::new()).id();
commands
.actions(agent)
.add(action_a)
.add_parallel(actions![
action_b,
action_c
])
.repeat(Repeat::Forever)
.order(AddOrder::Back)
.add(action_d)
// ...
}
Implementing an Action
The Action
trait contains two methods:
- The
on_start
method which is called when an action is started. - The
on_stop
method which is called when an action is stopped.
In order for the action queue to advance, every action has to somehow signal when they are finished. There are two ways of doing this:
- Using the
ActionFinished
component on anagent
. By default, a system at the end of the frame will advance the queue if all active actions are finished. This is the typical approach as it composes well with other actions running in parallel. - Calling the
next
method on anagent
. This simply advances the queue at the end of the current stage it was called in. Useful for short one-at-a-time actions.
A simple wait action follows.
pub struct WaitAction {
duration: f32, // Seconds
current: Option<f32>, // None
}
impl Action for WaitAction {
fn on_start(&mut self, agent: Entity, world: &mut World, _commands: &mut ActionCommands) {
// Take current duration (if paused), or use full duration
let duration = self.current.take().unwrap_or(self.duration);
// Run the wait system on the agent
world.entity_mut(agent).insert(Wait(duration));
}
fn on_stop(&mut self, agent: Entity, world: &mut World, reason: StopReason) {
// Remove the wait component from the agent
let wait = world.entity_mut(agent).take::<Wait>();
// Store current duration when paused
if let StopReason::Paused = reason {
self.current = Some(wait.unwrap().0);
}
}
}
#[derive(Component)]
struct Wait(f32);
fn wait_system(mut wait_q: Query<(&mut Wait, &mut ActionFinished)>, time: Res<Time>) {
for (mut wait, mut finished) in wait_q.iter_mut() {
wait.0 -= time.delta_seconds();
// Confirm finished state every frame
if wait.0 <= 0.0 {
finished.confirm_and_reset();
}
}
}
Warning
One thing to keep in mind is that you should not modify actions using World
inside the Action
trait.
We cannot borrow a mutable action from an agent
while also passing a mutable world to it.
Since an action is detached from an agent
when the trait methods are called,
the logic for advancing the action queue will not work properly.
This is why ActionCommands
was created, so you can modify actions inside the Action
trait in a deferred way.
pub struct SetStateAction<S: States>(S);
impl<S: States> Action for SetStateAction<S> {
fn on_start(&mut self, agent: Entity, world: &mut World, commands: &mut ActionCommands) {
// Set state
world.resource_mut::<NextState<S>>().set(self.0.clone());
// Bad. The action queue will advance immediately.
world.actions(agent).next();
// Good. The action queue will advance a bit later.
commands.actions(agent).next();
// Also good. Does the same as above.
commands.add(move |w: &mut World| {
w.actions(agent).next();
});
// Also good. By default, the action queue will advance at the end of the frame.
world.get_mut::<ActionFinished>(agent).unwrap().confirm_and_persist();
}
fn on_stop(&mut self, _agent: Entity, _world: &mut World, _reason: StopReason) {}
}
Macros
- Helper macro for creating a collection of boxed actions.
Structs
- Commands for modifying actions inside the
Action
trait. - Component for counting how many active actions have finished.
- The component bundle that all entities with actions must have.
- Modify actions using
ActionCommands
. - Modify actions using
Commands
. - Modify actions using
World
. - Builder for linked actions.
Enums
- The queue order for an
Action
to be added. - The repeat configuration for an
Action
to be added. - The reason why an
Action
was stopped.
Traits
- The trait that all actions must implement.
- Proxy method for modifying actions. Returns a type that implements
ModifyActions
. - Methods for modifying actions.