Sign in to follow this  

An efficiant game loop

This topic is 4698 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
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
Actually, there are indeed commercial, AAA games which implement the standard "noob" state-based loop... Even for a really complicated game, I'd be surprised if you need more than a handful of states.

Also, instead of using a switch statement, what you could in fact do is just have 1 game loop.... but then, the current game state could enable or disable certain parts of the system.

For example,


if( g_GameState == GAME_STATE_PLAYING )
{
UpdateWorld();
RenderWorld();
}

ScreenManager::Update();
ScreenManager::Render();




So basically, you update and render the world only if a game is in progress. Also every frame you render what's in the ScreenManager... The screen manager could contain a stack of Screens (which are pushed or popped as necessary)... So this little code snippet could be used for either the title screen, or the game itself.

For the title screen, you would create a class derived from Screen, and push it on to the screen stack. That's it- now the code I posted above will take care of showing the main screen. When you click on "Start game" from the title screen, then you could pop the title screen, and push on the screen which contains the game's HUD, and set the game state to GAME_STATE_PLAYING.

I dunno if this is the best way to do it, but it works :) It was used on a commercial RTS game of several hundred thousand lines of code so I don't think you'd run into any problems with it...

roos

Share this post


Link to post
Share on other sites
I implement my game loop using the following method:

1) Have a abstract class called GameMode which all of the "game modes" inherit from (map mode, boot mode, battle mode, etc). There are two virtual functions to this class, called Update() and Draw().

2) Each game mode class inherits from the GameMode class and implements the Update() and Draw() functions

3) keep a stack of GameModes, where the GameMode on top is the currently active mode.

4) Call the Update() and Draw() functions on the GameMode on top of the stack.


Here's the main game loop with this method:


// This is the main loop for the game. The loop iterates once every frame.
while (SettingsManager->not_done) {
// 1) Draws the screen to the back buffer
ModeManager->GetTop()->Draw();

// 2) Displays the new frame on the screen
VideoManager->Render();

// 3) Process all new events
EventHandler();

// 4) Updates the game status
ModeManager->GetTop()->Update(SettingsManager->UpdateTime());

// 5) Reset our key and joystick press and release flags
SettingsManager->ResetInputFlags();
} // while (SettingsManager.not_done)



And that's it. I pass the number of milliseconds that have passed since the last loop to the Update() function, because our engine uses time-based movement to compute how much/how far to update the game's status.


I can provide the definitions/implementations of the ModeManager, GameMode, and SettingsManager if anyone is interested in it.

Share this post


Link to post
Share on other sites
I basically use the stack.

I keep a stack of States, where each state has its own Input, Update and Render functions, much like Roos describes. Keeps everything very organized, and it works like you would expect a game to.

start game:

-push menu state to stack
-input/update/display menu
-player chooses options
-push option state to stack
-input/update/display options
-player presses escape (or whatever)
-pop options from stack
-input/update/display menu
-player chooses to play game
-push game state to stack
-input/update/display game
-player has enough, so presses F1 (or whatever)
-pop game state from stack
-input/update/display menu
-player chooses quit
-pop all, quit




Share this post


Link to post
Share on other sites
Here's a straight C way of doing it with callbacks. There is no processing done until you actually change the state...


typedef void (*TickCallback)();

BOOL gbRunning = TRUE;
TickCallback gpfTickCB = IntroTick;

enum GameState
{
GAMESTATE_INTRO,
GAMESTATE_GAME,
GAMESTATE_MENU,
}

void SetState(GameState eState)
{
switch(eState)
{
case GAMESTATE_INTRO:
{
gpfTickCB = IntroTick;
break;
}
case GAMESTATE_GAME:
{
gpfTickCB = GameTick;
break;
}
case GAMESTATE_MENU:
{
gpfTickCB = MenuTick;
break;
}
}
}

void IntroTick()
{
printf("intro");
if (bExit)
{
SetState(GAMESTATE_GAME);
}
}

void GameTick()
{
// game tick etc..
}

void MenuTick()
{
// menu tick etc..
}

void main()
{
while (gbRunning)
{
gpfTickCB();
}
}



Of course, you probably want to handle things like shutting down and initialization when you change the state. But you get the idea...

Share this post


Link to post
Share on other sites
Quote:
Original post by X-0ut
Personally I like to use function pointers :)

That makes a lot of sense, since you avoid the classic switch statement.

My first attempt of a game was in Java, and since there aren't function pointers there, I "registered" States in the main game object. The states are an implementation of a common interface that have update(), render(), process() -or whatever you want to call it- methods. Every State change registers the actual state-object the game is changing to, so the task os processing a state is a simple call to the methods of a member of the game object.

Share this post


Link to post
Share on other sites
As far as I know, function pointers are not neccessairely faster than switch statements. But they look nicer :)

I use 2 threads for my games, the main thread for drawing, so the framerate can be as high(or low) as possible, and one for game logic, which runs at constant speed, e.g. 50 FPS.

I also use a architecture of game states, all inherited from one abstract base game state class, and every game state has a method "draw" , called by the main thread and one "process", called by the game logic thread.

Share this post


Link to post
Share on other sites
Quote:
Original post by DirectXFreak
I have a question regarding the noob method of a game loop. Is using a switch statement slow? Or does it just get cluttered...


The problem with switch statements is that their pretty static if you want to add more states you have to go back to the switch statement and keep adding more cases.

This is solved by using the factory method, each time you create a new state you register this state with the StateFactory and a unique Idetnifier for that state e.g. "MenuState" etc. This gets rid of that the need for that static switch statement which is replaced by a more fluid registration system. This looks pretty much like JimPrice's solution, which is very similar to the way I handle game states and the main loop.

Share this post


Link to post
Share on other sites
Quote:
Original post by FReY
Here's a straight C way of doing it with callbacks. There is no processing done until you actually change the state...

*** Source Snippet Removed ***

Of course, you probably want to handle things like shutting down and initialization when you change the state. But you get the idea...


That is EXACTLY how I perform my game logic processing. Similar in nature to the switch statement, but a lot cleaner. I suppose you could extend the functionality of that method by having multiple function pointers, each tracking the state of a different task. Like, one function pointer only points to rendering functions, one only points to resource loading, one to game logic, etc. And each of these pointers has it's own state variable, so instead of having 50 states each with its own mix of rendering and game logic, you have maybe a few different rendering states and a few different game logic states, the actual result of the loop being the combination of states. It's a bit more flexible than the method I currently use (and plan to change) if you have no need for the complexity of a kernel-based or stack-based system, not that those methods are bad.

Share this post


Link to post
Share on other sites
Hang on a minute everyone - why spend so much time trying to speed up the game loop - it is the one part of the game that runs the least and hence the part you should spend least time on. When optimising you should go for those lower level functions not the ones that run just once a frame. A simple 'noob' state change is fine performance wise as this is not where any bottleneck will occur.

Share this post


Link to post
Share on other sites
It isn't neccesarily about efficiency. It's also about the most optimal solution to the programmer. The noob game loop is fine performance-wise (no one has said otherwise), but it becomes extremely cumbersome to manage and to organize in a game with the possibilities of many many states. A kernel system or a stack-based function pointer system won't help much in performance, but it'll make organization of the code much easier in a lot of large projects.

Share this post


Link to post
Share on other sites
Is it really that cumbersome? Honestly, sometimes you can get so boiled down with OO details that you never get around to finishing your game.

For my latest project, I've gone ahead and implemented the 'noob' loop, the noob 'everything' in fact, and progress has been great. Yes, I might have to add a new case to a switch statement everytime I want to add a state, but does that honestly take more time than implementing a new state subclass? Don't think so.

- ben

Share this post


Link to post
Share on other sites

This topic is 4698 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.

Create an account or sign in to comment

You need to be a member in order to leave a comment

Create an account

Sign up for a new account in our community. It's easy!

Register a new account

Sign in

Already have an account? Sign in here.

Sign In Now

Sign in to follow this