For about two years I've had a home game engine project, this has just been a little sandbox in which I have been able to experiment with graphics API's, systems, memory, threading models and other such "Game Engine" like things; it has simply been a learning aid to keep myself invigorated.
You see I work on a AAA game engine, for a game yet to be released and that engine does a lot of things its way, tens of engineers work on it in the "Engine" space.
I therefore wanted a space of my very own in which I could explore, the key piece I have done which ape that real engine have been using an Entity Component System.
My Ecs is quite different from the one at work, my focus is on game objects being made of many entities and those entities carrying discrete components to add their functionality. A very data driven ideal.
A great example might be simply putting a model on screen, lets take a complex object. The Missile Launcher as a case study and we will be looking at the code before images from the running application.
To place the game object entity I create the Object structure, filling it out and assign it a transform and launcher state instance, these components give the engine a key into the nature of what this entity is. There are many explanations of Ecs out there, but simply put we get an entity handle (an Id) and assign to it certain component types. The presence of these components then tell us everything we want to know about the entity:
This could be all we need for the entity, indeed this is a design decision I am yet to fully explore. However, in the actual code I immediately want the base model for the renderable to have this same transform.
Adding this is as simple as assigning more components:
The renderable and shader component are very strong indicators of quite how this works, an entity without these components will not ever draw.
In fact there are three components needed for the "Draw" system to pick up the entity and run the graphics API calls over the entity, these are the Transform, the Renderable and the Shader components; these three together indicate that this is something the engine will draw.
Systems in my engine do this with a view:
And the system simply iterates all the entities in this view and we have just those entities to show.
(At this point I know a bunch of you are lost, but lets just think of this like we've divided the thousands of entities in our game such that only those with these three entities will appear in our View).
We have right now though just got the object itself showing and the model showing is only the base, I want to rotate this base.... I have a component for that:
Assigning this component to the entity and the functionality this component brings is assigned to our launcher!
This is the key power of an Entity Component System, we can author discrete and well defined features as a component and which operate on the member data within that component and then assign it to any other entity we desire. Manually Rotating the entity around the Y (or up axis) is a good example.
Another might be the speed of a vehicle.
We however want to add a body model to our launcher object, our second model looks like this:
Adding a child entity to this launcher object we can keep all the components separate for the body than the base:
Because we have added this second renderable as a child (the parent being the launcher itself) the transform is hierarchical and the launcher now looks like this:
We want the launcher to carry missiles, but where to place them? Well, I have invented a "socket" system, that when you place a socket entity onto something you can find the socket and insert something into it...
And we can add new child renderables to these sockets, pointing to the missile model:
This activity is performed in my "LauncherUpdateSystem", lets look at the whole "Update" function:
We can see that for each launcher in the Launcher View (which is just any object with a components::LauncherState) and we know we can pull out that component and work on adding a missile if the launcher timeout has passed the reload time; calling AddMissileToSocket you can imagine looks for children of the launcher which have the components::LauncherSocket component type, and voila we have the transform from the base, the body and the socket to place the missile.
Putting all this together and we get:
You can see the component have their own UI (ImGui) controls, that one has complete control over the whole entity and each individual component.
And the parent-child relationship between different entities within the object allow for really complex game objects to be described in fairly quick turn around times.
Another example of this is my test vehicle, which has a rolling wheel to match the movement; the movement belongs to the vehicle, which is a game object with a renderable. But the wheel itself is a child, it has a renderable too, but also its own transform and its own "Wheel" component, which has the discrete maths for the circumference and rotation.
The effect of rotating the wheel per frame is even its own other component, so that we can assign the same "Rotate per frame" component to anything in our scene.
With all this technology in place, the basic rendering engine as you can see (in OpenGL 4.3) I am now placed to expand the amount of content and start to build an actual game.
You see a game engine, or any engine, can only really fulfill its potential and for me complete the learning round trip by creating and driving something, for me this will be a game.
The missile launcher is perhaps a hint as to the kind of game I am picturing. but the models I am working on as of new years night are perhaps stronger clues:
The Entity Component System has been a key implementation for my to progress onto content creation and, besides a few performance fears when I scale up the combat scenes I hope to deliver, I believe it to be the best choice for fast and easy iteration on a theme.
The mental leap of a game object being one or many entities, each with their own features dividing up the mammoth task of implementing all the features of a game for myself as a solo developer has been absolutely key.