Expand description
ยงBevy Sequential Actions
A simple library for managing and sequencing various actions in Bevy.
An entity with a queue of repeating actions
ยง๐ Getting Started
ยงPlugin
The quickest way for getting started is adding the SequentialActionsPlugin
to your App
.
use bevy_sequential_actions::*;
fn main() {
App::new()
.add_plugins((DefaultPlugins, SequentialActionsPlugin))
.run();
}
ยงImplementing an Action
An action is anything that implements the Action
trait.
The trait contains various methods that together defines the lifecycle of an action.
From this, you can create any action that can last as long as you like,
and do as much as you like.
An entity with actions is referred to as an agent
.
A simple wait action follows.
pub struct WaitAction {
duration: f32, // Seconds
current: Option<f32>, // None
}
impl Action for WaitAction {
// By default, this method is called every frame in the Last schedule.
fn is_finished(&self, agent: Entity, world: &World) -> bool {
// Determine if wait timer has reached zero.
world.get::<WaitTimer>(agent).unwrap().0 <= 0.0
}
// This method is called when an action is started.
fn on_start(&mut self, agent: Entity, world: &mut World) -> bool {
// Take current time (if paused), or use full duration.
let duration = self.current.take().unwrap_or(self.duration);
// Run the wait timer system on the agent.
world.entity_mut(agent).insert(WaitTimer(duration));
// Is action already finished?
// Returning true here will immediately advance the action queue.
self.is_finished(agent, world)
}
// This method is called when an action is stopped.
fn on_stop(&mut self, agent: Option<Entity>, world: &mut World, reason: StopReason) {
// Do nothing if agent has been despawned.
let Some(agent) = agent else { return };
// Take the wait timer component from the agent.
let wait_timer = world.entity_mut(agent).take::<WaitTimer>();
// Store current time when paused.
if reason == StopReason::Paused {
self.current = Some(wait_timer.unwrap().0);
}
}
// Optional. This method is called when an action is added to the queue.
fn on_add(&mut self, agent: Entity, world: &mut World) {}
// Optional. This method is called when an action is removed from the queue.
fn on_remove(&mut self, agent: Option<Entity>, world: &mut World) {}
// Optional. The last method that is called with full ownership.
fn on_drop(self: Box<Self>, agent: Option<Entity>, world: &mut World, reason: DropReason) {}
}
#[derive(Component)]
struct WaitTimer(f32);
fn wait_system(mut wait_timer_q: Query<&mut WaitTimer>, time: Res<Time>) {
for mut wait_timer in &mut wait_timer_q {
wait_timer.0 -= time.delta_seconds();
}
}
ยงModifying Actions
Actions can be added to any Entity
with the SequentialActions
marker component.
Adding and modifying actions is done through the actions(agent)
extension method implemented for both Commands
and World
.
See the ModifyActions
trait for available methods.
fn setup(mut commands: Commands) {
// Spawn entity with the marker component
let agent = commands.spawn(SequentialActions).id();
commands
.actions(agent)
// Add a single action
.add(action_a)
// Add more actions with a tuple
.add((action_b, action_c))
// Add a collection of actions
.add(actions![
action_d,
action_e,
action_f,
])
// Add an anonymous action with a closure
.add(|_agent, world: &mut World| -> bool {
// on_start
world.send_event(AppExit::Success);
true
});
}
ยงโ ๏ธ Warning
Since you are given a mutable World
, you can in practice do anything.
Depending on what you do, the logic for advancing the action queue might not work properly.
There are a few things you should keep in mind:
-
If you want to despawn an
agent
as an action, this should be done inon_start
. -
The
execute
andnext
methods should not be used, as that will immediately advance the action queue while inside any of the trait methods. Instead, you should returntrue
inon_start
. -
When adding new actions, you should set the
start
property tofalse
. Otherwise, you will effectively callexecute
which, again, should not be used. At worst, you will cause a stack overflow if the action adds itself.fn on_start(&mut self, agent: Entity, world: &mut World) -> bool { world .actions(agent) .start(false) // Do not start next action .add((action_a, action_b, action_c)); // Immediately advance the action queue true }
Macrosยง
- actions
- Helper macro for creating an array of boxed actions.
Structsยง
- Action
Queue - The action queue for an
agent
. - Actions
Bundle - The component bundle that all entities with actions must have.
- AddConfig
- Configuration for actions to be added.
- Agent
Actions - Modify actions using
World
. - Agent
Commands - Modify actions using
Commands
. - Current
Action - The current action for an
agent
. - Sequential
Actions - Marker component for entities with actions.
- Sequential
Actions Plugin - The
Plugin
for this library that you can add to yourApp
.
Enumsยง
- AddOrder
- The queue order for actions to be added.
- Drop
Reason - The reason why an
Action
was dropped. - Stop
Reason - The reason why an
Action
was stopped.
Traitsยง
- Action
- The trait that all actions must implement.
- Actions
Proxy - Proxy method for modifying actions.
- Into
Boxed Action - Conversion of an Action to a BoxedAction.
- Into
Boxed Actions - Conversion of actions to a collection of boxed actions.
- Modify
Actions - Methods for modifying actions.
Type Aliasesยง
- Boxed
Action - A boxed
Action
.