Un système de Process et de ProcessManager

 

WoWScrnShot_082916_183045

Intro :

Dans un jeu vidéo on fait souvent appel à plusieurs sous-systèmes et pour les mettre à jour fréquemment.

On va utiliser deux classes permettant de gérer ces sous systèmes.

class Process : classe de base, on peut la dériver puis redéfinir la méthode VUpdate().
class ProcessManager : gestionnaire d’instances de Process.

Un Process peut être n’importe quoi : il faut juste tout simplement que ce soit un objet qui nécessite d’être mise à jour.

Par exemple on peut l’utiliser pour : le système de script, des collisions, de l’audio, de l’IA, du rendu de certaines entités.

Si on veut mettre le jeu en pause il  suffira de faire appel aux méthodes Pause() et UnPause().

Pour le fichier include Process.h


class Process
{
    friend class ProcessManager;

public:
    enum State
    {
        UNINITIALIZED = 0,
        REMOVED,
        RUNNING,
        PAUSED,
        SUCCEEDED,
        FAILED,
        ABORTED,
    };
    
private:
    State m_state; 

public:

    Process(void);
    virtual ~Process(void);
    
protected:
    virtual void VOnInit(void) { m_state = RUNNING; }
    virtual void VOnUpdate(unsigned long deltaMs) = 0;
    virtual void VOnSuccess(void) { }
    virtual void VOnFail(void) { }
    virtual void VOnAbort(void) { }

public:
    inline void Succeed(void);
    inline void Fail(void);
    
    inline void Pause(void);
    inline void UnPause(void);
    State GetState(void) const { return m_state; }
    bool IsAlive(void) const { return (m_state == RUNNING
                               || m_state == PAUSED); }
    bool IsDead(void) const { return (m_state == SUCCEEDED
                              || m_state == FAILED
                              || m_state == ABORTED); }
    bool IsRemoved(void) const { return (m_state == REMOVED); }
    bool IsPaused(void) const { return m_state == PAUSED; }

    inline void AttachChild(Process* pChild);
    Process* RemoveChild(void);
    Process* PeekChild(void) { return m_pChild; }

private:
    void SetState(State newState) { m_state = newState; }
};

Dans le fichier Process.cpp :


Process::Process(void)
{
    m_state = UNINITIALIZED;
}

Process::~Process(void)
{
    if (m_pChild)
    {
        m_pChild->VOnAbort();
    }
}

inline void Process::Succeed(void)
{
    assert(m_state == RUNNING || m_state == PAUSED);
    m_state = SUCCEEDED;
}

inline void Process::Fail(void)
{
    assert(m_state == RUNNING || m_state == PAUSED);
    m_state = FAILED;
}

inline void Process::AttachChild(StrongProcessPtr pChild)
{
    if (m_pChild)
        m_pChild->AttachChild(pChild);
    else
        m_pChild = pChild;
}

inline void Process::Pause(void)
{
    if (m_state == RUNNING)
        m_state = PAUSED;
    else
        std::cout <<
        "Attempting to pause a process that isn't running"
        << std::endl;
}

inline void Process::UnPause(void)
{
    if (m_state == PAUSED)
        m_state = RUNNING;
    else
        std::cout <<
        "Attempting to unpause a process that isn't paused"
        << std::endl;
}

Process* Process::RemoveChild(void)
{
    if (m_pChild)
    {
        m_pChild = NULL;
    }

    return NULL;
}

Maintenant pour le fichier include ProcessManager.h :


#include "Process.h"

class ProcessManager
{
    typedef std::list<Process*> ProcessList;

    ProcessList m_processList;

public:

    ~ProcessManager(void);

    unsigned int UpdateProcesses(unsigned long deltaMs);
    Process* AttachProcess(Process* pProcess);
    void AbortAllProcesses(bool immediate);

    unsigned int GetProcessCount(void) const {
                 return m_processList.size(); }

private:
    void ClearAllProcesses(void);
};

Pour le fichier ProcessManager.cpp :


ProcessManager::~ProcessManager(void)
{
    ClearAllProcesses();
}

unsigned int ProcessManager::UpdateProcesses(unsigned long deltaMs)
{
    unsigned short int successCount = 0;
    unsigned short int failCount = 0;

    ProcessList::iterator it = m_processList.begin();
    while (it != m_processList.end())
    {
        Process* pCurrProcess = (*it);

        ProcessList::iterator thisIt = it;
        ++it;

        if (pCurrProcess->GetState() == Process::UNINITIALIZED)
            pCurrProcess->VOnInit();

        if (pCurrProcess->GetState() == Process::RUNNING)
            pCurrProcess->VOnUpdate(deltaMs);

        if (pCurrProcess->IsDead())
        {
            switch (pCurrProcess->GetState())
            {
                case Process::SUCCEEDED :
                {
                    pCurrProcess->VOnSuccess();
                    Process* pChild = pCurrProcess->RemoveChild();
                    if (pChild)
                        AttachProcess(pChild);
                    else
                        ++successCount;
                    break;
                }

                case Process::FAILED :
                {
                    pCurrProcess->VOnFail();
                    ++failCount;
                    break;
                }

                case Process::ABORTED :
                {
                    pCurrProcess->VOnAbort();
                    ++failCount;
                    break;
                }
            }

            m_processList.erase(thisIt);
        }
    }

    return ((successCount << 16) | failCount);
}

Process* ProcessManager::AttachProcess(Process* pProcess)
{
    m_processList.push_front(pProcess);
    return pProcess;
}

void ProcessManager::ClearAllProcesses(void)
{
    m_processList.clear();
}

void ProcessManager::AbortAllProcesses(bool immediate)
{
    ProcessList::iterator it = m_processList.begin();
    while (it != m_processList.end())
    {
        ProcessList::iterator tempIt = it;
        ++it;

        StrongProcessPtr pProcess = *tempIt;
        if (pProcess->IsAlive())
        {
            pProcess->SetState(Process::ABORTED);
            if (immediate)
            {
                pProcess->VOnAbort();
                m_processList.erase(tempIt);
            }
        }
    }
}


Résumé :

Ces classes vous seront utiles pour implémenter vos propres systèmes / process.

Références :

– Game Coding Complete 4 (code LGPL)

Laisser un commentaire

Votre adresse e-mail ne sera pas publiée. Les champs obligatoires sont indiqués avec *