Okay, so let’s discuss the plan. What does my game engine need? What game components are essential for building a very simple game? Well, in fact most games that need their game and render logic updated regularly share a similar base structure.
Luckily, MonoGame already does most of the low-level stuff for us and provides us with a Game class that has methods for content loading, updating game logic and rendering that are called at the appropriate time. But of course, we don’t want to put all of our game code into this class. That’d be very poor design and – needless to say – it would make our code quite unmanageable. So we want to structure our code and divide our game into reoccurring components, or “Game Elements” as I will be referring to them, since the term “Game Component” is already defined in MonoGame/XNA. As I said, this is handled similarly in most games. We create some sort of scene or game state class that is responsible for managing all of our game objects like the player, enemies, GUI elements, environmental stuff (like a tiled map), basically everything that makes up one particular part or “scene” of our game. Our scene could be a level, it could be a menu, it could be a loading screen… You get the idea. 😀
But before I start trying to draw a picture with words, here’s an actual picture to gaze your eyes upon. This is a (non-standard) UML diagram of what I (and many others before me) came up with.
Of course this is just a first draft and the structure is most likely subject to change a bit. But let me tell you about what you’re seeing real quick.
As mentioned above, the scene contains all the game objects we currently need in our game and makes sure to update their logic and call their Draw method. We keep track of all game objects that currently live in our scene using a generic List. Also we have two more collections of type Queue. These store the game objects – or “Game Entities” as I refer to them – that are to be added to or removed from the Scene in this update interval. We need those collections because we cannot directly manipulate our List of Game Entities while we are iterating through them in our Update method. Therefore, we keep track of what Entities we want to dynamically add or remove and than do so after all existing entities have been processed.
A Game Entity is basically any object inside our Scene that needs to be updated. This abstract class can be used as a pattern for anything that brings some logic into our messy game world. The basic Game Entity is not intended to have a graphical representation on the screen but it can certainly implement some render logic if the developer (aka me) decides so.
The Actor class derives from the GameEntity class. The main difference between a simple Game Entity and what I refer to as an “Actor” is that an Actor has a Sprite that makes it visible on the screen. It can also optionally have a Sprite Animator which is used to, well, animate the sprite. More information on Sprites and Sprite Animators are to come… right now.
Well, anyone who has ever had something to do with game development knows what a Sprite is. It is basically a certain part of a texture. I feel like explaining it is kind of unnecessary since it is more like a general term. If you really want to know more about sprites and texture atlases… Google is your friend. 😀
This class is basically my simple implementation of a Sprite. It has a source rectangle which represents the texture coordinates of what part of the texture should be rendered. For reasons of convenience I also implemented the properties Index, Width and Height which are direct links to the source rectangle’s location and size.
I really wasn’t sure if I should also add properties for the Sprite’s position and scale. That way, I could only manipulate those values and used them when the Sprite is drawn to the screen. But eventually I decided against those since the Actor class that is the main user of the Sprite class already has such properties. And since I want the Sprite to sort of graphically represent the Actor, I decided that instead I wanted to pass the Actor’s position and scale to the Sprite’s Draw method. Maybe this will change in the future. I’m not entirely sure. We’ll see.
Sprite Animator and Sprite Animation
The Sprite Animator does exactly what it says. It animates the Sprite that is assigned to it. I. e. according to some predefined data set, it changes the texture coordinates (the index) of the Sprite at a certain interval. This data set can be found in the SpriteAnimation class. The Sprite Animator has methods for playing, pausing and stopping its animation. Originally, I implemented this behavior with a subclass of Sprite called “AnimatedSprite”. However, I quickly found that this was not a good design choice in my case. That is because the Actor class has a property of the type Sprite, remember? I wanted to leave it up to the developer to decide whether the actor should have a Sprite or an Animated Sprite. So far so good, Animated Sprite derives from Sprite, so it wouldn’t have been a problem to assign an instance of AnimatedSprite to the Sprite property of the Actor. The problem however would have been that every time I wanted to use the Sprite as an Animated Sprite, e. g. to update the animation or to play or pause it, I couldn’t have done so easily. Every Animated Sprite is a Sprite, but not every Sprite is an Animated Sprite. I couldn’t just “upcast” the Sprite to an Animated Sprite. So I figured, using an optional Sprite Animator was a better idea.
I created a custom extension for the MonoGame content pipeline that interprets a lua script and creates an instance of the Sprite Animation class from it (see my previous post). I will describe this in more detail in a future post, possibly including a video tutorial on how to create a content pipeline extension, because you wouldn’t believe how poorly documented this subject is. Tutorials about this are very hard to find. So I might possibly create one to fill this gap a bit.
I also use a few interfaces so far and there are most likely more to come. The ITimeScale interface provides a scaling value for all time based operations. The Scene class implements this interface to provide a global time scaling value, that is passed to all of the Game Entities. I plan to use this to manipulate any calculations that rely on the time that elapsed between the current frame and the previous one (delta time). This way I can easily achieve effects like slow motion or game pause.
The Game Entity class and the Sprite Animator class also implement this interface. This is so that I also have some sort of “local” time scale. In certain cases I might want to slow some entities down while maintaining or increasing the speed of others. That’s what this is for.
There is not much to say about the IDraw and the IUpdate interface. They are used by all the objects that implement the Draw and the Update method the exact same way. I couldn’t name them IDrawable and IUpdatable (to conform to the convention) because, again, those terms are already used by XNA/MonoGame for interfaces with slightly different purposes.
That’s it for now. I will be posting about some more details about the Himalaya Game Engine shortly. Remember: The source code of the project, including everything you just read about, can be found in my GitHub repository: