Jump to content

  • Log In with Google      Sign In   
  • Create Account

We need your feedback on a survey! Each completed response supports our community and gives you a chance to win a $25 Amazon gift card!


Main game loop design


Old topic!
Guest, the last post of this topic is over 60 days old and at this point you may not reply in this topic. If you wish to continue this conversation start a new topic.

  • You cannot reply to this topic
6 replies to this topic

#1 nsc92   Members   -  Reputation: 106

Like
0Likes
Like

Posted 03 June 2012 - 04:00 PM

So far, I've made a few small simple games in the past using visual c++ and Windows GDI. More recently in the past year, I've been wanting to develop more complex games and have learned through books and online tutorials about AI techniques and I have a decent understanding of how to use DirectX.

My problem is I don't know how to structure my main game loop. Essentially, I want to create my own simple game engine. I know there are plenty of game engines out there, but I want to do this as a learning experience more than anything.

Here are the three main things I know that I need in my loop.
  • Graphics update -- runs more or less as fast as it can
  • Physics update -- from what I understand, this should run every predetermined set period of time to limit the number of odd physics related bugs that I see.
  • AI update -- this takes care of computer "strategy", pathfinding, etc, and should only be run much less often when compared with the graphics or physics updates.
Based on what I've ready, the sudo code way of how I imagine this going looks like this:
#define PHYSICS_DELAY 30
#define AI_DELAY 500
.
.
.
while(!exit)
{
   if (time_since_last_physics_update > PHYSICS_DELAY)
		 run_physics_update();
   if (time_since_last_ai_update > AI_DELAY)
		 run_ai_update();
   run_graphics_update();
}

However, this means that the time required to make it through a single loop is highly variable. It might just run the graphics update (hopefully not because from what I read, the physics should be updating about twice as fast as the graphics) or it might run all three updates.

I'm sure I'm missing something because this doesn't seem right to me at all.

Could someone please explain to me how a game loop should work? Everything I've seen up to this point that tries to explain it leaves out one part or another.

Sponsor:

#2 SeiryuEnder   Members   -  Reputation: 199

Like
1Likes
Like

Posted 03 June 2012 - 04:21 PM

That's a highly procedural approach.
Generally my update loop will go something like (this is complete pseudocode mind you...):

void Game::Update( float _delta )
{
	 m_Input.Update();
	 m_ObjectManager.Update( _delta );
	 m_Sound.Update();
	 m_Render.Update(); // <== Does the actual rendering
	 m_Events.Update();
}

void Object::Update( float _delta )
{
	 HandleInput();
	 UpdateAI( _delta );
	 UpdatePhysics( _delta );
	 UpdateRenderInfo(); // <== Update render information, doesn't actually render the object
}

Bear in mind there's a really good chance I'm missing something, but the logic behind this ordering is as follows:
Update Input first, as Input may raise events and needs to be readily accessible to other systems.
Update Objects second, they may create/play/stop audio assets and have to tell the renderer what to do.
Update Events last so that any events raised by other systems can be handled.

If I could offer some advice though... Don't worry about throttling yet. Worry about optimization once you get things working.

Edited by SeiryuEnder, 03 June 2012 - 04:35 PM.


#3 nsc92   Members   -  Reputation: 106

Like
0Likes
Like

Posted 03 June 2012 - 04:58 PM

Ok, thanks! This helps a lot.

So just a few last questions to clarify for myself:
  • what would you have HandleInput() do within an individual Object::Update?
  • what are some examples of what m_Events.Update() might include?
  • If opjects are being moved one at a time, where would collisions be handled? Would that be within m_ObjectManager.Update after all the individual Object::Update methods have been called?


#4 SeiryuEnder   Members   -  Reputation: 199

Like
1Likes
Like

Posted 03 June 2012 - 05:34 PM

  • what would you have HandleInput() do within an individual Object::Update?


That depends on the object.. Generally you have an ObjectManager that contains a list of Object*.
Then you have other objects that derive from the parent object and do different things.

Something like this (untested code):
class Animal
{
public: virtual void Talk() = 0;
};

class Cat : public Animal
{
public: void Talk() { say( "Meow" ); }
};

class Dog : public Animal
{
public: void Talk() { say( "Woof" ); }
};

class Bird : public Animal
{
public: void Talk() { say( "Chirp" ); }
};

class AnimalManager
{
public:
	 Add( Animal* _animal ) { m_Animals.push_back( _animal ); }
	 AllTalk()
	 {
		  for( int i = 0; i < m_Animals.size(); ++i )
			   m_Animals[i]->Talk();
	 }

private:
	 std::vector<Animal*> m_Animals;
};

int main()
{
	 Cat cat;
	 Dog dog;
	 Bird bird;
	 AnimalManager mgr;

	 mgr.Add(&cat);
	 mgr.Add(&dog);
	 mgr.Add(&bird);

	 mgr.AllTalk();

	 return 0;
}

  • what are some examples of what m_Events.Update() might include?


Simple Event System

  • If opjects are being moved one at a time, where would collisions be handled? Would that be within m_ObjectManager.Update after all the individual Object::Update methods have been called?


Different people handle it different ways. Some people move the collision check out of the object and make it part of the object manager. Some people do it through events, and keep track of objects they've collided with that frame so that they don't multiply collide. There are other solutions as well. Do a little Googling and find a solution that works for you.

Edited by SeiryuEnder, 03 June 2012 - 05:35 PM.


#5 aeroz   Members   -  Reputation: 171

Like
1Likes
Like

Posted 03 June 2012 - 05:36 PM

Have a look at this article:
http://gafferongames...-your-timestep/
It's from a game physics tutorial but this particular article is generic. It was quite helpful for me.

Edited by aeroz, 03 June 2012 - 05:44 PM.


#6 nsc92   Members   -  Reputation: 106

Like
0Likes
Like

Posted 03 June 2012 - 05:56 PM

Thanks! This is all really helpful information to get me started. I'll take a look through all these articles and give all this a try here soon.

#7 Cygon   Crossbones+   -  Reputation: 1157

Like
1Likes
Like

Posted 05 June 2012 - 01:45 AM

I _really_ _strongly_ _passionately_ hate event systems. One day I'm going to write an entire blog post dedicated as to why they're terrible in my opinion :)

I'm using fixed time steps as well for most of my works. In multiplayer, it's a must to achieve identical results on all system and in single player games, it makes a lot of situations more controllable (like physics libraries which, despite all the clever math, tend to produce vastly different outcomes depending on the amount by which simulation time is advanced).

To keep my main loop simple, I'm using a small class that encapsulates most of the math involved for the time stepping:
[source lang="cpp"]void MyGame::RunGameLoop() { SteppedTimer timer(Clock::GetSystemDefault()); timer.SetStepFrequency(60); while(!this->endRequested) { // Update the state of the game world GameTime timeStep; while(timer.TryAdvance(timeStep)) { Update(timeStep); } // Draw the game world GameTime frameTime = timer.GetFrameTimeAndReset(); Draw(frameTime); }}[/source]

I only moved the calculations for the delta time and time steps into a class so I can use more expressive names inside my main loop. Still, if you're curious, I posted the code for the SteppedTimer class in one of my blog posts: Perfectly Accurate Game Timing.
Professional C++ and .NET developer trying to break into indie game development.
Follow my progress: http://blog.nuclex-games.com/ or Twitter - Topics: Ogre3D, Blender, game architecture tips & code snippets.




Old topic!
Guest, the last post of this topic is over 60 days old and at this point you may not reply in this topic. If you wish to continue this conversation start a new topic.



PARTNERS