Saturday, November 14, 2015

Game Engine Design 101: Component Based Systems

Hey all,

I often find myself answering questions about how to design a game engine, what a game engine is like, what to start with, etc. etc.

So, as of today, I'm starting a 101 series on designing a game engine.

The good news: You can make a game engine by yourself!
The bad news: It's hard work!

From here I will assume a few things:
  1. You have Visual Studio, Code::Blocks, XCode, Eclipse, or some other IDE (Integrated Development Environment)
  2. You know how to use said IDE.
  3. You have a grasp on C / C++.
If your grasp of C / C++ is kinda okay, or meh, or whatever, then you're okay. If you want a primer on that let me know, I may write a 101 on that.

Before I get started, all of this code (from here on out) will be referenced from my game engine here (and it's open source!): JFramework

So, without further delay, let's start the tutorial.

Two GameObjects: Character and Egg.

Every object in a game is known as a GameObject, which are built up of Components.

"What are components?", I hear you ask. Why, they are the building blocks of GameObjects!

"You said that earlier..." you may say. I will follow up with this: What would a GameObject contain?
  • A position? A rotation? A scale? An alignment on an axis? (All of these can be combined into what's known as a Transform)
  • A hitbox? A hurtbox? Mass? (Known as a PhysicsObject)
  • Textures? Draw mode? (Known as a Surface)
How do you get all of these things to have such unique features, yet keep the code easy to read in the future?

Easy, we use Component based design to solve this.

The main paradigms of Component based design are:
  1. All things that a GameObject can contain will derive from the Component base class
  2. Inheritance will be kept to an absolute minimum. (Ideally no deeper than 1 level)
Without further ado, some code:

This is what our base class will look like. Every component will derive from this class and implement the methods that are marked as "virtual".

Each "virtual" method is set "= 0" so that when anything derives from our base class, those methods MUST be implemented. This is known as creating an abstract class, by the way.

Each Component will be aware of its owner, which is a GameObject, and its unique identifier, for searching purposes.

What will our Transform class look like? Simple, like so:

Notice the those methods at the bottom? How they're not set to "= 0" like our component class? We are implementing them, as we should / have to. Some of which in a .cpp file, which you can see in Source/Components/Transform.cpp in the project I already linked.

"What's the point of this?", you may ask. Let me show you the GameObject class and how it utilizes Components:

Notice how our GameObject class has a vector of Components? Almost like it's built up from them... right? Imagine building a GameObject if it had a specific Surface object, a Transform object, a PhysicsObject object, it would look messy and would be hard-coded, not ideal.

In this example, an object can be missing components and still work. What if a GameObject doesn't need a hitbox? Easy, just don't give the GameObject one!

What we now have is an interface in which Components with many different features can be responsible for updating and managing themselves when need be.

How do I update our Components? Also easy! Remember that "virtual" method named "Update" in our Component class? We're gonna use it, yep.

Now, no matter how many Components our GameObject has, this method will always scale to update every Component.

I'll end the lesson here, next time, I'll discuss how to utilize these Components in order to draw, move, and collide GameObjects. If you didn't quite understand, it'll all come together then, I'm sure.


No comments:

Post a Comment