As written in the last Sideletter, I will introduce in this Newsletter a better and more improved Game Engine before we continue with the Game-related stuff.
The “New” Game Engine
In the least articles, I used code that was written in pure “C” and showed the basic principles of how to create vector games (for the PiTrex).
On the feature side, the previous approach and this new engine have many things in common:
Load from the same level file (
level1.txt
)Adding game objects (Boxes vs. Object models)
Structure game in
Create(), Update()
andDestroy()
functions
But the new game engine has some advantages which I will describe in more detail below.
Use of Object Models
What you see at first is that we no longer use boxes (draw by lines) but a more modern approach to using triangles (draw by lines). This means we can use any Model File Format created by Blender or similar programs. Since we don’t use materials (color or textures), OBJ files are enough to describe the geometry of the objects. Such a file looks like this:
# Blender v2.91.2 OBJ File: 'bullet.blend'
# www.blender.org
o Cube_Cube.005
v 0.052417 -0.061201 -0.083113
v 0.052417 0.061201 -0.083113
v 0.052417 -0.061201 0.083113
v 0.052417 0.061201 0.083113
v -0.052417 -0.061201 -0.083113
v -0.052417 0.061201 -0.083113
v -0.052417 -0.061201 0.083113
v -0.052417 0.061201 0.083113
s off
f 1 2 4 3
f 3 4 8 7
f 7 8 6 5
f 5 6 2 1
f 3 7 5 1
f 8 4 2 6
The advantage of this file format is also that it is quite easy to read and even write by hand. We can parse this OBJ file as we do for the level file by reading line by line and checking the first character.
For our purposes, we are just interested in the lines starting with v and f.
v
- Indicates a line with a geometric vertice, Which is followed by x,y, and z coordinatesf - Indicates a line with a vertex index that matches the corresponding vertex elements of a previously defined vertex list. Each face can contain three or more vertices.
That’s all we need to define a game model and this work is done in rb_mesh.cpp
. Of course, we need to optimize this a bit later since we don’t really want to draw all lines of the triangle but just the ones that are needed to describe our geometry.
Game States
The second enhancement of the new game engine is the usage of game states. What are games states?
A game has different states, like an intro, play, and of course, also win or lose a game. This is implemented as a state machine and allows us to focus on different situations. For example, pressing a button in the intro games state means that we want start the game but during playing the game I want to fire a bullet when pressing the same button. This shouldn’t be mixed with the Create(), Update()
and Destroy() functions. Those are the (technical) states of the engine itself but not the game’s states. The game states are all handled in the Update() function (Our game loop)
A state machine looks something like this and we use events that trigger how we switch from one state to another. Events can be something initiated by the player like pressing a button, but can also be a technical trigger like a timer or even a game-related event like zero player lifes. This approach is also called a (Game-) Design Pattern and is widely used in games. In Vexxon, I use the following states:
GAME_INITIALIZE - The game is loading its content
GAME_INTRO - The intro screen is shown to the user. In Vexxon this is the rotation starship at the begin
GAME_PLAY - The player is playing a level
GAME_END - The level is finished and the outro scene is shown
Object-oriented approach
Last not but least I have decided to move forward with C++ and also an object-oriented approach. Of course, on the Vectrex itself, this is not very much approachable but since the code run’s on a PiTrex we have plenty of power and can therefore use the advantage of C++ and also structure the game and engine better in objects. Overall a more modern way of creating games that are also used in today’s games.
That said, I will not use all the latest features of C++, but all that helps to simplify programming the game.
Besides the fact that C++ and object-oriented approach is used the files and their functionality is quite similar to those before.
rb_engine.cpp
- The game engine itself. To implement a game we just derive a game class from it and overrideOnCreate()
,OnUpdate()
andOnDestroy()
. That’s all :)rb_file.cpp
- A helper class to load text files (OBJ and TXT)rb_level.cpp
- Load the game data from a file (ex.level1.txt
)rb_math.cpp
- All mathematical functions I use for 3D game programmingrb_mesh.cpp
- Load a model object file (ex.jet.obj
)rb_object.cpp
- Handles game objects and holds all datarb_types.h
- Basic types used by the engine
The “New” Game Class
Of course, also the game itself has slightly changed, mainly because I use now objects for each game object and game state. Other than that the approach is quite similar to the other one used before:
OnCreate() - Preload all the game objects we use in the game and create game objects. Also, the correct projection matrix and the camera are set here.
OnUpdate() - Depending on the different game states (see above) I do the following here:
GAME_INTRO - Show a rotating jet and wait until the user press button 4
All other states - Check the joystick and move the jet either up, down, left, or right. Also, we check if another game section can already be added (See also the description in Sideletter #4)
OnDestroy() - Nothing is done so far
That’s it for today’s Newsletter. In the next newsletters, I explain how we make this work on the PiTrex and improve the game step by step. The engine itself contains now all that we need to finish Vexxon :)
And as always: Find the source code here on GitHub.
The latest version is always in the src
folder and previous versions are archived in the archive
folder.