Thursday 3 May 2012

Persisting Hi Scores


When you switch off the battery pack on the GamePack or unplug it from your computer, the AVR chip loses power and you lose all your data stored in standard memory. This means we need to write the hi scores to an area of memory that will persist even when power is lost in order to recover them again when the game restarts. The ATMega2560 comes with 4kb EEPROM. Data stored here will remain even when power is lost.

The WinAVR development tools contains a library to read and write from EEPROM and it is pretty simple to use. See this blog post for some details about using it. The save/load functionality is encapsulated in the HiScores class in Tetris.

Here are some code snippets from this class:

You need to include the library:

 #include <avr/eeprom.h>  

Detecting if valid data has been saved:

 uint8_t data_flag = eeprom_read_byte((uint8_t*)DATA_FLAG_ADDRESS);  
   
 if(data_flag == VALID_DATA_FLAG){  
   return true;  
 }else{  
   return false;  
 }  

It is dangerous to assume that the data you want is present in the address you are looking in without some kind of check to confirm the data exists. For example if you run the game for the very first time, no high score data will exist. Who knows what data is written to the addresses you expect to read from. This can be solved by setting a single byte address to a value that indicates that valid data exists. If you read this address and the value is correct, you can assume the other addresses also contain valid data. If not, then you should not assume valid data in the other addresses. This mechanism makes resetting the hi score very easy as you don't actually have to erase the data, just set the flag to not be valid so the existing data will be ignored and overwritten (you can see this in HighScore.cpp).

Save a name and score to EEPROM:

 //indicate there is valid data to be read  
 eeprom_write_byte((uint8_t*)DATA_FLAG_ADDRESS, VALID_DATA_FLAG);  
   
 //save the player name  
 for(int i=0 ; i<player_name_length_ ; i++){  
   eeprom_write_byte((uint8_t*)(DATA_NAME_ADDRESS+i), player_name[i]);  
 }  
 //terminate the name array  
 eeprom_write_byte((uint8_t*)(DATA_NAME_ADDRESS+player_name_length_), '\0');  
   
 //save the player score  
 eeprom_write_word((uint16_t*)(DATA_SCORE_ADDRESS), score);  

An example set of data saved in Tetris is as follows:

   Address:  1    2    3   4   5   6   7
   Data:        9   B   O   B  \0   123

Where address 1 contains the valid check flag (where a value of 9 means valid data exists). This gives us a name of BOB (terminated by the null character) and a hi score of 123. The score is a stored as a 2 byte word.


Load the name and score back from EEPROM:

 //extra character to include the terminating character  
 char* player_name = new char[player_name_length_+1];  
   
 for(int i=0 ; i<player_name_length_+1 ; i++){  
   player_name[i] = eeprom_read_byte((uint8_t*)(DATA_NAME_ADDRESS+i));  
 }  
   
 int score = eeprom_read_word((uint16_t*)(DATA_SCORE_ADDRESS));  

Note: It is important to terminate the player name with a null character so no garbage gets appended on the end when you are displaying it on the screen. The graphics function text(char*, int, int) that will take the player name will stop looking for characters when it encounters the null character so without it you may get all sorts of stuff appended to the name.

The LandingScreen loads the hi score data and displays it to the player. The NameEntryScreen saves the hi score data back. Simples.

You can download version 2 of the Tetris Eclipse project here.

Check out a video of the hi score persistence in action. You can also see the game transition screens implemented from the last post:


Watch the video on youtube if you want to see the annotations. They seem to have been chopped off in this tiny format and I don't see a way to make it any bigger.

Note: There is a super secret button combo to reset the high score. On the landing screen where it says press A to continue, if you hold down the B button then press A, the screen will say 'HI SCORE RESET' and then continue. 

Game state transitions


I thought I'd tackle the top item on the Tetris to-do list; adding persistent hi scores. It's a little sad to have played a game and have no evidence of your achievements. It also encourages replay through a little competition. As I started implementing this feature I realised that the current code structure was getting a little unwieldy and could do with some refactoring first.

The current game path is controlled by the main method in Tetris.cpp. It is essentially a procedural style list of things to do in a list that loops forever:

e.g.

while(true){
   gameLoop();
   gameOver();
}

But then what happens when you want to add new states the to path? For example a landing page or name entry screen if you get a hi score. It would probably look something like this:

while(true){
   showLandingPage();
   gameLoop(); 
   gameOver();

   if(gotHiScore()){
      saveHiScore();
   }
}

This structure can get messy quite quickly if you want to add more states, especially ones are only moved to on a particular condition. To solve this I have introduced a Screen base class into Tetris with an implementation for each game state. The Screen then encapsulates the state transition logic within it.

 class Screen {  
   
   virtual void activate();  
   virtual Screen* getNextScreen();  
 }  

example Screen implementation:

 class PlayScreen : public Screen {  
   
   void activate(){  
    //code to play a game of tetris  
   }  
   
   Screen* getNextScreen(){  
    return new GameOverScreen();  
   }  
   
 }  

This reduces the main loop to:

Screen screen = new LandingScreen();

while(true){
   screen.activate();
   screen = screen.getNextScreen();
}

and it never needs to change, even when new screens are added. It also encapsulates all the code required for that state in a single class. 

Tetris screen state transitions

You can download version 2 of the Tetris Eclipse project here. This new version includes the state transitions and hi score saving/loading (as described here)

Wednesday 18 April 2012

Game Pack: Tetris


Now we can get control input to the TouchShield the next step is to use it to control a game. One of my favourite games of all time (up there with Zelda: Majora's Mask, Mario 64 and Secret of Mana) is Tetris. It's just so simple, addictive and satisfying that you can play it all day. This seemed like a realistic first game to be able to complete, so I have made a simple Tetris based on the most popular released version on the Nintendo Game Boy from 1989.

You can download the Eclipse project for Tetris here. You just need to import it into Eclipse.

Note: When testing importing the project into a different instance of Eclipse it built fine in 'Debug' mode but threw an error in 'Release' mode saying something like 'bad address'. Cleaning the project made this error go away and the project built successfully. Also I had to change the AVRDude programmer configuration back to TouchShield as it was set to ArduinoUno and so the program wouldn't upload as the chip was not in sync with the uploader.

The InputShieldForwarder is still used on the Arduino, and this new Tetris project is designed to be uploaded to the TouchShield.

Here is a video of the game in action:



The main considerations I took into account when making the game were:

  1. Providing a good frame rate
  2. Ensuring the game can be played indefinitely (i.e. no memory leaks)
  3. Making the blocks rotate in the proper way
  4. Making the graphics look like the Game Boy version

Providing a good frame rate


If nothing is happening in the game (no graphics changing, no logic processing) the frame rate will be very high as each game loop will execute very quickly. If something quite intensive is happening (like lines being matched on the screen and lots of blocks being shuffled down to fill the gap) the frame rate will be much slower or at least shutter for a few frames.

I found that if the frame rate was too high then the user input would be applied too quickly and blocks would shoot across the screen making fine positioning impossible.


In order to level this out you can throttle the frame rate by only allowing a game loop to execute after a specific period has elapsed. For Tetris I chose a frame rate of 40fps which looks like smooth. This is achieved in Tetris.cpp:


 long curr_time = millis();  
   
   if(millis() - curr_time > (1000/40)){  
   
     //do game processing  
   
     curr_time = millis();  
   }  

Ensuring the game can be played indefinitely


I spent quite a while play-testing the game and am pretty sure there are no memory leaks present. Having come from a mainly Java background I found it quite challenging ensuring each object I created was destroyed again at the appropriate time (having been spoilt with automatic behind-the-scenes garbage collection and a memory space that was unlikely to run out). This was achieved through the use of class destructors and calls to delete() when an object was no longer needed.

The only transient objects in the game are Tetromino and GridBlock. A Tetromino object represents the currently falling block and is used to coordinate the 4 sub-blocks when it moves around the grid. A Tetromino is created when a new block is required to fall from the top of the grid. It is destroyed when it collides with either another block or the bottom of the grid. A GridBlock object represents a single sub-block within a Tetromino or a single occupied square on the grid. Four GridBlocks are created when a Tetromino is created. When a Tetromino is destroyed the GridBlocks remain as they are now part of the grid and can interact with future falling blocks. GridBlocks are destroyed when they are cleared in a line.



Making the blocks rotate in the proper way


Each block can be rotated 90 degrees into 4 positions. These rotations are not necessarily around the central point of the block and the final position of the block is allowed to be shifted left or right to fit into the available space if possible.

For example, s-blocks and line-blocks do not rotate around a single point:

Bottom row shows real rotation behaviour of an s-block



Bottom row shows real rotation behaviour of a line-block
however t-blocks and l-blocks do:

Real rotation behaviour matches rotating around a single point



Real rotation behaviour matches rotating around a single point


This means there is no common rule of rotation. (Or at least not one that I could see).

I decided to implement block rotation as a set of 4 translations for each block. In order for the blocks to match the configuration for a given rotation, the 4 sub-blocks need to be translated into the appropriate positions. This makes rotation really easy as it just involves a relative X/Y coordinate translations for each sub-block.

For example, to rotate the given t-block from the left position to the right position, the following translations need to be applied:


red block += (1,-1)
blue block += (0,0)
green block += (-1,1)
yellow block += (1,1)

You can see these rotation translations in the Tetromino sub-classes in the project.

Also the blocks are allowed to shift to fit into the available space. This makes it easier on the player as they don't have to move the blocks into positions where rotations will fit, the grid will handle that for them.

For example, rotating an s-block from position 2 while it is against a wall would result in one of the sub-blocks ending up inside the wall. However as there is space to shift, the block does so:

block shifting after rotation


The only time a rotation will fail is if there is no amount of shifting that can be done to fit the new configuration on the grid without colliding with another block or the edges of the grid.

shifting right allows the rotation to fit

No amount of shifting will allow the rotation to fit


Making the graphics look like the Game Boy version


I have very fond memories of playing Tetris on my older brother's Game Boy as a child. The yellow hued screen and sepia-toned blocks had to be recreated on the TouchShield for maximum authenticity! I thought it seemed a shame to deliberatly make the graphics look previous-gen as the TouchShield is capable of providing super vibrant, clear images that wouldn't look out of place on any modern hand-held device. However as the look was completed I changed my mind and thought it made the game look awesome. I'm not too keen on the look of cheesy brightly coloured Tetris clones that are floating around, but I feel this retro-style makes it stand out. It could do with some fake screen-bleed at the edges though...



While the finished game is pretty cool, it could do with some improvements that I will work on soon (assuming the Tetris god is smiling on me):

  1. Saving hi-scores
  2. Option to switch out the current falling block with a saved block
  3. Sorting out the level speed scaling
  4. Sound (it could definitely do with some epic tunes)

Monday 16 April 2012

Getting data from the InputShield to the TouchShield


Writing an application for the Game Pack will generally consist of 2 programs. One that runs on the Arduino to send data from the InputShield to the TouchShield, and another that runs on the TouchShield that will perform the main game processing and handle the data from the InputShield.

The program to send data from the InputShield is relatively simple. It polls the pins connected to the various buttons for signals and then sends these signals to the TouchShield through another pin using serial communications. The data is sent in a group containing a value for each component.

e.g. the data sent for one poll, will contain the following set of information

JoyStick Lateral = 100
JoyStick Vertical = 0
JoyStick Button = 1
Button A = 0
Button B = 1

The program to upload to the Arduino can be created using the SimpleArduinoLibrary and adding a main source file (InputShieldForwarder.cpp) containing the code to poll the pins and send the data out through another pin. You can download InputShieldForwarder.cpp here

Create a new project called InputShieldForwarder for the Arduino Uno (follow the steps from the last post). The InputShieldForwarder.cpp source file is copied from the original code created by Liquidware (You can find it here) but required a few tweaks to remove the dependencies on the processing libraries and use the SimpleArduinoLibrary instead.

Your new project should look like this:



So now you can upload the program to the Arduino but it won't look very impressive because the TouchShield is not listening and will not react to data sent from the InputShield. To remedy this, we will upload a little program for the TouchShield which will poll for data and display it on the screen.

Creating a new project for the TouchShield


A TouchShield project is created in the same way as we did for the Arduino except some different configuration is required:

Under AVR Target Hardware properties:

    MCU Type → Atmega2560

In the AVRDude configuration:

    New Programmer configuration:

    Name → TouchShield
    Programmer Hardware → Atmel Butterfly Development Board
    Override default baud rate → 57600

The Antipasto IDE contains loads of useful libraries for manipulating the graphics on the TouchShield. We will reuse these libraries in our Eclipse project (they're super easy to use and there's no point re-inventing the wheel). We will also need the 'utils' folder from the last example to provide methods for constructing and destructing objects (not included in the avr-gcc linker) and a new class to handle the InputShield.

I have packaged up the source files required for this program here. Simply unzip them into your empty project.

Your new project should look like this



Included in the source files is a class called InputShield. This encapsulates the data format away from the main code and interprets the data into a more useful format (well, I have found the format more useful anyway). The analogue readings from the joystick are translated into discrete Left/Right/Up/Down values and the buttons values are also translated into booleans (note: when a button is pressed, the value is 0, not 1). This code is based on the InputShieldDisplay code written by Liquidware which is available here.

The code uses the graphics function: 

    text(textToOutput, xPos, yPos)

to display the data from the InputShield (Coordinates are referenced from the top left corner of the screen). For more information on what graphics functions are available for the TouchShield check out out the wiki page here.

Build the projects (in Release mode) and then we are ready to upload our programs.

  1. Connect the USB cable to the Arduino (connect it back into the Game Pack set up).

  2. Upload the InputShieldForwarder by selecting the project in the Project Explorer and selecting the 'AVR' option from the top menu and 'Upload Project to target device'.

  3. Before we upload to the TouchShield we need to prepare it for receiving the new code. Do this by pressing the teeny tiny button on the left side of the TouchShield. This will make the screen go blank (assuming it was displaying anything before)

    reset button on the TouchShield


  4. Select the InputShieldDisplay project in the Project Explorer and upload it in the same manner as step 2. This takes a little longer than uploading to the Arduino.

If all goes well you should now see some output on the TouchShield that changes when you interact with the InputShield.


Friday 13 April 2012

A simple Arduino program in Eclipse


Here is a guide to create a simple example project to flash an LED on the Arduino Uno. Once this is working it is a small step to do something with the Game Pack as a whole.

Create an empty project

First create a new AVR project:

  1. File → New → C++ Project
  2. Project name → FlashLED
  3. Project type → AVR Cross Target Application
  4. Toolchains → AVR-GCC Toolchain
  5. Next
  6. Next
  7. AVR Target Hardware Properties

The program we are creating will be run on an Arduino Uno board. This uses an Atmega328P micro controller which operates at 16MHz. Set the following config:

    MCU Type → Atmega328P
    MCU Frequency → 16000000

We now have a blank project set up to compile C++ code into hex code that will run on the Arduino Uno board.

Write some code

If you have previously used one of the Arduino IDEs you will have referenced functions like digitalWrite, pinMode etc. to control the components attached to the board. We do not have access to these functions now (unless we were to copy the code from the IDE into our project) so I have written a simple set of classes to provide some basic functionality to control components attached to the Arduino. You can download these classes here.

(These classes only have very limited functionality as I only implemented what I needed at the time. Using the datasheet for the chip and the arduino schematic to map pins to registers you can extend the functionality as you want.)


The main class you will interact with is ArduinoUno. This class has the following methods:

setDigitalPinMode - sets a pin to either input or output mode.

digitalWrite - sends a high or low signal to the specified pin.

digitalRead - reads a high or low value from the specified pin.

analogueRead - reads a value between 0-255 from an analogue input pin.

startSerial - starts serial communications specifying the pin that will receive data and the pin that will send data. This is useful later for the Game Pack as we will send the button presses and joystick movement data over serial to the TouchShield for processing.

sendSerialData - 2 versions to send a single character or character array over the serial connection created in startSerial.



Copy the 3 folders into your project directory and refresh the project in Eclipse so they show up in the Project Explorer.

Create a new source file in the root directory of the project called 'FlashLED.cpp'

Add the following content to it to flash an LED on and off with an interval of 1 second on pin number 13:

 #include <util/delay.h>  
 #include "hardware/ArduinoUno.h"  
   
 using namespace hardware;  
   
 #define LED_PIN 13  
   
 ArduinoUno arduino;  
   
 int main() {  
   
   arduino.setDigitalPinMode(LED_PIN, OUTPUT);  
   
   while (true) {  
   
     arduino.digitalWrite(LED_PIN, HIGH);  
     _delay_ms(1000);  
     arduino.digitalWrite(LED_PIN, LOW);  
     _delay_ms(1000);  
   }  
   
   return 1;  
 }  


Your project should now look something like:


Build the project

Ensure the FlashLED project is selected in the Project Explorer and click the arrow next to the hammer icon on the menu bar to select 'Release'. This build mode will generate the hex output we will upload to the Arduino. Assuming the build goes ok, the console output should end in 'Build Finished'.

Now we have our code ready to upload to the Arduino, but we need to configure a few settings first.

Configure the upload settings

Right click the FlashLED project in the Project Explorer and select 'Properties'. Expand 'AVR' and click on 'AVRDude'. This is the utility that will upload the code to the Arduino. Check here for more information about AVRDUDE.
  1. Under 'Programmer configuration' select 'New'
  2. Set Configuration name to 'Arduino Uno'
  3. Select 'Arduino' from the Programmer Hardware list
  4. Fill in 'Override default port' with the port ID you will be using.
  5. Click OK
  6. Select your new Arduino Uno configuration
  7. Click OK

Note: If you are unsure which port ID to enter:
  1. Connect your Arduino to your computer with the USB cable
  2. In windows explorer right click 'Computer' and select 'Manage'
  3. Click on 'Device Manager'
  4. Expand 'Ports (COM & LPT)'

You should see 'Communications Port (XXX) listed here. The XXX will be the port ID (e.g. COM3). You can confirm it is the one linked to your Arduino by unplugging the cable and seeing it disappear.

Upload and run the program

Ok now we're good to go. Unplug your Arduino from your Game Pack setup and connect an LED (with an appropriate resistor) to pin 13 and then connect it to your computer via the USB cable.

hardware setup for the FlashLED program


In Eclipse select 'AVR' from the top menu and 'Upload project to target device'. The console output will show avrdude uploading the hex file to the arduino. The LED on the board should now be flashing as the program executes.

Arduino: Setting up Eclipse to develop for the Game Pack


Here are the steps required to get ready to develop C++ programs for the Game Pack in a Windows environment.

Download and install the following 3 components:

1. Eclipse for C/C++

This IDE is a good choice because of the AVR plugin available for Eclipse. This simplifies the compilation and uploading of AVR targeted code.

   a. Download it from http://www.eclipse.org/downloads/
   b. Unzip the folder (no installation required)

2. WinAVR

This is a set of development tools to produce and upload programs to AVR micro controllers on the Windows platform.

    a. Download it from http://sourceforge.net/projects/winavr/files/ 
    b. Run the executable installer

3. AVR plugin for Eclipse

This is a plugin to integrate the AVR development tools into the Eclipse IDE

    a. Open Eclipse and go to  'Help' → 'Install new software'
    b. 'Add' a new repository:
             name: avr plugin
             location: http://avr-eclipse.sourceforge.net/updatesite


    c. Select 'AVR Eclipse Plugin' and follow through the screens to complete the installation.

    d. Restart Eclipse

We are now ready to create some AVR based projects in Eclipse that can run on the Arduino and TouchShield.

Monday 9 April 2012

Arduino: Game Pack programming environment


The guys at Liquidware suggest using the Antipasto Arduino . This is similar in style to the original Arduino IDE but has support for some of the extra boards you might attach to an arduino (e.g. the TouchShield).

When I first started programming the TouchShield, the Antipasto IDE did not support the Arduino Uno. This meant that I had to have 2 IDEs open, one to program the Uno and one to program the TouchShield (although at time of writing this support has now been added in release 0044). As well as the hassle of having 2 IDEs open, they only provide very simple functionality to help you organise and write your code. It essentially feels like writing code in a tabbed note pad.

These IDEs do a great job of abstracting the low level programming away from the user if they would rather focus on the high level interactions and are perfectly adequate for small programs spanning only a few files.

However, having grand plans to create some relatively complex games, I thought it would be productive to see if it was possible to program these 2 devices in Eclipse before progressing any further. And what do you know...it is possible...and wasn't too arduous to set up.

Arduino: Game Pack


So the Game Pack arrived and I quickly put it together. Here is a video showing you how to connect it all together:



The TouchShield came pre-programmed with some kind of drawing application so you can play around with it straight out of the box, which was a nice touch.

When you program an Arduino, you are really programming the Atmel AVR mico controller embedded on the board. When you upload a sketch to the Arduino the program is written to the flash memory of the AVR chip. When power is supplied to the board a boot loader then runs your program. The chip will then interact with all your input/output devices you have plugged in to the pins on the board. The chip on the Arduino Uno is an ATmega328P.

Similarly the TouchShield Slide also contains an AVR micro controller that you program in much the same way as the one on the Arduino board. This chip is an ATmega2560. The ATmega2560 has much more flash memory than the 328P so you can write more complex programs for it. This is required as graphics processing and game logic is not as trivial as making an LED blink.

Arduino: what next


So you've make some lights flash, hooked up a piezo buzzer to your PC serial connection to play some excellent 8-bit tunes and other such small projects. What do you do next for something more meaty?

Personally I wanted to dive straight in with a 3D LED cube but being more interested in the programming element, rather than construction, I couldn't face soldering all those LEDs together and opted for some pre-made hardware which can be programmed to do some funky stuff. You can get 'shields'  to attach to Arduinos that provide a certain piece of functionality (e.g. networking, input buttons, compass) so I thought that would be the way to go. I found it quite hard to actually find any of these to buy but eventually found Liquidware, an excellent shop to buy open source hardware for various platforms including Arduino. I opted for a Game Pack. This consists of an Arduino Uno, lithium battery pack, input shield, 320x240 OLED touch screen and an extender shield to connect them all together. This combination will essentially make you a hand held games console.



 [A warning for UK residents: although this kit is totally worth the money, when it reached the UK it got stuck at customs where I had to pay a further £35 for them to release it]

Arduino: the beginning


I bought myself an arduino a while back to have a go at learning some basic electronics. I bought the SparkFun Inventors Kit which came with a load of cool stuff and useful instructions, hints and tips for building the circuits. I would definitely recommend this kit to anyone looking to get into some experimentation with an arduino. The kit comes with most of the components you need to start out with and so saves you a lot of time going round to electronics shops trying to find bits and pieces. 

However, when I finished the set of circuits provided with the kit, a great place to buy more components for a good price is BitsBox (Assuming you're in the UK). It was very easy to browse their site picking 'one of those' and 'one of those' and ending up with a basket full of awesome stuff for less than £10. Their delivery was pretty quick too. In the few cases where I burnt out some components (which probably will happen if you're not too sure what you're doing) Maplin had a pretty good selection of components when you just can't wait for a delivery.