Our primary goal in this learning guide was to illustrate how to use the TwoPlayerGame Library to create your own two player games. The library code and example programs are extensively commented with detailed descriptions of each of the object classes and methods used in the game engine. In this section of the guide we will go over some of the basics of what you will need to do to create your own game.

We will not be covering the details of how to use the Adafruit_Arcada_Library to display graphics or to take input from the joystick and buttons. For details see this section of the PyGamer learning guide titled Arcada Library.

As mentioned earlier there are 3 example games provided. "Tic-Tac-Toe", "Battleship", and a debugging game consisting only of text input and output to the serial monitor. When developing your own game you might want to start by creating a copy of one of these 3 example games and editing out our game procedures and entering your own code in its place. We developed "Tic-Tac-Toe" by editing a copy of the demo and debugging game and in turn created "Battleship" by editing a copy of "Tic-Tac-Toe".

The library consists of 4 object class definitions. These are base classes with some abstract and virtual methods. You will have to create a derived class using this base class. The base classes handle all of the basic work of transmitting packets of data between the two devices and maintaining the general flow of the game. This means you can concentrate on creating the game specific portions of your code and let the game engine do the heavy lifting for you.

Here are the 4 base classes in the system:

  • baseRadio -- An object that handles all radio communication between the devices.
  • baseMove -- An object whose contents is transmitted to inform your opponent of your move.
  • baseResults -- An object that returns information to you regarding the results of your move.
  • baseGame -- The main object of the game engine. Handles basic game flow logic.

There is an additional object basePacket from which baseMove and baseResults are derived but you will not need to make your own extended version of it.

We have already designed an extension of baseRadio for the RF69HCW packet radio feather wing. If you are using that packet radio you can simply use our provided code. Eventually we hope to provide other options or perhaps one of you can design your own. We would welcome it as a commit to our GitHub repository.

In the following pages we will describe each of these classes and how you can extend them to implement your game.

Your Main Program

Let's take a quick look at our main program which is almost identical for all of the games. It will illustrate how the different parts of the game engine connect together to implement your game. Here is a complete listing of tic-tac-toe.ino.

Download: file
 * Two Player Game Main Program
 * Compile and upload to one device using IS_PLAYER_1 true and compile and upload
 * to the other device using IS_PLAYER_1 false. This is the only difference between 
 * the code on the two different machines.
 * A simple tic-tac-toe game.
#define IS_PLAYER_1 true

//Basic game engine code
#include <TwoPlayerGame.h>

//Code for RF69HCW packet radios
#include <TwoPlayerGame_RF69HCW.h>

//All of my code is here
#include "tictactoe.h"

 * The Game object requires pointers to Move, Results, and Radio objects. Create
 * an instance of each of these and pass their address to the game constructor.
RF69Radio Radio;
TTT_Move Move;
TTT_Results Results;
TTT_Game Game(&Move, &Results, &Radio, IS_PLAYER_1);

void setup() {
  Game.setup();           //Initializes everything
void loop() {
  Game.loopContents();    //Does everything

We have already discussed the use of the IS_PLAYER_1 flag.

The basic game engine code is included via TwoPlayerGame.h.

The packet radio code for the RF69HCW is in TwoPlayerGame_RF69HCW.h. It defines an object type RF69Radio.

Finally we include the file containing our game code in this case tictactoe.h. This code defines 3 object classes: TTT_Move, TTT_Results, and TTT_Game.

We then need to create an instance of the Radio, Move, and Results objects. We then pass their addresses to the constructor for the Game object along with the IS_PLAYER_1 flag.

From there you can see that the only item in our setup() function is a call to Game.setup(). Similarly the loop() consists of nothing but a call to the Game.loopContents() method.

This guide was first published on Jul 07, 2020. It was last updated on Jul 07, 2020.

This page (Creating Your Own Games) was last updated on Mar 16, 2021.

Text editor powered by tinymce.