This is the implementation of all the actions used by the dog behaviors.

#include "Action.h"

#include <alive/TreeBuilder.h>
#include <alive/engine/ConstantNode.h>
#include <alive/tree/Parallel.h>
#include <alive/tree/Repeat.h>
#include <alive/tree/ErrorHandler.h>


inline float getDelta()
{
    // Frame rate fixed at 30Hz
    return 0.033333333f;
}

Rotation and Translation

Two actions for manipulating the scene graph in space, relatively to its current position.

alive::Status ActionTranslate::execute()
{
    if (m_pNode == 0)
    {
        return FAILED;
    }

    // Setup a forward vector of sensible magnitude, and scale it according to
    // the configuration of this action.
    Ogre::Vector3 vTranslate(0.0f, 0.0f, 18.0f * m_Settings.getSpeed() * getDelta());
    // Use Ogre to translate this scene graph node relatively to the current
    // position.
    m_pNode->translate(vTranslate, Ogre::Node::TS_LOCAL);
    return RUNNING;
}


alive::Status ActionRotate::execute()
{
    if (m_pNode == 0)
    {
        return FAILED;
    }

    // Setup a rotation quaternion according to the settings of this action.
    Ogre::Quaternion qRotate;
    qRotate.FromAngleAxis(getDelta() * Ogre::Radian(m_Settings.getSpeed()),
                          Ogre::Vector3::UNIT_Y);
    // Use Ogre also to rotate this relatively to the Y axis.
    m_pNode->rotate(qRotate, Ogre::Node::TS_LOCAL);
    return RUNNING;
}

Waiting Action

This simple action sets a random value when starting, and decrements it during each update.

alive::Status ActionWaitFor::execute()
{
    m_fTimer -= getDelta();
    return m_fTimer < 0.0f ? COMPLETED : RUNNING;
}


void ActionWaitFor::init()
{
    m_fTimer = m_Settings.getTime() + m_Settings.getRandom()
             * (float)(rand()&65535) / 65535.0f;
}

Play Animation

The logic for playing an animation sets up an observer for shutting down the animation once it's done. The main update then steps the animation forward directly by accessing Ogre's functionality.

alive::Status ActionAnimate::execute()
{
    if (m_pAnimState == 0)
    {
        return FAILED;
    }
    // Keep playing the current animation forward.
    m_pAnimState->addTime(getDelta() * m_Settings.getSpeed());
    // Check if this action should keep running or not.
    if (!m_Settings.getLoop() && m_pAnimState->hasEnded())
    {
        return COMPLETED;
    }
    return RUNNING;
}


void ActionAnimate::init()
{
    m_pAnimState = 0;
    // Setup an observer to be notified upon termination.
    m_Observer.bind(this, &ActionAnimate::stop);
}


void ActionAnimate::stop(alive::Status)
{
    // This function disables the animation state once done.
    m_pAnimState->setEnabled(false);
    m_pAnimState->setWeight(0.0f);
}


void ActionAnimate::setup(Ogre::Entity& entity)
{
    m_pAnimState = entity.getAnimationState(m_Settings.getName());
    m_pAnimState->setLoop(m_Settings.getLoop());
    m_pAnimState->setWeight(1.0f);
    m_pAnimState->setEnabled(true);
    m_pAnimState->setTimePosition(0.0f);
}

Spatial Action

The implementation of the base class for rotation and translation.

void SpatialAction::setup(Ogre::Node& node)
{
    m_pNode = &node;
}


void SpatialAction::init()
{
    m_pNode = 0;
}