Derive Macro big_brain_derive::Action [−][src]
#[derive(Action)] { // Attributes available to this derive: #[action] }
Action
s in big-brain
are defined through this derive macro. Once defined,
they can be freely used in a .ron file. They define actual behaviors that an
actor
will perform when the Thinker engine picks it as the active action,
based on Considerations.
Definition Example
ⓘ
use specs::{Component, Entity, System, WriteStorage}; use big_brain::{Action, ActionState}; // These are your game's components. use crate::components; // This will be used to create `Action` components. They MUST implement the // `specs::Component` trait. #[derive(Debug, Clone, Component, Action)] pub struct Eat { // All actions **must** have a public `actor` field. This will be populated // with the actual actor performing the Action. The `Entity` associated with // the `Action` itself is distinct from the actor. pub actor: Entity, // `default` fields will be populated using default::Default() when the // Action is instantiated. These cannot be used as params. #[action(default)] pub foo: f32, // `param` fields will be populated using the value passed in through the // `.ron` file. #[action(param)] pub reduce_by: f32, } // Once an Action component is defined, we define a System that can act on it. pub struct EatSystem; impl<'a> System<'a> for EatSystem { type SystemData = ( WriteStorage<'a, components::Hunger>, // This is the actual Eat component. WriteStorage<'a, Eat>, // An ActionState component is attached to every Action Entity. // It contains the current running status of the Action, and will be // updated as needed by the actor's Thinker. WriteStorage<'a, ActionState>, ); fn run(&mut self, (mut hungers, mut eat_actions, mut states): Self::SystemData) { // You can join the Eat and ActionState together. They're on the same component. for (state, eat_action) in (&mut states, &mut eat_actions).join() { // Any components attached to the actor must be fetched separately. if let Some(hunger) = hungers.get_mut(eat_action.actor.clone()) { match state { // At the very least, every Action should handle the // `Requested` state. ActionState::Requested => { hunger.hunger -= eat_action.reduce_by; // Success tells the Thinker that this action succeeded! *state = ActionState::Success; } // Make sure to handle Cancelled for long-running Actions. // The Thinker will not continue until the state is either // Success or Failure. ActionState::Cancelled => { *state = ActionState::Failure; } _ => {} } } } } }
Usage Example
ⓘ
( picker: {"FirstToScore": ()}, // Actions are defined using the `then` param to Choices choices: [( consider: [{"Hunger": ()}], // We can use the param defined in our derive definition here. // The `foo` field will be defaulted and cannot be defined here. then: {"Eat": (reduce_by: 80.0)}, )] )