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@2:bb0f631a6068, 2013-06-06 (annotated)
- Committer:
- RichardE
- Date:
- Thu Jun 06 20:11:28 2013 +0000
- Revision:
- 2:bb0f631a6068
- Parent:
- 1:dfd5eaaf96a3
- Child:
- 3:a6a0cd726ca0
More code brought in from Maple version. Now uses fancy character set and displays Robotric logo. Started re-writing I2C EEPROM code as SPI EEPROM code since now using an SPI EEPROM but not finished yet.
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 | 0:5fa232ee5fdf | 21 | // Number of lives player starts with. |
RichardE | 0:5fa232ee5fdf | 22 | #define START_LIVES 5 |
RichardE | 0:5fa232ee5fdf | 23 | |
RichardE | 0:5fa232ee5fdf | 24 | // Pin allocations for I2C communications link. |
RichardE | 0:5fa232ee5fdf | 25 | #define EEPROM_SCL 5 |
RichardE | 0:5fa232ee5fdf | 26 | #define EEPROM_SDA 7 |
RichardE | 0:5fa232ee5fdf | 27 | #define EEPROM_WP 8 |
RichardE | 0:5fa232ee5fdf | 28 | |
RichardE | 0:5fa232ee5fdf | 29 | // Address of EEPROM set using A0, A1 and A2 pins. |
RichardE | 0:5fa232ee5fdf | 30 | #define ADDRESS_OF_EEPROM 0 |
RichardE | 0:5fa232ee5fdf | 31 | |
RichardE | 0:5fa232ee5fdf | 32 | /**************************/ |
RichardE | 0:5fa232ee5fdf | 33 | /* CHECK FOR A HIGH SCORE */ |
RichardE | 0:5fa232ee5fdf | 34 | /**************************/ |
RichardE | 0:5fa232ee5fdf | 35 | // Pass pointer to high score table in highScores. |
RichardE | 0:5fa232ee5fdf | 36 | // Pass score that was achieved in score. |
RichardE | 0:5fa232ee5fdf | 37 | void GameRobotRic::CheckForHighScore( HighScoreTable *highScores, UInt32 score ) { |
RichardE | 0:5fa232ee5fdf | 38 | #if 0 |
RichardE | 0:5fa232ee5fdf | 39 | UInt8 tablePos; |
RichardE | 0:5fa232ee5fdf | 40 | // Enter name into high score table if score is high enough. |
RichardE | 0:5fa232ee5fdf | 41 | if( ( tablePos = highScores->GetPositionInTable( player.Score ) ) < highScores->GetCapacity() ) { |
RichardE | 0:5fa232ee5fdf | 42 | // Player has made it onto the high score table. |
RichardE | 0:5fa232ee5fdf | 43 | // Get player to input name. |
RichardE | 0:5fa232ee5fdf | 44 | HighScoreEntry nameGetter; |
RichardE | 0:5fa232ee5fdf | 45 | PlayerName name; |
RichardE | 0:5fa232ee5fdf | 46 | nameGetter.GetName( &name, &controls ); |
RichardE | 0:5fa232ee5fdf | 47 | // Add name and score to table. |
RichardE | 0:5fa232ee5fdf | 48 | highScores->Add( tablePos, &name, score ); |
RichardE | 0:5fa232ee5fdf | 49 | } |
RichardE | 0:5fa232ee5fdf | 50 | #endif |
RichardE | 0:5fa232ee5fdf | 51 | } |
RichardE | 0:5fa232ee5fdf | 52 | |
RichardE | 0:5fa232ee5fdf | 53 | /*****************/ |
RichardE | 0:5fa232ee5fdf | 54 | /* PLAY THE GAME */ |
RichardE | 0:5fa232ee5fdf | 55 | /*****************/ |
RichardE | 0:5fa232ee5fdf | 56 | // This NEVER exits. |
RichardE | 0:5fa232ee5fdf | 57 | void GameRobotRic::Play( void ) { |
RichardE | 2:bb0f631a6068 | 58 | // Make a digital output for use as the Gameduino chip select pin. Deselect it. |
RichardE | 2:bb0f631a6068 | 59 | DigitalOut gameduinoCS( p8 ); |
RichardE | 2:bb0f631a6068 | 60 | gameduinoCS = 1; |
RichardE | 2:bb0f631a6068 | 61 | // Make a digital output for use as the Gameduino chip select pin. Deselect it. |
RichardE | 2:bb0f631a6068 | 62 | DigitalOut eepromCS( p14 ); |
RichardE | 2:bb0f631a6068 | 63 | eepromCS = 1; |
RichardE | 2:bb0f631a6068 | 64 | // Initialise an SPI link for communications with Gameduino and the serial EEPROM. |
RichardE | 2:bb0f631a6068 | 65 | // This is different from how the Maple version of RobotRic did it. It used an |
RichardE | 2:bb0f631a6068 | 66 | // I2C EEPROM. |
RichardE | 0:5fa232ee5fdf | 67 | // Use pin 5 for MOSI. |
RichardE | 0:5fa232ee5fdf | 68 | // Use pin 6 for MISO. |
RichardE | 0:5fa232ee5fdf | 69 | // Use pin 7 for SCK. |
RichardE | 0:5fa232ee5fdf | 70 | SPI spi( p5, p6, p7 ); |
RichardE | 0:5fa232ee5fdf | 71 | // 8MHz clock should be OK. |
RichardE | 0:5fa232ee5fdf | 72 | spi.frequency( 8000000 ); |
RichardE | 0:5fa232ee5fdf | 73 | // Set SPI format to use. |
RichardE | 0:5fa232ee5fdf | 74 | // Use 8 bits per SPI frame. |
RichardE | 0:5fa232ee5fdf | 75 | // Use SPI mode 0. |
RichardE | 0:5fa232ee5fdf | 76 | spi.format( 8, 0 ); |
RichardE | 0:5fa232ee5fdf | 77 | // Make a Gameduino and pass SPI link and digital output for chip select. |
RichardE | 2:bb0f631a6068 | 78 | Gameduino gd( &spi, &gameduinoCS ); |
RichardE | 0:5fa232ee5fdf | 79 | // Reset the Gameduino. |
RichardE | 0:5fa232ee5fdf | 80 | gd.begin(); |
RichardE | 2:bb0f631a6068 | 81 | gd.copy( Gameduino::RAM_SPRIMG, sprite_sprimg, sizeof( sprite_sprimg ) ); |
RichardE | 2:bb0f631a6068 | 82 | // Copy sprite palette data into Gameduino memory. |
RichardE | 2:bb0f631a6068 | 83 | gd.copy( Gameduino::RAM_SPRPAL, sprite_sprpal, sizeof( sprite_sprpal ) ); |
RichardE | 2:bb0f631a6068 | 84 | // Initialise character set pixel data RAM. |
RichardE | 2:bb0f631a6068 | 85 | gd.copy( Gameduino::RAM_CHR, RobotRicCharacterSet::PixelData, ( LAST_CHAR_IN_CHARACTER_SET + 1 ) << 4 ); |
RichardE | 2:bb0f631a6068 | 86 | // Initialise character set pixel palette RAM. |
RichardE | 2:bb0f631a6068 | 87 | gd.copy( Gameduino::RAM_PAL, RobotRicCharacterSet::PaletteData, ( LAST_CHAR_IN_CHARACTER_SET + 1 ) << 3 ); |
RichardE | 2:bb0f631a6068 | 88 | // Turn off JK collision detection. Every sprite collides with every other. |
RichardE | 2:bb0f631a6068 | 89 | // Did it this way because I could not resolve some problems with wandering humans. |
RichardE | 2:bb0f631a6068 | 90 | // Suppose JK collision detection were used. The player sprite is of type J and humans |
RichardE | 2:bb0f631a6068 | 91 | // are of type K so collisions between them will register allowing humans to be rescued. |
RichardE | 2:bb0f631a6068 | 92 | // However, I also need some enemies (Crushers for example) to be able to collide with |
RichardE | 2:bb0f631a6068 | 93 | // humans so they would need to be J type to collide with humans. But then player and |
RichardE | 2:bb0f631a6068 | 94 | // enemies are both J type and so collisions between players and enemies are not detected. |
RichardE | 2:bb0f631a6068 | 95 | gd.wr( Gameduino::JK_MODE, 0 ); |
RichardE | 2:bb0f631a6068 | 96 | // Initialise serial EEPROM object which is on same SPI bus as the Gameduino. |
RichardE | 2:bb0f631a6068 | 97 | SPIEEPROM eeprom( &spi, &eepromCS ); |
RichardE | 0:5fa232ee5fdf | 98 | // Create a high score table that uses the EEPROM. |
RichardE | 0:5fa232ee5fdf | 99 | HighScoreTable highScores( &eeprom ); |
RichardE | 2:bb0f631a6068 | 100 | // Start on the attract level. |
RichardE | 2:bb0f631a6068 | 101 | UInt8 levelNumber = LevelCollection::AttractLevel; |
RichardE | 0:5fa232ee5fdf | 102 | #if 0 |
RichardE | 0:5fa232ee5fdf | 103 | player.Lives = START_LIVES; |
RichardE | 0:5fa232ee5fdf | 104 | #endif |
RichardE | 0:5fa232ee5fdf | 105 | LevelCollection levels; |
RichardE | 0:5fa232ee5fdf | 106 | Level *level; |
RichardE | 0:5fa232ee5fdf | 107 | Level::LevelExitCode exitCode; |
RichardE | 0:5fa232ee5fdf | 108 | #if 0 |
RichardE | 0:5fa232ee5fdf | 109 | // Initialise panel controls. |
RichardE | 0:5fa232ee5fdf | 110 | controls.InitialisePins(); |
RichardE | 0:5fa232ee5fdf | 111 | // Specify controls player should use. |
RichardE | 0:5fa232ee5fdf | 112 | player.SetControls( &controls ); |
RichardE | 0:5fa232ee5fdf | 113 | // Restrict players movement. |
RichardE | 0:5fa232ee5fdf | 114 | player.MovementRestricted = true; |
RichardE | 0:5fa232ee5fdf | 115 | player.Bounds = &ArenaRectangle; |
RichardE | 0:5fa232ee5fdf | 116 | #endif |
RichardE | 0:5fa232ee5fdf | 117 | // Repeat forever. |
RichardE | 0:5fa232ee5fdf | 118 | while( true ) { |
RichardE | 0:5fa232ee5fdf | 119 | // Get level specified by level number. |
RichardE | 0:5fa232ee5fdf | 120 | level = levels.GetLevel( levelNumber ); |
RichardE | 0:5fa232ee5fdf | 121 | // If failed to get level with that number go back to first normal level. |
RichardE | 0:5fa232ee5fdf | 122 | // This will happen if player completes last level. |
RichardE | 0:5fa232ee5fdf | 123 | if( level == NULL ) { |
RichardE | 0:5fa232ee5fdf | 124 | levelNumber = LevelCollection::FirstNormalLevel; |
RichardE | 0:5fa232ee5fdf | 125 | // Refetch level. |
RichardE | 0:5fa232ee5fdf | 126 | level = levels.GetLevel( levelNumber ); |
RichardE | 0:5fa232ee5fdf | 127 | } |
RichardE | 1:dfd5eaaf96a3 | 128 | #if 0 |
RichardE | 1:dfd5eaaf96a3 | 129 | // Pass reference to high score table. |
RichardE | 1:dfd5eaaf96a3 | 130 | level->SetHighScores( &highScores ); |
RichardE | 0:5fa232ee5fdf | 131 | // Set player that is playing the level. |
RichardE | 0:5fa232ee5fdf | 132 | level->SetPlayer( &player ); |
RichardE | 1:dfd5eaaf96a3 | 133 | #endif |
RichardE | 1:dfd5eaaf96a3 | 134 | // Set Gameduino to use. |
RichardE | 1:dfd5eaaf96a3 | 135 | level->SetGameduino( &gd ); |
RichardE | 0:5fa232ee5fdf | 136 | // Play the level. |
RichardE | 0:5fa232ee5fdf | 137 | exitCode = level->Play(); |
RichardE | 0:5fa232ee5fdf | 138 | // If player was killed then decrement lives otherwise |
RichardE | 0:5fa232ee5fdf | 139 | // advance to next level. |
RichardE | 0:5fa232ee5fdf | 140 | switch( exitCode ) { |
RichardE | 0:5fa232ee5fdf | 141 | case Level::GameOver : |
RichardE | 1:dfd5eaaf96a3 | 142 | #if 0 |
RichardE | 0:5fa232ee5fdf | 143 | // TODO : Do some sort of game over fuss. |
RichardE | 0:5fa232ee5fdf | 144 | CheckForHighScore( &highScores, player.Score ); |
RichardE | 1:dfd5eaaf96a3 | 145 | #endif |
RichardE | 0:5fa232ee5fdf | 146 | // Go back to attract level and reset player lives and score. |
RichardE | 0:5fa232ee5fdf | 147 | levelNumber = LevelCollection::AttractLevel; |
RichardE | 1:dfd5eaaf96a3 | 148 | #if 0 |
RichardE | 0:5fa232ee5fdf | 149 | player.Lives = START_LIVES; |
RichardE | 0:5fa232ee5fdf | 150 | player.Score = 0; |
RichardE | 1:dfd5eaaf96a3 | 151 | #endif |
RichardE | 0:5fa232ee5fdf | 152 | break; |
RichardE | 0:5fa232ee5fdf | 153 | case Level::Completed : |
RichardE | 0:5fa232ee5fdf | 154 | levelNumber++; |
RichardE | 0:5fa232ee5fdf | 155 | break; |
RichardE | 0:5fa232ee5fdf | 156 | } |
RichardE | 1:dfd5eaaf96a3 | 157 | // Wait a bit. |
RichardE | 1:dfd5eaaf96a3 | 158 | wait( (float)2 ); |
RichardE | 0:5fa232ee5fdf | 159 | } |
RichardE | 0:5fa232ee5fdf | 160 | } |
RichardE | 0:5fa232ee5fdf | 161 |