[][src]Derive Macro big_brain_derive::Consideration

#[derive(Consideration)]
{
    // Attributes available to this derive:
    #[consideration]
}

Considerations in big-brain are defined through this derive macro. Once defined, they can be freely used in a .ron file. While Actions define behaviors, Considerations are used to determine whether to execute a certain action.

Considerations are responsible for determining a specific Utility, or score, in Utility AI terms. This score is what sets Utility AI apart from plain old Behavior Trees.

Like anything else in an Entity system, considerations and their behaviors consist of a Component and an associated System.

Definition Example

This example is not tested
use specs::{Component, Entity, ReadStorage, System, WriteStorage};
use big_brain::{Consideration, Utility};

// These are your game's components.
use crate::components;

// `Consideration`s are defined by deriving them -- they MUST be Components.
#[derive(Debug, Component, Consideration)]
pub struct Hunger {
    // All considerations **must** have a public `actor` field. This will be populated
    // with the actual actor considering the world around it The `Entity` associated with
    // the `Consideration` itself is distinct from the actor.
    pub actor: Entity,

    // `default` fields will be populated using default::Default() when the
    // Consideration is instantiated. These cannot be used as params.
    #[consideration(default)]
    pub evaluator: PowerEvaluator,

    // `param` fields will be populated using the value passed in through the
    // `.ron` file.
    #[consideration(param)]
    pub weight: f32,
}

pub struct ConsiderHunger;

impl<'a> System<'a> for ConsiderHunger {
    type SystemData = (
        ReadStorage<'a, components::Hunger>,

        // This is the actual `Consideration` component.
        WriteStorage<'a, Hunger>,

        // The `Utility` component associated with this `Consideration` holds
        // the current calculated score for that consideration.
        WriteStorage<'a, Utility>,
    );

    fn run(&mut self, (hungers, mut considerers, mut utilities): Self::SystemData) {
        // Join the considerations with the utilities -- they share an `Entity`.
        for (conser, util) in (&mut considerers, &mut utilities).join() {
            // Any actor-related components must be fetched separately, based on
            // the consideration's `actor`.
            if let Some(hunger) = hungers.get(conser.actor.clone()) {
                *util = Utility {
                    // values and weights can be arbitrary numbers. The final
                    // score is based on combining these two values.
                    //
                    // Utilities with weight `0.0` are not used.
                    //
                    // For the formula, refer to the docs on `WeightedMeasure`.
                    value: conser.evaluator.evaluate(hunger.hunger),
                    weight: conser.weight,
                };
            }
        }
    }
}

Usage Example

This example is not tested
(
    picker: {"FirstToScore": ()},
    choices: [(
        // Considerations to use are defined using the `consider` param in choices.
        // A choice can have zero or more considerations.
        consider: [{"Hunger": (weight: 1.0)}],

        // This is the action that will be executed if this choice "wins".
        then: {"Eat": ()},
    )]
)