Jump to content
  • Advertisement
Sign in to follow this  
Stompy9999

An efficiant game loop

This topic is 5007 days old which is more than the 365 day threshold we allow for new replies. Please post a new topic.

If you intended to correct an error in the post then please contact us.

Recommended Posts

So far, I've been using the standard noob game loop. My loops look like this:

while(gamerunning)
{

    switch(gamestate)
    {

        case TITLE:
             // do title stuff.
             break;

        case GAME:
             // do game stuff.
             break;

        case OVER:
             // do ending stuff.
             break;

    }

}


It works, but I realize it's not the most efficiant method. I was thinking of using linked list for game loops. I'm interested in how you guys handle the game loop. Some sample code would be appreciated. Thanks!

Share this post


Link to post
Share on other sites
Advertisement
I think a good node for a game state link list would be a struct like this:



typedef struct GAME_STATE
{

void (*handlefunc)(void);
GAME_STATE *last, *next;

} GAME_STATE;




this would allow for less conditional statements.

Share this post


Link to post
Share on other sites
I've implemented a basic kernel system, where you add tasks you want to run. So I simply implement any system that needs to run continuously as a task, add it to the kernel, and I'm set. I also implemented priorities and the ability to stop, restart, pause, and resume tasks, which makes it easy to turn things on and off. So your main game loop turns into something like this:

while(kernel->Run() == false) /* returns true when all tasks done */
{
// Any additional processing here
}

Tasks also implement a Run method, so when that returns true the kernel puts the task in a special stop list (doesn't remove it for efficiency in case another agent wants to restart the task). As long as there are tasks that are either running or suspended, the kernel runs.

Share this post


Link to post
Share on other sites
That makes sense. I'll take this method into consideration.

In simple games like Pong, it is okay to use a switch statement. However, large projects like RPGs have so many states that this process would make no logical sense.

That is why I'm interested in hearing everybody's take on the subject. It is something that can be done in many different ways. By hearing theories and examples on the subject, I can formulate my own method.

and if all else fails...I can just take one of your methods.[grin]

Share this post


Link to post
Share on other sites
Another good thing about the kernel setup is that you can also chose to derive a special sub-kernel object, which is a task itself. That way, you can add sub-kernels as tasks to parent kernels, and right away you've got yourself robust, nested task loops. Any process that requires a loop, turn into a task, add it to a kernel/sub-kernel, and the whole thing runs like a charm.

This is actually what many developers do in large games, simply because it's an easy, consistent setup that works well and cuts down on large loops and switch statements. And you can encapsulate data for each task, which makes everyone smile. I personally like to see it as the equivalent of functors [function objects], for loops. Looptors anyone? [smile]

Share this post


Link to post
Share on other sites
I did mine entirely differently. I have a class Scene, which is basically the root node of my scene graph. This node can have a script attached to it, like every other node in my scene graph. The script bound to the Scene node acts as the overall management script for the scene, meaning I'd load "title.nsg", "level1.nsg", "menu.nsg", or whatever, and each one of those can have its own script to define its behaviour. They can share scripts of course, so each level can use the same script to manage the in-game behaviour. This decentralises my game engine, and puts total control in the hands of the scripts. As I have implemented scripts using actual compiled dll's (with the possible option of incorporating an interpreted script langauge at a later date, allowing you to use either), there isn't a performance hit.

It's a little hard to explain properly without explaining the entire core architecture of my engine.

Share this post


Link to post
Share on other sites
As we're all sharing - here's my current implementation (although the code still needs cleaning up). Uses the factory method and a stack of states.

First the statemanager factory .h file:

#pragma once

#include <stack>
#include <map>
#include <string>

#include <boost/shared_ptr.hpp>
#include <singleton.h>

class State;

class SingletonStateManager
{
public:
// Init and de-init functions
SingletonStateManager(void);
~SingletonStateManager(void);

void Init();
void Kill();

typedef boost::shared_ptr<State> (*CreateNewStateCallback)();
bool RegisterState(std::string stateName, CreateNewStateCallback newStateFn);

// Utility functions
void PushState(std::string whichState);
void PopState();
void Update();

// Accessors and mutators
void Exiting() {exiting_ = true;}
bool IsExiting() const {return exiting_;}
boost::shared_ptr<State> GetCurrentState() const {return stateStack_.top();};

private:
std::stack<boost::shared_ptr<State> > stateStack_;

typedef std::map<std::string, CreateNewStateCallback> theAvailableStatesTypedef_;
theAvailableStatesTypedef_ theAvailableStates_;

bool exiting_;

// TODO : Hack until improve inputmanager
bool changedThisFrame_;
};

typedef Loki::SingletonHolder<SingletonStateManager> StateManager;



And then the state base class, from which all game states are derived:


#pragma once

#include "entitymanager.h"
#include "inputmanager.h"

#include <string>
#include <vector>

class State
{
public:
State(void);
virtual ~State(void);

virtual void OnEntry() = 0;
virtual void Update() = 0;
virtual void OnExit() = 0;

virtual void RegisterInterestKeyboard(const std::vector<int>& interestingCommands, CanBeControlledByKeyboard* interestedParty);
virtual void RegisterInterestMouse(const std::vector<int>& interestingCommands, CanBeControlledByMouse* interestedParty);
virtual void ProcessInput();

EntityManager& GetEM() {return entityManager_;}

protected:
// This setup allows easy pushing and popping of states
EntityManager entityManager_;
InputManager inputManager_;
};



And finally, a state implementation:


#include ".\stategamepathfind.h"

#include "statemanager.h"
#include "logmanager.h"

#include <vector>
#include <boost/any.hpp>

// Register this state with statemanager
namespace
{
boost::shared_ptr<State> RegisterStateGamePathFind()
{
boost::shared_ptr<State> thisState(new StateGamePathFind);
return thisState;
};
const bool registerStateGamePathFind = StateManager::Instance().RegisterState("PathFind", RegisterStateGamePathFind);
}


StateGamePathFind::StateGamePathFind(void)
{
}

StateGamePathFind::~StateGamePathFind(void)
{
}


void StateGamePathFind::OnEntry()
{
LogManager::Instance().Write(1, "Starting PathFind State");

entityManager_.LoadLevel("./resources/level1.txt");

std::vector<boost::any> theVec;
theVec.push_back(D3DXVECTOR2(50, 50));
theVec.push_back(0);
entityManager_.PushNewEntity("Player", theVec);

theVec.clear();
theVec.push_back(D3DXVECTOR2(750, 550));
theVec.push_back(1);
entityManager_.PushNewEntity("Player", theVec);

theVec.clear();
theVec.push_back(D3DXVECTOR2(50, 550));
theVec.push_back(2);
entityManager_.PushNewEntity("Player", theVec);

theVec.clear();
theVec.push_back(D3DXVECTOR2(750, 50));
theVec.push_back(3);
entityManager_.PushNewEntity("Player", theVec);
}


void StateGamePathFind::Update()
{
entityManager_.UpdateEntities();
entityManager_.RenderEntities();
}


void StateGamePathFind::OnExit()
{
LogManager::Instance().Write(1, "Killing PathFind State");
}



It's still a bit hacky in places, and there's some stuff that I don't like yet, but it's working for me at the moment. Plus I never really got my head around the kernel based system - I can never work out how to compartmentalise my tasks. Maybe one day.

HTH,
Jim.

Share this post


Link to post
Share on other sites
To me, the most efficient game loop is the one where all of your states are handled like ingame events. My menu is drawn using the exact same control path as any other part of the game, sure some systems aren't needed for things like menus and endgame sequences etc [like scene logic, which is pluggable in my engine, so you just swap it to the menu logic from the game logic], but these things are less time intensive than the ingame counterparts.

Also, because I use the same path as when I render the game, I can make my menus do anything that the game can do, and the menus receive all of the benefits of optimisations made to make the game run quicker.

In fact, I think that this is how games like UT2004 work with their menu systems [I remember that the introduction sequence with the nvidia branding and then the fades of the epic logo were done as an ingame map. I think that the menus might also have been set up as preconfigured huds, but I'm not sure].

Anywho,
//end rant

CJM

Share this post


Link to post
Share on other sites
I use one game loop per scene instead of one game loop to handle everything

i am using inheritance and its slightly different than this but here is an example of what I mean


class Level_mainMenu
{
graphics gfx;

int render();
int load();

int run(); // game loop is in here
};

// so it would be one class for each level or scene

WinMain()
{
Level_mainMenu mainmenu;
Level_scene1 level1;
Level_scene2 level2;

int x = mainmenu.run(); // run the main menus game loop

switch(x)
{
case 1:
{
level1.run(); // level 1 has its own game loop
break;
}
case 2:
{
level2.run(); // and so does level 2
break;
}
}
}

Share this post


Link to post
Share on other sites
Sign in to follow this  

  • Advertisement
×

Important Information

By using GameDev.net, you agree to our community Guidelines, Terms of Use, and Privacy Policy.

We are the game development community.

Whether you are an indie, hobbyist, AAA developer, or just trying to learn, GameDev.net is the place for you to learn, share, and connect with the games industry. Learn more About Us or sign up!

Sign me up!