Click here to Skip to main content
15,878,748 members
Articles / Programming Languages / C++
Article

Designing a framework for a game engine using C++

Rate me:
Please Sign up or sign in to vote.
4.00/5 (7 votes)
6 Jul 2008CPOL3 min read 47.8K   1.3K   27   2
This article describes my work in creating a framework for a generic game engine in C++.

Introduction

I took a task of writing a white paper about designing a game engine. For this work, I started implementing a framework in C++ which involves the basic implementation of Design Patterns and C++ concepts like Policy based design. This article talks about my design, and it includes a compiled code snippet as well.

Background

This describes a framework which makes use of famous design paradigms like Policy based design, Decorator and Strategy Patterns, and is implemented using C++.

Using the Code

Use of Policy Based Design for Settings

Before even diving into the nifty gritty of a Football gaming engine design, any game during start-up has to allow the user to choose the Difficulty level. I am assuming there are three levels of difficulty, by default: Low, Medium, and High. Since the level has to be chosen at the beginning, this gives me an opportunity to use Policy based design using template classes (based on Andrei Alexandrescu's book, Modern C++ Design). So, the difficulty level can be a policy here. Also, I am going to add another policy for the playing mode. The playing mode can be Auto (in this case, you will play against the machine) or Multi (you can play with your friend).

Policy based design has been described as a compile-time variant of the Strategy pattern

C++
template <typename T>
struct DifficultyLevel_High
{
    static void setDifficultyLevel(T&) { cout << "Setting to High difficulty 
    level" <<endl; }
};
template <typename T>
struct DifficultyLevel_Med
{ 
    static void setDifficultyLevel(T&)
    { cout << "Setting to Medium difficulty level" <<endl; }
};
template <typename T>
struct DifficultyLevel_Low
{
    static void setDifficultyLevel(T&)
    {cout << "Setting to Low difficulty level" <<endl; }
};
template <typename T>
struct Playmode_policy_auto
{
    static void setPlaymodepolicy(T&)
    { cout << "Setting to auto Playmode" <<endl; }
};
template <typename T>
struct Playmode_policy_multi
{ 
    static void setPlaymodepolicy(T&)
    { cout << "Setting to multi Playmode" <<endl; }
};

class FootballEngineType
{
public:
    FootballEngineType()
    { cout << "Engine set as Football " << endl; 
    }
};

//---------------------Usage of Policy based design----------------//
template< typename T,
template <typename> class DifficultyLevel_policy, 
template <typename> class Playmode_policy >
class GamingEngine
{
public:
    void Run()
    {
        DifficultyLevel_policy<T>::setDifficultyLevel(engineType);
        Playmode_policy<T> ::setPlaymodepolicy(engineType);
        start();
    }
private:
    T engineType;
};

The next important thing is that a team should be able to change the logic and strategy of the game at runtime. For example, a user can opt to go for a defend instead of an attack. This can be made possible using the Strategy pattern. We can have a list of algorithms for defending, attacking etc., so that the user is able to choose the team strategy at runtime. This is possible by using the Strategy pattern. Here, I have defined three strategies, and the strategies can be set by the GameLogic class.

C++
class Strategy
{
public:
    Strategy() {}
    virtual void Apply()=0;
    virtual ~Strategy() {}
};
class DefendStrategy : public Strategy{ 
public: 
    DefendStrategy():Strategy() { cout << "Defend strategy set" << endl; }
    void Apply() { cout << "Defend strategy applied" << endl; }
    virtual ~DefendStrategy() {} 
}; 

class AttackStrategy: public Strategy
{
public:
    AttackStrategy():Strategy() { cout << "Attack strategy set" << endl; }
    void Apply() { cout << "Attack strategy applied" << endl; }
    virtual ~AttackStrategy() {}
};

class MediumStrategy: public Strategy
{
public:
    MediumStrategy() :Strategy(){ cout << "Medium strategy set" << endl; }
    void Apply() { cout << "Medium strategy applied" << endl; }
    virtual ~MediumStrategy() {}
};
class GameLogic
{ 
public:
    StratType StrategyType;
    GameLogic()
    {
        m_Strategy = NULL;
    }
    void SetStrategy(StratType type)
    {
        if (m_Strategy) delete m_Strategy;
        if (type == Med)
            m_Strategy = new MediumStrategy();
        else if (type == Defend)
            m_Strategy = new DefendStrategy();
        else if (type == Attack)
            m_Strategy = new AttackStrategy();
    }
    void Exec() { m_Strategy->Apply(); }
    ~GameLogic() { if (m_Strategy) delete m_Strategy; }
private:
    Strategy *m_Strategy;
};

Then comes the different roles each entity can perform. Each team has a list of players, coach, physiotherapist, manager, referee, and team CEO etc. Each one in a team can perform one or more roles, and the role can be assigned at runtime based on the credibility and other parameters. Also, each person as a player can have different responsibilities like Forward, Defender, Midfielder, and Goalkeeper etc. This should also be done at runtime without using sub classing.

Both the roles and responsibilities are assigned at runtime using the Decorator pattern.

Following are the helper functions used to get the roles and responsibilities of a gaming entity (a person) at runtime:

C++
//------------templated helper functions for getting roles-------//
template <class T>
T* getresponsibility_entity(GameEntity *pEnt)
{
    return dynamic_cast<T*>(pEnt->GetResponsibility(T::RESP_CLSID));
}
template <class T>
T* getroles_entitiy(GameEntity *pEnt)
{
    return dynamic_cast<T*>(pEnt->GetRole(T::ROL_CLSID));
}

Following is the code snippet which creates a gaming entity and assigns roles and responsibilities at run time and retrieves those objects using the above mentioned helper functions (for the full implementation, please refer to the attached CPP file):

C++
// Add a single player
GameEntity* play1 = new GameEntity("Beckham", "David");
//Adding role as Player
play1->AddRole(new Player(play1));
Player *playRole = getroles_entitiy<Player>(play1);
//Adding Responsibilities to play and manage
play1->AddResponsibilities(new ToPlay(play1));
play1->AddResponsibilities(new ToManage(play1));

Also, different teams can play for different league matches in different playgrounds with different settings. For example, each entity in a Football game can be clubbed as a team, and then different presentation settings can be applied. You can add players to a specific football club (dress colour) and add different teams for a league match (like English premier league etc.). Here, the actual abstraction of each entity (Team/League match) can be decoupled from the implementation (League/Football ground/Presentation settings etc.) using the Bridge pattern. Hence the implementation and the abstraction can vary independently. Alternatively, the Builder pattern can also be used for the same task.

The entire design is implemented/compiled and tested in the Visual Studio 2005 (VC8.0) compiler. The implemented CPP files FootballEngine.cpp and stdafx.h are attached.

Points of Interest

Future Add-Ons

I was thinking of using the Subject-Observer pattern to notify players (Gaming entity) about the strategy and the position of the ball and the co-ordinates of other opponents. I will add it in a later stage.

History

N/A

License

This article, along with any associated source code and files, is licensed under The Code Project Open License (CPOL)


Written By
Team Leader
United Kingdom United Kingdom
Nalla has 9+ years of experience in system software development using C++/C# on Windows/Linux platform applied using OOAD/UML. He has good knowledge of x86 and AMD64 architecture.

Comments and Discussions

 
GeneralGeneric Programming! Pin
chenyu22028639-Jan-10 21:05
chenyu22028639-Jan-10 21:05 
QuestionComputer Online Game Pin
Gonaz6-Jan-10 18:36
Gonaz6-Jan-10 18:36 

General General    News News    Suggestion Suggestion    Question Question    Bug Bug    Answer Answer    Joke Joke    Praise Praise    Rant Rant    Admin Admin   

Use Ctrl+Left/Right to switch messages, Ctrl+Up/Down to switch threads, Ctrl+Shift+Left/Right to switch pages.