Version of Robotron arcade game using LPC1768, a Gameduino shield, a serial EEPROM (for high scores), two microswitch joysticks and two buttons plus a box to put it in. 20 levels of mayhem.
Dependencies: 25LCxxx_SPI CommonTypes Gameduino mbed
GameRobotRic.cpp@3:a6a0cd726ca0, 2013-06-07 (annotated)
- Committer:
- RichardE
- Date:
- Fri Jun 07 20:29:59 2013 +0000
- Revision:
- 3:a6a0cd726ca0
- Parent:
- 2:bb0f631a6068
- Child:
- 4:673eb9735d44
Abandoned writing serial EEPROM class and used Ser25LCxxx library instead. HighScoreTable class appears to be reading and writing correctly to EEPROM and high scores are displayed correctly.
Who changed what in which revision?
User | Revision | Line number | New contents of line |
---|---|---|---|
RichardE | 0:5fa232ee5fdf | 1 | /* |
RichardE | 0:5fa232ee5fdf | 2 | * SOURCE FILE : GameRobotRic.cpp |
RichardE | 0:5fa232ee5fdf | 3 | * |
RichardE | 0:5fa232ee5fdf | 4 | * The RobotRic game class. |
RichardE | 0:5fa232ee5fdf | 5 | * |
RichardE | 0:5fa232ee5fdf | 6 | */ |
RichardE | 0:5fa232ee5fdf | 7 | |
RichardE | 0:5fa232ee5fdf | 8 | #include "GameRobotRic.h" // this module's prototypes |
RichardE | 0:5fa232ee5fdf | 9 | #include "Types.h" // various integer types etc. |
RichardE | 0:5fa232ee5fdf | 10 | #include "LevelCollection.h" // all the levels |
RichardE | 2:bb0f631a6068 | 11 | #include "sprite.h" // sprite data |
RichardE | 2:bb0f631a6068 | 12 | #include "RobotRicCharacterSet.h" // character set used in this game |
RichardE | 0:5fa232ee5fdf | 13 | #if 0 |
RichardE | 0:5fa232ee5fdf | 14 | #include "GDExtra.h" // extra Gameduino functions |
RichardE | 0:5fa232ee5fdf | 15 | #include "GDConst.h" // a few more Gameduino constants |
RichardE | 0:5fa232ee5fdf | 16 | #include "ArenaConst.h" // gameplay arena constants |
RichardE | 0:5fa232ee5fdf | 17 | #include "I2CEEPROM.h" // for access to serial EEPROM |
RichardE | 0:5fa232ee5fdf | 18 | #include "HighScoreEntry.h" // for getting player's name for high score table |
RichardE | 0:5fa232ee5fdf | 19 | #endif |
RichardE | 0:5fa232ee5fdf | 20 | |
RichardE | 3:a6a0cd726ca0 | 21 | // Define following for debugging messages to serial port. |
RichardE | 3:a6a0cd726ca0 | 22 | #define CHATTY |
RichardE | 3:a6a0cd726ca0 | 23 | |
RichardE | 0:5fa232ee5fdf | 24 | // Number of lives player starts with. |
RichardE | 0:5fa232ee5fdf | 25 | #define START_LIVES 5 |
RichardE | 0:5fa232ee5fdf | 26 | |
RichardE | 0:5fa232ee5fdf | 27 | // Pin allocations for I2C communications link. |
RichardE | 0:5fa232ee5fdf | 28 | #define EEPROM_SCL 5 |
RichardE | 0:5fa232ee5fdf | 29 | #define EEPROM_SDA 7 |
RichardE | 0:5fa232ee5fdf | 30 | #define EEPROM_WP 8 |
RichardE | 0:5fa232ee5fdf | 31 | |
RichardE | 0:5fa232ee5fdf | 32 | // Address of EEPROM set using A0, A1 and A2 pins. |
RichardE | 0:5fa232ee5fdf | 33 | #define ADDRESS_OF_EEPROM 0 |
RichardE | 0:5fa232ee5fdf | 34 | |
RichardE | 3:a6a0cd726ca0 | 35 | // Serial link to PC over USB cable. Globally accessible. |
RichardE | 3:a6a0cd726ca0 | 36 | Serial pc( USBTX, USBRX ); |
RichardE | 3:a6a0cd726ca0 | 37 | |
RichardE | 0:5fa232ee5fdf | 38 | /**************************/ |
RichardE | 0:5fa232ee5fdf | 39 | /* CHECK FOR A HIGH SCORE */ |
RichardE | 0:5fa232ee5fdf | 40 | /**************************/ |
RichardE | 0:5fa232ee5fdf | 41 | // Pass pointer to high score table in highScores. |
RichardE | 0:5fa232ee5fdf | 42 | // Pass score that was achieved in score. |
RichardE | 0:5fa232ee5fdf | 43 | void GameRobotRic::CheckForHighScore( HighScoreTable *highScores, UInt32 score ) { |
RichardE | 0:5fa232ee5fdf | 44 | #if 0 |
RichardE | 0:5fa232ee5fdf | 45 | UInt8 tablePos; |
RichardE | 0:5fa232ee5fdf | 46 | // Enter name into high score table if score is high enough. |
RichardE | 0:5fa232ee5fdf | 47 | if( ( tablePos = highScores->GetPositionInTable( player.Score ) ) < highScores->GetCapacity() ) { |
RichardE | 0:5fa232ee5fdf | 48 | // Player has made it onto the high score table. |
RichardE | 0:5fa232ee5fdf | 49 | // Get player to input name. |
RichardE | 0:5fa232ee5fdf | 50 | HighScoreEntry nameGetter; |
RichardE | 0:5fa232ee5fdf | 51 | PlayerName name; |
RichardE | 0:5fa232ee5fdf | 52 | nameGetter.GetName( &name, &controls ); |
RichardE | 0:5fa232ee5fdf | 53 | // Add name and score to table. |
RichardE | 0:5fa232ee5fdf | 54 | highScores->Add( tablePos, &name, score ); |
RichardE | 0:5fa232ee5fdf | 55 | } |
RichardE | 0:5fa232ee5fdf | 56 | #endif |
RichardE | 0:5fa232ee5fdf | 57 | } |
RichardE | 0:5fa232ee5fdf | 58 | |
RichardE | 0:5fa232ee5fdf | 59 | /*****************/ |
RichardE | 0:5fa232ee5fdf | 60 | /* PLAY THE GAME */ |
RichardE | 0:5fa232ee5fdf | 61 | /*****************/ |
RichardE | 0:5fa232ee5fdf | 62 | // This NEVER exits. |
RichardE | 0:5fa232ee5fdf | 63 | void GameRobotRic::Play( void ) { |
RichardE | 3:a6a0cd726ca0 | 64 | #ifdef CHATTY |
RichardE | 3:a6a0cd726ca0 | 65 | pc.puts( "Program has restarted!\r\n" ); |
RichardE | 3:a6a0cd726ca0 | 66 | #endif |
RichardE | 2:bb0f631a6068 | 67 | // Make a digital output for use as the Gameduino chip select pin. Deselect it. |
RichardE | 2:bb0f631a6068 | 68 | DigitalOut gameduinoCS( p8 ); |
RichardE | 2:bb0f631a6068 | 69 | gameduinoCS = 1; |
RichardE | 2:bb0f631a6068 | 70 | // Initialise an SPI link for communications with Gameduino and the serial EEPROM. |
RichardE | 2:bb0f631a6068 | 71 | // This is different from how the Maple version of RobotRic did it. It used an |
RichardE | 2:bb0f631a6068 | 72 | // I2C EEPROM. |
RichardE | 0:5fa232ee5fdf | 73 | // Use pin 5 for MOSI. |
RichardE | 0:5fa232ee5fdf | 74 | // Use pin 6 for MISO. |
RichardE | 0:5fa232ee5fdf | 75 | // Use pin 7 for SCK. |
RichardE | 0:5fa232ee5fdf | 76 | SPI spi( p5, p6, p7 ); |
RichardE | 0:5fa232ee5fdf | 77 | // 8MHz clock should be OK. |
RichardE | 0:5fa232ee5fdf | 78 | spi.frequency( 8000000 ); |
RichardE | 0:5fa232ee5fdf | 79 | // Set SPI format to use. |
RichardE | 0:5fa232ee5fdf | 80 | // Use 8 bits per SPI frame. |
RichardE | 3:a6a0cd726ca0 | 81 | // Use SPI mode 0. Clock normally low. Data captured on rising edge. |
RichardE | 0:5fa232ee5fdf | 82 | spi.format( 8, 0 ); |
RichardE | 0:5fa232ee5fdf | 83 | // Make a Gameduino and pass SPI link and digital output for chip select. |
RichardE | 2:bb0f631a6068 | 84 | Gameduino gd( &spi, &gameduinoCS ); |
RichardE | 0:5fa232ee5fdf | 85 | // Reset the Gameduino. |
RichardE | 0:5fa232ee5fdf | 86 | gd.begin(); |
RichardE | 2:bb0f631a6068 | 87 | gd.copy( Gameduino::RAM_SPRIMG, sprite_sprimg, sizeof( sprite_sprimg ) ); |
RichardE | 2:bb0f631a6068 | 88 | // Copy sprite palette data into Gameduino memory. |
RichardE | 2:bb0f631a6068 | 89 | gd.copy( Gameduino::RAM_SPRPAL, sprite_sprpal, sizeof( sprite_sprpal ) ); |
RichardE | 2:bb0f631a6068 | 90 | // Initialise character set pixel data RAM. |
RichardE | 2:bb0f631a6068 | 91 | gd.copy( Gameduino::RAM_CHR, RobotRicCharacterSet::PixelData, ( LAST_CHAR_IN_CHARACTER_SET + 1 ) << 4 ); |
RichardE | 2:bb0f631a6068 | 92 | // Initialise character set pixel palette RAM. |
RichardE | 2:bb0f631a6068 | 93 | gd.copy( Gameduino::RAM_PAL, RobotRicCharacterSet::PaletteData, ( LAST_CHAR_IN_CHARACTER_SET + 1 ) << 3 ); |
RichardE | 2:bb0f631a6068 | 94 | // Turn off JK collision detection. Every sprite collides with every other. |
RichardE | 2:bb0f631a6068 | 95 | // Did it this way because I could not resolve some problems with wandering humans. |
RichardE | 2:bb0f631a6068 | 96 | // Suppose JK collision detection were used. The player sprite is of type J and humans |
RichardE | 2:bb0f631a6068 | 97 | // are of type K so collisions between them will register allowing humans to be rescued. |
RichardE | 2:bb0f631a6068 | 98 | // However, I also need some enemies (Crushers for example) to be able to collide with |
RichardE | 2:bb0f631a6068 | 99 | // humans so they would need to be J type to collide with humans. But then player and |
RichardE | 2:bb0f631a6068 | 100 | // enemies are both J type and so collisions between players and enemies are not detected. |
RichardE | 2:bb0f631a6068 | 101 | gd.wr( Gameduino::JK_MODE, 0 ); |
RichardE | 2:bb0f631a6068 | 102 | // Initialise serial EEPROM object which is on same SPI bus as the Gameduino. |
RichardE | 3:a6a0cd726ca0 | 103 | Ser25LCxxx eeprom( &spi, p14, 32768, 64 ); |
RichardE | 0:5fa232ee5fdf | 104 | // Create a high score table that uses the EEPROM. |
RichardE | 0:5fa232ee5fdf | 105 | HighScoreTable highScores( &eeprom ); |
RichardE | 2:bb0f631a6068 | 106 | // Start on the attract level. |
RichardE | 2:bb0f631a6068 | 107 | UInt8 levelNumber = LevelCollection::AttractLevel; |
RichardE | 0:5fa232ee5fdf | 108 | #if 0 |
RichardE | 0:5fa232ee5fdf | 109 | player.Lives = START_LIVES; |
RichardE | 0:5fa232ee5fdf | 110 | #endif |
RichardE | 0:5fa232ee5fdf | 111 | LevelCollection levels; |
RichardE | 0:5fa232ee5fdf | 112 | Level *level; |
RichardE | 0:5fa232ee5fdf | 113 | Level::LevelExitCode exitCode; |
RichardE | 0:5fa232ee5fdf | 114 | #if 0 |
RichardE | 0:5fa232ee5fdf | 115 | // Initialise panel controls. |
RichardE | 0:5fa232ee5fdf | 116 | controls.InitialisePins(); |
RichardE | 0:5fa232ee5fdf | 117 | // Specify controls player should use. |
RichardE | 0:5fa232ee5fdf | 118 | player.SetControls( &controls ); |
RichardE | 0:5fa232ee5fdf | 119 | // Restrict players movement. |
RichardE | 0:5fa232ee5fdf | 120 | player.MovementRestricted = true; |
RichardE | 0:5fa232ee5fdf | 121 | player.Bounds = &ArenaRectangle; |
RichardE | 0:5fa232ee5fdf | 122 | #endif |
RichardE | 0:5fa232ee5fdf | 123 | // Repeat forever. |
RichardE | 0:5fa232ee5fdf | 124 | while( true ) { |
RichardE | 0:5fa232ee5fdf | 125 | // Get level specified by level number. |
RichardE | 0:5fa232ee5fdf | 126 | level = levels.GetLevel( levelNumber ); |
RichardE | 0:5fa232ee5fdf | 127 | // If failed to get level with that number go back to first normal level. |
RichardE | 0:5fa232ee5fdf | 128 | // This will happen if player completes last level. |
RichardE | 0:5fa232ee5fdf | 129 | if( level == NULL ) { |
RichardE | 0:5fa232ee5fdf | 130 | levelNumber = LevelCollection::FirstNormalLevel; |
RichardE | 0:5fa232ee5fdf | 131 | // Refetch level. |
RichardE | 0:5fa232ee5fdf | 132 | level = levels.GetLevel( levelNumber ); |
RichardE | 0:5fa232ee5fdf | 133 | } |
RichardE | 1:dfd5eaaf96a3 | 134 | // Pass reference to high score table. |
RichardE | 1:dfd5eaaf96a3 | 135 | level->SetHighScores( &highScores ); |
RichardE | 3:a6a0cd726ca0 | 136 | #if 0 |
RichardE | 0:5fa232ee5fdf | 137 | // Set player that is playing the level. |
RichardE | 0:5fa232ee5fdf | 138 | level->SetPlayer( &player ); |
RichardE | 1:dfd5eaaf96a3 | 139 | #endif |
RichardE | 1:dfd5eaaf96a3 | 140 | // Set Gameduino to use. |
RichardE | 1:dfd5eaaf96a3 | 141 | level->SetGameduino( &gd ); |
RichardE | 0:5fa232ee5fdf | 142 | // Play the level. |
RichardE | 0:5fa232ee5fdf | 143 | exitCode = level->Play(); |
RichardE | 0:5fa232ee5fdf | 144 | // If player was killed then decrement lives otherwise |
RichardE | 0:5fa232ee5fdf | 145 | // advance to next level. |
RichardE | 0:5fa232ee5fdf | 146 | switch( exitCode ) { |
RichardE | 0:5fa232ee5fdf | 147 | case Level::GameOver : |
RichardE | 1:dfd5eaaf96a3 | 148 | #if 0 |
RichardE | 0:5fa232ee5fdf | 149 | // TODO : Do some sort of game over fuss. |
RichardE | 0:5fa232ee5fdf | 150 | CheckForHighScore( &highScores, player.Score ); |
RichardE | 1:dfd5eaaf96a3 | 151 | #endif |
RichardE | 0:5fa232ee5fdf | 152 | // Go back to attract level and reset player lives and score. |
RichardE | 0:5fa232ee5fdf | 153 | levelNumber = LevelCollection::AttractLevel; |
RichardE | 1:dfd5eaaf96a3 | 154 | #if 0 |
RichardE | 0:5fa232ee5fdf | 155 | player.Lives = START_LIVES; |
RichardE | 0:5fa232ee5fdf | 156 | player.Score = 0; |
RichardE | 1:dfd5eaaf96a3 | 157 | #endif |
RichardE | 0:5fa232ee5fdf | 158 | break; |
RichardE | 0:5fa232ee5fdf | 159 | case Level::Completed : |
RichardE | 0:5fa232ee5fdf | 160 | levelNumber++; |
RichardE | 0:5fa232ee5fdf | 161 | break; |
RichardE | 0:5fa232ee5fdf | 162 | } |
RichardE | 1:dfd5eaaf96a3 | 163 | // Wait a bit. |
RichardE | 1:dfd5eaaf96a3 | 164 | wait( (float)2 ); |
RichardE | 0:5fa232ee5fdf | 165 | } |
RichardE | 0:5fa232ee5fdf | 166 | } |
RichardE | 0:5fa232ee5fdf | 167 |