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. 

No comments:

Post a Comment