Please note that I don't update this web site anymore. You can visit my new personal blog at www.williamwilling.com.

Writing A Basic Game Engine

Thursday, July 21, 2005

Rejoice! An article about programming! :-)

I have no idea at what skill level you are when it comes to game programming. I'm going to assume you know your way around C++, so that I can focus entirely on the topic at hand. If I'm going to fast for you, just leave a comment and I'll explain as best I can. And if this stuff bores you: a future article will be of more interest to you, so just fast forward in time. Or go do something else for now.

Game loop

Just about every game follows the same basic structure. First, you read the player's input: keys pressed, movement of the mouse, stuff like that. Depending on what the input actually is, you send instructions to the game world. Second, you update the game world. This ensures that things that don't rely on user input get simulated as well: enemies, landslides, time of day. And finally, the scene is rendered to the screen, so the player can actually see what's happening.

It would be a dull affair if the game would end here. It'd be short, too. So, we need to repeat these steps again and again. And that is why this is called the game loop.

The game loop repeats three steps over and over: process input, simulate game world, render.

Before the game start, we usually need to run some initialization code, setting up libraries that we use and getting the game world in the proper state. When it's all done, we shut everything down proper. And that's how a game works, basically.

int main()
{
  Initialize();

  while (true)
  {
    Process();
    Update();
    Render();
  }
  
  ShutDown();
}

Creating an engine

While the above (pseudo) code is fine, we can make it a bit nicer by putting it all into the game engine. The game engine is a fairly simple creature; you only need to be able to start it and, in time, to stop it. (Pausing the game engine is a topic for another day.) After you start the game engine, it enters the game loop and drives your game from there.

First, let's start our engine. I prefer to keep my main() function simple. All it has to do is start the game engine and catch any unhandled exceptions so we can display an error message or write something to the log.

int main()
{
  try
  {
    GameEngine::Start();
  }
  catch (std::exception& e)
  {
    std::err << e.what();
  }
  
  return 0;
}

Note the call to the static member function Start(). Although there is only one place where you start the game engine, there are usually quite a few places from where you want to stop the game engine. That means that you need easy access to it. Passing around an engine reference can become quite cumbersome. A singleton is an option, but I like the above syntax better and we don't need lazy instantiation.

// this is what it looks like using a static member function
GameEngine::Start();

// using a singleton is slightly more contrived
GameEngine::GetInstance().Start();

You can implement the GameEngine class entirely with static members. It's not necessary, however. As long as you make your public members static, you can implement all private members as instance members. The code below shows how to implement this. As far as I know, there is no real difference between the two options (especially since we don't need inheritance).

class GameEngine
{
private:
  static GameEngine engine;

  void Run();

public:
  static void Start();
};

GameEngine GameEngine::engine;

void GameEngine::Start()
{
  engine.Run();
}

You have already seen the code for the game loop, so the implementation of Run() won't be much of surprise. The only addition is the isRunning variable. The code at the beginning of the article had the game loop running indefinitely. Obviously, we want to be able to stop our game at some point. A boolean is all it takes.

void GameEngine::Run()
{
  isRunning = true;
  
  while (isRunning)
  {
    Process();
    Update();
    Render();
  }
}

Stopping the game engine is easy: just set isRunning to false. Since we should be able to stop the game engine from outside the GameEngine class, Stop() needs to be public and static.

void GameEngine::Stop()
{
  engine.isRunning = false;
}

Initialization and shut down

This will go fast, so pay attention. Use the constructor for initialization code and the destructor for shut down code. There.

What about Process(), Update() and Render()?

The game loop still contains calls to functions that don't exist yet. Normally, you'll want to implement these functions in another class than GameEngine and that means they are outside the scope of this article. Next time, Gadget, next time.

Back to blog index

Comments

GBGames says:

Great post! I can't wait for the next one. I have seen that using a Singleton like I have can just make the game engine's functions harder to use. I have since tried to implement the game engine as a regular class, but found it awkward to pass a pointer to the engine in different methods. Your method looks fairly clean and easy to use so I'll likely adopt it myself. When you say that Process(), Update(), and Render() are implemented in another class, do you mean that GameEngine has these functions and they simply pass through to another set of classes to do the real work, or that those functions shouldn't actually be part of GameEngine in the first place?

Thursday, July 21, 2005 6:33 PM


Joost Ronkes Agerbeek says:

Those functions shouldn't be part of GameEngine. Instead, they should go in the class that holds your game state. My next article (which I'll probably post tomorrow) talks about the implementation of these three functions. A discussion on game states will have to what for yet another article, though. By the way, thanks for mentioning me on your blog. :-)

Thursday, July 21, 2005 9:14 PM


GBGames says:

Hey, what are blogs for? B-)

Thursday, July 21, 2005 11:08 PM


Jon Trainer says:

Thanks for this great post. I look forward to the rest of the series. It's interesting to note that your GameEngine class and methods look very similar to a WorkFlow / Business Rules engine I'm working on in C# and .NET for a client of mine.

Friday, July 22, 2005 2:28 PM

Tell me what you think

Since I'm not updating this site anymore, I disabled comments. You can visit me at my new site: www.williamwilling.com.