Skip to content

Commands

fallahn edited this page Oct 5, 2017 · 4 revisions

Unlike Messages commands are a method of inter-system communication which can target specific entities. In fact commands target only entities, and only those which are currently have a xy::CommandTarget component attached. Commands are made up of a set of target flags describing a group of entities, and an action in the form of a function. To send a command first create an instance of xy::Command, assign its target, and then give it an action.

xy::Command cmd;
cmd.targetFlags = MyNpcs;

xy::Command::targetFlags is simply a bit mask of user defined values, which you may declare in an enum for example:

enum CommandIds
{
    NPC = 0x1,
    Player = 0x2,
    LogicNode = 0x4
};

These IDs then need to be assigned to an entity when it is created, using the xy::CommandTarget component. The component contains a single field ID which represents one or more target flags. For example an entity may fall into multiple categories, the values of which can be OR'd together:

entity.addComponent<xy::CommandTarget>().ID = CommandIds::NPC | CommandIds::LogicNode;

A similar mask is used to set the target of the command

cmd.targetFlags = CommandIds::Player | CommandIds::LogicNode;

when the command is sent down the scene graph any entities which are flagged with any of the target categories will then perform the action associated with the command.

To create a command action you can either use std::bind() to bind an existing function to the action, a functor, or you can use a lambda expression to define a function in-place (as well as capture any relevant variables). The function must have this signature:

void func(xy::Entity entity, float time);

When the function is executed the targeted entity is passed in, along with the current frame time. Although commands only target entities, the entity class itself provides access to attached components, which allows modification from within an action.

cmd.action = [](xy::Entity entity, float time)
{
    entity.getComponent<xy::Sprite>().setColour(sf::Color::Green);
};

The above lambda expression will attempt to call setColour() on the attached component of type xy::Sprite. It is down to the user to ensure that this component is actually attached to the entity, and handle any errors which may occur. Finally, to send the command, the scene must have an active instance of xy::CommandSystem. This can be added manually, but will also be automatically added when any Director objects are added to the scene. It is then only a matter of:

m_scene().getSystem<xy::CommandSystem>().sendCommand(cmd);

Commands are placed in a queue, and are therefore not actually executed until the next frame when the scene's systems are processed. Be aware of this when capturing any variables in lambda expressions, as the state of those variables may have changed (or gone out of scope altogether!) between frames.