In the last two years I was mainly interrested in exploring C++. One result of my learning is the subject of this post. I started to reimplement the snake game using C++11 for the LED cube. Later I divided the code into two sections. The general part became a base library for creating games or animations. The snake specific code is now only an application, which is based on the general library part. Later, the famous 2048 game was also implemented on top of the library.
The basic classes and interfaces of the library are:
- Point: holds one LED’s position and brightness level. The position is comparable with operator ==; collection of _Point_s passed through the higher level constructs
- Display: pure interface for the cube. Used to send the content to the LED cube driver. The real cube’s driver is pluggable here (CubeDisplay), but there is also a debugger class to dump the content’s coordinate’s to the screen (DisplayDumper)
- Schedulable: interface for the classes which produces variable content
- ClockSource: base class for scheduling. Holds a collection of Schedulable objects. Two inherited solution is implemented:
- TimerClockSource: notifies all Schedulable objects in predefined time intervals
- CondVarClockSource: an event driven solution, may used for example to notify the Schedulable objects on keypress
- Renderable: interface for content supplier objects; classes based on it has to provide Point collections at any time representing their content
- Renderer: holds a collection of Renderable objects and one Display; inherits Schedulable, so that the ClockSource will trigger the redrawing of the cube’s content as well; collects all Renderable objects’ contents and passes it to the Display when scheduled
- ClockDivider: a Schedulable helper class which holds a real Schedulable object and a division rate; after passed into the Renderer, it will only pass a divided amount of update requests to the given real Schedulable objects; this way the update rate can be fine tuned between the content suppliers
- Controllable: pure interface for objects, which content is based on some expected physical Direction (up,down,right,left,forward,backward)
- KeyboardInput: instructs a Controllable object based on keypresses (wasd, / and ‘); keyboard events are waited in a separate thread
3D snake game
The snake game’s classes are the following:
- SnakeFood: supplies one blinking LED on the cube, which the Snake should catch; it is:
- Schedulable (has to replace itself on random place if the Snake didn’t reached it in a given amount of schedule cycles)
- Snake: supplies the snake’s body; it is:
- Schedulable (to keep going in the current direction)
- Controllable (direction is changed based on keyboard presses)
- SnakeController: the main controller of the game; it counts the score, checks if the Snake reached the SnakeFood, etc; it is:
The main function acts as a factory for the game. It creates a Snake, a SnakeFood, passes them (with the help of ClockDivider_s) to a _Renderer together with a CubeDisplay. Creates a KeyboardInput to control the Snake, gives the Snake and the SnakeFood to a SnakeController, etc etc. Then calls the TimeClockSource_s loop method and the game starts. The gameover is determined by a helper class, namely a _SnakeExitConditionClass, which passed into the TimeClockSource and checked after every schedule round.
An other example application is the LED cube adaption of the famous 2048 game. The values are represented by lighting LED columns at the center of the cube. Each column’s height is the number, which 2 has to powered to get the number value of the place. Hard to imagine, but really easy to play the game this way. Basically if two columns has equal height, the columns can be merged together and the result will be a one unit taller column, representing the twice bigger number in the grid. The classes are:
- GameTable: holds the gameboards’ state and gives interface to alter that state. The core logic if borrowed from clinew’s C implementation of the game, thanks for it
- GameRenderable: connects the GameTable to the Renderer by extracting the table content to column data displayed on the cube; it is Renderable
- GameController: core game logic; through the Controllable interface it controls the GameTable
- GameExitCondition: similarly to the solution in the snake game, this class determines if the game is over (either by win of lose) of the user wants to quit
Just like in the snake game, the main function only wires the game parts together and let the ClockSource to react to the user’s keypresses. That means that here the other, CondVarClockSource is used because the content need to be only rendered when some keypress occured. I’ve created an UML diagram to represent the 2048 game classes:
Code is on the github. It is developed as Eclipse CDT projects under Linux.
You can also find some unittests in the repo written in GoogleTest. It was easier to reproduce corner cases with UT instead of eg. solve the 2048 on the cube just to test if the application determines the winning situation :).