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