[ Web Proxy ]
URL:
Viewing: https://raw.githubusercontent.com/aigamedev/btsk/master/BehaviorTreeEvent.cpp [Back]  [Original]

/******************************************************************************
 * This file is part of the Behavior Tree Starter Kit.
 * 
 * Copyright (c) 2012, AiGameDev.com
 * 
 * Credits:         Alex J. Champandard
 *****************************************************************************/

#include 
#include 
#include 
#include "Shared.h"
#include "Test.h"

namespace bt4
{

// ============================================================================

enum Status
{
    BH_INVALID,
    BH_SUCCESS,
    BH_FAILURE,
    BH_RUNNING,
    BH_SUSPENDED,
};

typedef std::function BehaviorObserver;

class Behavior
{
public:
    Behavior()
    :	m_eStatus(BH_INVALID)
    {
    }

    virtual ~Behavior()
    {
    }

    Status tick()
    {
        if (m_eStatus == BH_INVALID)
        {
            onInitialize();
        }

        m_eStatus = update();

        if (m_eStatus != BH_RUNNING)
        {
            onTerminate(m_eStatus);
        }
        return m_eStatus;
    }

    virtual Status update() = 0;

    virtual void onInitialize() {}
    virtual void onTerminate(Status) {}

    Status m_eStatus;
    BehaviorObserver m_Observer;
};

class BehaviorTree
{
public:

    void start(Behavior& bh, BehaviorObserver* observer = NULL)
    {
        if (observer != NULL)
        {
            bh.m_Observer = *observer;
        }
        m_Behaviors.push_front(&bh);
    }

    void stop(Behavior& bh, Status result)
    {
        ASSERT(result != BH_RUNNING);
        bh.m_eStatus = result;

        if (bh.m_Observer)
        {
            bh.m_Observer(result);
        }
    }

    void tick()
    {
        // Insert an end-of-update marker into the list of tasks.
        m_Behaviors.push_back(NULL);

        // Keep going updating tasks until we encounter the marker.
        while (step())
        {
            continue;
        }
    }

    bool step()
    {
        Behavior* current = m_Behaviors.front();
        m_Behaviors.pop_front();

        // If this is the end-of-update marker, stop processing.
        if (current == NULL)
        {
            return false;
        }

        // Perform the update on this individual task.
        current->tick();

        // Process the observer if the task terminated.
        if (current->m_eStatus != BH_RUNNING  &&  current->m_Observer)
        {
            current->m_Observer(current->m_eStatus);
        }
        else // Otherwise drop it into the queue for the next tick().
        {
            m_Behaviors.push_back(current);
        }
        return true;
    }

protected:
    std::deque m_Behaviors;
};

// ----------------------------------------------------------------------------

struct MockBehavior : public Behavior
{
    int m_iInitializeCalled;
    int m_iTerminateCalled;
    int m_iUpdateCalled;
    Status m_eReturnStatus;
    Status m_eTerminateStatus;

    MockBehavior()
    :	m_iInitializeCalled(0)
    ,	m_iTerminateCalled(0)
    ,	m_iUpdateCalled(0)
    ,	m_eReturnStatus(BH_RUNNING)
    ,	m_eTerminateStatus(BH_INVALID)
    {
    }

        virtual ~MockBehavior()
        {
        }

    virtual void onInitialize()
    {
        ++m_iInitializeCalled;
    }

    virtual void onTerminate(Status s)
    {
        ++m_iTerminateCalled;
        m_eTerminateStatus = s;
    }

    virtual Status update()
    {
        ++m_iUpdateCalled;
        return m_eReturnStatus;
    }
};

TEST(StarterKit4, TaskInitialize)
{
    MockBehavior t;
    BehaviorTree bt;

    bt.start(t);
    CHECK_EQUAL(0, t.m_iInitializeCalled);

    bt.tick();
    CHECK_EQUAL(1, t.m_iInitializeCalled);
};

TEST(StarterKit4, TaskUpdate)
{
    MockBehavior t;
    BehaviorTree bt;

    bt.start(t);
    bt.tick();
    CHECK_EQUAL(1, t.m_iUpdateCalled);

    t.m_eReturnStatus = BH_SUCCESS;
    bt.tick();
    CHECK_EQUAL(2, t.m_iUpdateCalled);
};

TEST(StarterKit4, TaskTerminate)
{
    MockBehavior t;
    BehaviorTree bt;

    bt.start(t);
    bt.tick();
    CHECK_EQUAL(0, t.m_iTerminateCalled);

    t.m_eReturnStatus = BH_SUCCESS;
    bt.tick();
    CHECK_EQUAL(1, t.m_iTerminateCalled);
};


// ============================================================================

class Composite : public Behavior
{
public:
    typedef std::vector Behaviors;
    Behaviors m_Children;
};

class Sequence : public Composite
{
public:
    Sequence(BehaviorTree& bt)
    :	m_pBehaviorTree(&bt)
    {
    }

protected:
    BehaviorTree* m_pBehaviorTree;

    virtual void onInitialize()
    {
        m_Current = m_Children.begin();
        BehaviorObserver observer = std::bind(&Sequence::onChildComplete, this, std::placeholders::_1);
        m_pBehaviorTree->start(**m_Current, &observer);
    }

    void onChildComplete(Status)
    {
        Behavior& child = **m_Current;
        if (child.m_eStatus == BH_FAILURE)
        {
            m_pBehaviorTree->stop(*this, BH_FAILURE);
            return;
        }

        ASSERT(child.m_eStatus == BH_SUCCESS);
        if (++m_Current == m_Children.end())
        {
            m_pBehaviorTree->stop(*this, BH_SUCCESS);
        }
        else
        {
            BehaviorObserver observer = std::bind(&Sequence::onChildComplete, this, std::placeholders::_1);
            m_pBehaviorTree->start(**m_Current, &observer);
        }
    }

    virtual Status update()
    {
        return BH_RUNNING;
    }

    Behaviors::iterator m_Current;
};

// ----------------------------------------------------------------------------

template 
class MockComposite : public COMPOSITE
{
public:
    MockComposite(BehaviorTree& bt, size_t size)
    :	COMPOSITE(bt)	
    {
        for (size_t i=0; i

Web Proxy Viewer  |  New URL  |  Original Page