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

Committer:
RichardE
Date:
Sat Jun 08 15:50:38 2013 +0000
Revision:
6:8bbdb70bc11c
Parent:
5:0b0651ac7832
Child:
7:e72691603fd3
Player can now fire bullets and they move. Mayhem!

Who changed what in which revision?

UserRevisionLine numberNew contents of line
RichardE 0:5fa232ee5fdf 1 /*
RichardE 0:5fa232ee5fdf 2 * SOURCE FILE : LevelNormal.cpp
RichardE 0:5fa232ee5fdf 3 *
RichardE 0:5fa232ee5fdf 4 * Definition of class LevelNormal.
RichardE 0:5fa232ee5fdf 5 * Base class for all "normal" levels.
RichardE 0:5fa232ee5fdf 6 * i.e. Levels that are not special attract modes
RichardE 0:5fa232ee5fdf 7 * but have enemies who are trying to kill you
RichardE 0:5fa232ee5fdf 8 * and so on.
RichardE 0:5fa232ee5fdf 9 *
RichardE 0:5fa232ee5fdf 10 */
RichardE 0:5fa232ee5fdf 11
RichardE 5:0b0651ac7832 12 // Define this for debugging messages.
RichardE 5:0b0651ac7832 13 #define CHATTY
RichardE 5:0b0651ac7832 14
RichardE 5:0b0651ac7832 15 #ifdef CHATTY
RichardE 5:0b0651ac7832 16 #include "mbed.h"
RichardE 5:0b0651ac7832 17 extern Serial pc;
RichardE 5:0b0651ac7832 18 #endif
RichardE 5:0b0651ac7832 19
RichardE 0:5fa232ee5fdf 20 #include "LevelNormal.h"
RichardE 5:0b0651ac7832 21 #include "GameObjectLocator.h"
RichardE 5:0b0651ac7832 22 #include "FrameCounter.h"
RichardE 5:0b0651ac7832 23 #include "SpriteNumber.h"
RichardE 5:0b0651ac7832 24 #include "ArenaConst.h"
RichardE 0:5fa232ee5fdf 25
RichardE 0:5fa232ee5fdf 26 // Current instance being processed.
RichardE 0:5fa232ee5fdf 27 LevelNormal *LevelNormal::currentInstance;
RichardE 0:5fa232ee5fdf 28
RichardE 0:5fa232ee5fdf 29 /***************/
RichardE 0:5fa232ee5fdf 30 /* CONSTRUCTOR */
RichardE 0:5fa232ee5fdf 31 /***************/
RichardE 5:0b0651ac7832 32 LevelNormal::LevelNormal()
RichardE 5:0b0651ac7832 33 {
RichardE 0:5fa232ee5fdf 34 }
RichardE 0:5fa232ee5fdf 35
RichardE 0:5fa232ee5fdf 36 /**************/
RichardE 0:5fa232ee5fdf 37 /* DESTRUCTOR */
RichardE 0:5fa232ee5fdf 38 /**************/
RichardE 5:0b0651ac7832 39 LevelNormal::~LevelNormal()
RichardE 5:0b0651ac7832 40 {
RichardE 0:5fa232ee5fdf 41 }
RichardE 0:5fa232ee5fdf 42
RichardE 0:5fa232ee5fdf 43 /********************/
RichardE 0:5fa232ee5fdf 44 /* INITIALISE LEVEL */
RichardE 0:5fa232ee5fdf 45 /********************/
RichardE 5:0b0651ac7832 46 // Pass pointer to Gameduino to draw on in gd.
RichardE 5:0b0651ac7832 47 void LevelNormal::InitialiseLevel( Gameduino *gd )
RichardE 5:0b0651ac7832 48 {
RichardE 0:5fa232ee5fdf 49 // Note that if you re-arrange the following code you may need to adjust the
RichardE 0:5fa232ee5fdf 50 // SpriteNumber enumeration in SpriteNumber.h.
RichardE 5:0b0651ac7832 51 UInt8 spriteNumber = FirstEnemySprite;
RichardE 5:0b0651ac7832 52 // Initialise enemies.
RichardE 5:0b0651ac7832 53 GameObject::InitialiseAll( DataForLevel->Enemies, LevelData::MaxEnemies, &spriteNumber );
RichardE 5:0b0651ac7832 54 // Initialise humans.
RichardE 0:5fa232ee5fdf 55 spriteNumber = FirstHumanSprite;
RichardE 5:0b0651ac7832 56 GameObject::InitialiseAll( DataForLevel->Humans, LevelData::MaxHumans, &spriteNumber );
RichardE 5:0b0651ac7832 57 // Use next free sprite number for player.
RichardE 5:0b0651ac7832 58 player->SpriteNumber = PlayerSprite;
RichardE 5:0b0651ac7832 59 // Do futher initialisation for all enemies.
RichardE 5:0b0651ac7832 60 #if 0
RichardE 5:0b0651ac7832 61 EnemyObject *object;
RichardE 5:0b0651ac7832 62 for( UInt8 e = 0; e < LevelData::MaxEnemies; ++e ) {
RichardE 5:0b0651ac7832 63 object = (EnemyObject*)DataForLevel->Enemies[ e ];
RichardE 5:0b0651ac7832 64 if( object != (EnemyObject*)NULL ) {
RichardE 0:5fa232ee5fdf 65 // Get enemy to chase the player.
RichardE 5:0b0651ac7832 66 object->SetChaseObject( player );
RichardE 0:5fa232ee5fdf 67 // Pass array of all enemies to this enemy.
RichardE 0:5fa232ee5fdf 68 object->Enemies = DataForLevel->Enemies;
RichardE 0:5fa232ee5fdf 69 // If enemy is a brain then tell it about the humans to chase.
RichardE 0:5fa232ee5fdf 70 if( object->GetEnemyType() == Brain ) {
RichardE 0:5fa232ee5fdf 71 ((BrainObject*)object)->HumansToChase = DataForLevel->Humans;
RichardE 0:5fa232ee5fdf 72 }
RichardE 5:0b0651ac7832 73 }
RichardE 0:5fa232ee5fdf 74 }
RichardE 0:5fa232ee5fdf 75 #endif
RichardE 5:0b0651ac7832 76 // Put player in the centre of the arena.
RichardE 5:0b0651ac7832 77 player->Xco = PLAYER_START_X;
RichardE 5:0b0651ac7832 78 player->Yco = PLAYER_START_Y;
RichardE 5:0b0651ac7832 79 // Kill off all player's bullets.
RichardE 5:0b0651ac7832 80 player->KillAllBullets( gd );
RichardE 5:0b0651ac7832 81 // Kill off all explosions.
RichardE 5:0b0651ac7832 82 // ExplosionManager::Instance.KillAllExplosions();
RichardE 0:5fa232ee5fdf 83 }
RichardE 0:5fa232ee5fdf 84
RichardE 0:5fa232ee5fdf 85 /**********************************/
RichardE 0:5fa232ee5fdf 86 /* DRAW SCORE AND NUMBER OF LIVES */
RichardE 0:5fa232ee5fdf 87 /**********************************/
RichardE 5:0b0651ac7832 88 void LevelNormal::DrawScoreAndLives( void )
RichardE 5:0b0651ac7832 89 {
RichardE 5:0b0651ac7832 90 GDExtra::WriteBCDNumber( gd, 16, 0, player->Score, 8 );
RichardE 5:0b0651ac7832 91 // Display number of lives but limit this to 20 lives displayed.
RichardE 5:0b0651ac7832 92 UInt8 lives = ( player->Lives > 20 ) ? 20 : player->Lives;
RichardE 5:0b0651ac7832 93 gd->fill( Gameduino::RAM_PIC + VISIBLE_CHAR_WIDTH - lives, MiniPlayer, lives );
RichardE 0:5fa232ee5fdf 94 }
RichardE 0:5fa232ee5fdf 95
RichardE 0:5fa232ee5fdf 96 /******************/
RichardE 0:5fa232ee5fdf 97 /* DRAW THE LEVEL */
RichardE 0:5fa232ee5fdf 98 /******************/
RichardE 5:0b0651ac7832 99 void LevelNormal::DrawLevel( void )
RichardE 5:0b0651ac7832 100 {
RichardE 5:0b0651ac7832 101 // Set screen background to black.
RichardE 5:0b0651ac7832 102 gd->wr( Gameduino::BG_COLOR, Gameduino::RGB( 0, 0, 0 ) );
RichardE 5:0b0651ac7832 103 // Clear the screen to zero characters.
RichardE 5:0b0651ac7832 104 GDExtra::ClearScreen( gd, TransparentChar );
RichardE 5:0b0651ac7832 105 // Hide all sprties.
RichardE 5:0b0651ac7832 106 GDExtra::HideAllSprites( gd );
RichardE 5:0b0651ac7832 107 // Display level number.
RichardE 5:0b0651ac7832 108 GDExtra::WriteProgString( gd, 0, 0, StringData::LevelString );
RichardE 5:0b0651ac7832 109 GDExtra::WriteUInt16( gd, 6, 0, LevelNumber, 10, 2 );
RichardE 5:0b0651ac7832 110 // Display score.
RichardE 5:0b0651ac7832 111 GDExtra::WriteProgString( gd, 10, 0, StringData::ScoreString );
RichardE 5:0b0651ac7832 112 // Update score and lives.
RichardE 5:0b0651ac7832 113 DrawScoreAndLives();
RichardE 5:0b0651ac7832 114 // Draw border around screen.
RichardE 5:0b0651ac7832 115 CharFrame::Draw(
RichardE 5:0b0651ac7832 116 gd,
RichardE 5:0b0651ac7832 117 ARENA_BORDER_X,
RichardE 5:0b0651ac7832 118 ARENA_BORDER_Y,
RichardE 5:0b0651ac7832 119 ARENA_BORDER_WIDTH,
RichardE 5:0b0651ac7832 120 ARENA_BORDER_HEIGHT
RichardE 5:0b0651ac7832 121 );
RichardE 0:5fa232ee5fdf 122 }
RichardE 0:5fa232ee5fdf 123
RichardE 0:5fa232ee5fdf 124 /************************************************/
RichardE 0:5fa232ee5fdf 125 /* HANDLE COLLISIONS BETWEEN HUMANS AND ENEMIES */
RichardE 0:5fa232ee5fdf 126 /************************************************/
RichardE 0:5fa232ee5fdf 127 // Pass index of human in level's humans array in humanIndex.
RichardE 0:5fa232ee5fdf 128 // Pass sprite number of sprite that it hit in spriteNumber.
RichardE 5:0b0651ac7832 129 void LevelNormal::HandleHumanCollision( UInt8 humanIndex, UInt8 spriteNumber )
RichardE 5:0b0651ac7832 130 {
RichardE 0:5fa232ee5fdf 131 #if 0
RichardE 5:0b0651ac7832 132 // Point to array of enemy object pointers.
RichardE 5:0b0651ac7832 133 GameObject **enemies = currentInstance->DataForLevel->Enemies;
RichardE 5:0b0651ac7832 134 EnemyObject *enemy;
RichardE 5:0b0651ac7832 135 UInt8 enemyIndex, mutantIndex;
RichardE 5:0b0651ac7832 136 // Find an enemy with given sprite number.
RichardE 5:0b0651ac7832 137 if( GameObject::FindSpriteNumber( enemies, LevelData::MaxEnemies, spriteNumber, &enemyIndex ) ) {
RichardE 5:0b0651ac7832 138 // Found enemy. Check if it squashes humans.
RichardE 5:0b0651ac7832 139 enemy = (EnemyObject*)enemies[ enemyIndex ];
RichardE 0:5fa232ee5fdf 140 // Get hold of the human that is doomed.
RichardE 0:5fa232ee5fdf 141 GameObject **humans = currentInstance->DataForLevel->Humans;
RichardE 0:5fa232ee5fdf 142 HumanObject *human = (HumanObject*)humans[ humanIndex ];
RichardE 0:5fa232ee5fdf 143 // Human must be walking around. Not rescued or already dead.
RichardE 0:5fa232ee5fdf 144 if( human->CurrentState == HumanObject::WalkingAbout ) {
RichardE 0:5fa232ee5fdf 145 if( enemy->SquashesHumans ) {
RichardE 0:5fa232ee5fdf 146 // Change human to dead state.
RichardE 0:5fa232ee5fdf 147 human->CurrentState = HumanObject::Dead;
RichardE 0:5fa232ee5fdf 148 // Make a noise.
RichardE 0:5fa232ee5fdf 149 SoundManager::Instance.PlaySound( Sounds::HumanDies, 0, 0 );
RichardE 5:0b0651ac7832 150 } else if( enemy->GetEnemyType() == Brain ) {
RichardE 0:5fa232ee5fdf 151 // Kill human by inserting a null into humans array.
RichardE 0:5fa232ee5fdf 152 humans[ humanIndex ] = (GameObject*)NULL;
RichardE 0:5fa232ee5fdf 153 // Find a free slot for a new enemy.
RichardE 0:5fa232ee5fdf 154 if( GameObject::FindUnusedObject( enemies, LevelData::MaxEnemies, &mutantIndex ) ) {
RichardE 0:5fa232ee5fdf 155 // Write a pointer to a mutant with the same index as the human that just died
RichardE 0:5fa232ee5fdf 156 // into the enemy array.
RichardE 0:5fa232ee5fdf 157 MutantObject *mutant = currentInstance->DataForLevel->Mutants + humanIndex;
RichardE 0:5fa232ee5fdf 158 enemies[ mutantIndex ] = mutant;
RichardE 0:5fa232ee5fdf 159 // Initialise mutant at coordinates of human and chasing the player.
RichardE 0:5fa232ee5fdf 160 mutant->Start( human, currentInstance->player );
RichardE 0:5fa232ee5fdf 161 // Make a noise.
RichardE 0:5fa232ee5fdf 162 // TODO : SoundManager::Instance.PlaySound( Sounds::HumanMutates, 0, 0 );
RichardE 5:0b0651ac7832 163 } else {
RichardE 0:5fa232ee5fdf 164 // Could not find a free slot for a new enemy so just erase the human sprite.
RichardE 0:5fa232ee5fdf 165 GDExtra::HideSprite( human->SpriteNumber );
RichardE 0:5fa232ee5fdf 166 }
RichardE 0:5fa232ee5fdf 167 }
RichardE 0:5fa232ee5fdf 168 }
RichardE 0:5fa232ee5fdf 169 }
RichardE 0:5fa232ee5fdf 170 #endif
RichardE 0:5fa232ee5fdf 171 }
RichardE 0:5fa232ee5fdf 172
RichardE 0:5fa232ee5fdf 173 /********************************************************/
RichardE 0:5fa232ee5fdf 174 /* HANDLE COLLISIONS BETWEEN PLAYER BULLETS AND ENEMIES */
RichardE 0:5fa232ee5fdf 175 /********************************************************/
RichardE 0:5fa232ee5fdf 176 // Pass index of bullet in player's bullet array in bulletIndex.
RichardE 0:5fa232ee5fdf 177 // Pass sprite number of sprite that it hit in spriteNumber.
RichardE 5:0b0651ac7832 178 void LevelNormal::HandleBulletCollision( UInt8 bulletIndex, UInt8 spriteNumber )
RichardE 5:0b0651ac7832 179 {
RichardE 0:5fa232ee5fdf 180 #if 0
RichardE 5:0b0651ac7832 181 // Point to array of enemy object pointers.
RichardE 5:0b0651ac7832 182 GameObject **enemies = currentInstance->DataForLevel->Enemies;
RichardE 5:0b0651ac7832 183 EnemyObject *enemy;
RichardE 5:0b0651ac7832 184 UInt8 enemyIndex;
RichardE 5:0b0651ac7832 185 // Find an enemy with given sprite number.
RichardE 5:0b0651ac7832 186 if( GameObject::FindSpriteNumber( enemies, LevelData::MaxEnemies, spriteNumber, &enemyIndex ) ) {
RichardE 5:0b0651ac7832 187 // Found enemy. Check if it is indestructable.
RichardE 5:0b0651ac7832 188 enemy = (EnemyObject*)enemies[ enemyIndex ];
RichardE 0:5fa232ee5fdf 189 if( enemy->HitPoints != EnemyObject::Indestructable ) {
RichardE 0:5fa232ee5fdf 190 // Enemy is not indestructable. Decrement hit points and die when it reaches zero.
RichardE 0:5fa232ee5fdf 191 enemy->HitPoints--;
RichardE 0:5fa232ee5fdf 192 if( enemy->HitPoints == 0 ) {
RichardE 0:5fa232ee5fdf 193 // Kill enemy by inserting a NULL into enemies array.
RichardE 0:5fa232ee5fdf 194 enemies[ enemyIndex ] = (GameObject*)NULL;
RichardE 0:5fa232ee5fdf 195 // Hide the enemy sprite.
RichardE 0:5fa232ee5fdf 196 GDExtra::HideSprite( enemy->SpriteNumber );
RichardE 0:5fa232ee5fdf 197 // Add points to player's score.
RichardE 0:5fa232ee5fdf 198 currentInstance->player->AddToScore( enemy->GetPoints() );
RichardE 0:5fa232ee5fdf 199 }
RichardE 0:5fa232ee5fdf 200 }
RichardE 0:5fa232ee5fdf 201 // Tell enemy it has been hit by a bullet.
RichardE 0:5fa232ee5fdf 202 enemy->RegisterHitByBullet();
RichardE 0:5fa232ee5fdf 203 // Kill off the bullet.
RichardE 0:5fa232ee5fdf 204 currentInstance->player->KillBullet( bulletIndex );
RichardE 0:5fa232ee5fdf 205 // Make a noise.
RichardE 0:5fa232ee5fdf 206 SoundManager::Instance.PlaySound( Sounds::Explosion, 0, 0 );
RichardE 0:5fa232ee5fdf 207 // Start explosion animation using coordinates of enemy.
RichardE 0:5fa232ee5fdf 208 ExplosionManager::Instance.StartExplosion( enemy->Xco, enemy->Yco );
RichardE 5:0b0651ac7832 209 }
RichardE 0:5fa232ee5fdf 210 #endif
RichardE 0:5fa232ee5fdf 211 }
RichardE 0:5fa232ee5fdf 212
RichardE 0:5fa232ee5fdf 213 /*********************************************************/
RichardE 0:5fa232ee5fdf 214 /* CHECK FOR COLLISIONS BETWEEN PLAYER AND OTHER OBJECTS */
RichardE 0:5fa232ee5fdf 215 /*********************************************************/
RichardE 0:5fa232ee5fdf 216 // Pass pointer to a flag that will be set true if player is dead in isDead parameter.
RichardE 5:0b0651ac7832 217 void LevelNormal::CheckPlayerCollisions( bool *isDead )
RichardE 5:0b0651ac7832 218 {
RichardE 0:5fa232ee5fdf 219 #if 0
RichardE 5:0b0651ac7832 220 UInt8 enemyIndex, humanIndex;
RichardE 5:0b0651ac7832 221 // Check if player sprite has hit another sprite.
RichardE 5:0b0651ac7832 222 UInt8 hitSpriteNumber = GD.rd( COLLISION + player->SpriteNumber );
RichardE 5:0b0651ac7832 223 // If you get 0xFF then no collision found.
RichardE 5:0b0651ac7832 224 if( hitSpriteNumber != 0xFF ) {
RichardE 5:0b0651ac7832 225 // Check for collision with an enemy.
RichardE 5:0b0651ac7832 226 if(
RichardE 5:0b0651ac7832 227 GameObject::FindSpriteNumber(
RichardE 5:0b0651ac7832 228 DataForLevel->Enemies, LevelData::MaxEnemies, hitSpriteNumber, &enemyIndex
RichardE 5:0b0651ac7832 229 )
RichardE 5:0b0651ac7832 230 ) {
RichardE 5:0b0651ac7832 231 // Hit an enemy. Player is dead.
RichardE 5:0b0651ac7832 232 *isDead = true;
RichardE 5:0b0651ac7832 233 }
RichardE 5:0b0651ac7832 234 // Check for collision with a human that has not already been rescued or killed.
RichardE 5:0b0651ac7832 235 else if(
RichardE 5:0b0651ac7832 236 GameObject::FindSpriteNumber(
RichardE 5:0b0651ac7832 237 DataForLevel->Humans, LevelData::MaxHumans, hitSpriteNumber, &humanIndex
RichardE 5:0b0651ac7832 238 )
RichardE 5:0b0651ac7832 239 ) {
RichardE 5:0b0651ac7832 240 HumanObject *human = (HumanObject*)DataForLevel->Humans[ humanIndex ];
RichardE 0:5fa232ee5fdf 241 if( human->CurrentState == HumanObject::WalkingAbout ) {
RichardE 0:5fa232ee5fdf 242 // Change human state to rescued.
RichardE 0:5fa232ee5fdf 243 human->CurrentState = HumanObject::Rescued;
RichardE 0:5fa232ee5fdf 244 // Give player 50 points (in BCD!).
RichardE 0:5fa232ee5fdf 245 player->AddToScore( 0x50 );
RichardE 0:5fa232ee5fdf 246 // Make a noise.
RichardE 0:5fa232ee5fdf 247 SoundManager::Instance.PlaySound( Sounds::RescueHuman, 0, 0 );
RichardE 0:5fa232ee5fdf 248 }
RichardE 5:0b0651ac7832 249 }
RichardE 5:0b0651ac7832 250 }
RichardE 0:5fa232ee5fdf 251 #endif
RichardE 0:5fa232ee5fdf 252 }
RichardE 0:5fa232ee5fdf 253
RichardE 0:5fa232ee5fdf 254 /***********************************************************************************/
RichardE 0:5fa232ee5fdf 255 /* WAIT UNTIL SLOT FREE FOR A NEW SOUND, PLAY IT AND WAIT FOR ALL SOUNDS TO FINISH */
RichardE 0:5fa232ee5fdf 256 /***********************************************************************************/
RichardE 0:5fa232ee5fdf 257 // Pass sound to play in soundToPlay parameter.
RichardE 5:0b0651ac7832 258 void LevelNormal::PlaySoundAndWait( const UInt8 *soundToPlay )
RichardE 5:0b0651ac7832 259 {
RichardE 0:5fa232ee5fdf 260 #if 0
RichardE 5:0b0651ac7832 261 // Keep trying to play sound until it works and meanwhile
RichardE 5:0b0651ac7832 262 // keep currently playing sounds going.
RichardE 5:0b0651ac7832 263 while( ! SoundManager::Instance.PlaySound( soundToPlay, 0, 0 ) ) {
RichardE 5:0b0651ac7832 264 // Update sound manager.
RichardE 5:0b0651ac7832 265 SoundManager::Instance.Update();
RichardE 5:0b0651ac7832 266 // Wait for frame flyback.
RichardE 5:0b0651ac7832 267 GD.waitvblank();
RichardE 5:0b0651ac7832 268 }
RichardE 5:0b0651ac7832 269 // Now wait until all sounds have finished.
RichardE 5:0b0651ac7832 270 while( SoundManager::Instance.CountSoundsPlaying() > 0 ) {
RichardE 5:0b0651ac7832 271 // Update sound manager.
RichardE 5:0b0651ac7832 272 SoundManager::Instance.Update();
RichardE 5:0b0651ac7832 273 // Wait for frame flyback.
RichardE 5:0b0651ac7832 274 GD.waitvblank();
RichardE 5:0b0651ac7832 275 }
RichardE 0:5fa232ee5fdf 276 #endif
RichardE 0:5fa232ee5fdf 277 }
RichardE 0:5fa232ee5fdf 278
RichardE 0:5fa232ee5fdf 279 /*************/
RichardE 0:5fa232ee5fdf 280 /* PLAY LOOP */
RichardE 0:5fa232ee5fdf 281 /*************/
RichardE 0:5fa232ee5fdf 282 // Returns code indicating how level ended.
RichardE 0:5fa232ee5fdf 283 // This method should be called from the Play method after the
RichardE 0:5fa232ee5fdf 284 // level data has been initialised and the return value returned
RichardE 0:5fa232ee5fdf 285 // by the Play method.
RichardE 5:0b0651ac7832 286 Level::LevelExitCode LevelNormal::PlayLoop( void )
RichardE 5:0b0651ac7832 287 {
RichardE 5:0b0651ac7832 288 // Do nothing if Gameduino has not been specified, level data is NULL or player has not been specified.
RichardE 5:0b0651ac7832 289 if( ( gd != (Gameduino*)NULL ) || ( DataForLevel != (LevelData*)NULL ) || ( player == (PlayerObject*)NULL ) ) {
RichardE 5:0b0651ac7832 290 // Point static pointer to current instance.
RichardE 5:0b0651ac7832 291 currentInstance = this;
RichardE 5:0b0651ac7832 292 // Do some initialisation first.
RichardE 5:0b0651ac7832 293 InitialiseLevel( gd );
RichardE 5:0b0651ac7832 294 // Redraw the screen.
RichardE 5:0b0651ac7832 295 DrawLevel();
RichardE 5:0b0651ac7832 296 // Wait for frame flyback once before entering loop so collision data is recalculated.
RichardE 5:0b0651ac7832 297 // At this point there should not be any sprites on the screen so no collisions
RichardE 5:0b0651ac7832 298 // should be found.
RichardE 5:0b0651ac7832 299 gd->waitvblank();
RichardE 5:0b0651ac7832 300 // Repeat until all enemies are dead or player is dead.
RichardE 5:0b0651ac7832 301 bool allEnemiesAreDead = false;
RichardE 5:0b0651ac7832 302 bool playerIsDead = false;
RichardE 5:0b0651ac7832 303 bool gameIsOver = false;
RichardE 5:0b0651ac7832 304 bool firstDraw = true;
RichardE 5:0b0651ac7832 305 while( ! allEnemiesAreDead && ! gameIsOver ) {
RichardE 5:0b0651ac7832 306 // Update sound manager.
RichardE 5:0b0651ac7832 307 // SoundManager::Instance.Update();
RichardE 5:0b0651ac7832 308 // Wait for frame flyback.
RichardE 5:0b0651ac7832 309 gd->waitvblank();
RichardE 5:0b0651ac7832 310 // Check for collisions between player and other objects.
RichardE 5:0b0651ac7832 311 CheckPlayerCollisions( &playerIsDead );
RichardE 5:0b0651ac7832 312 #if 0
RichardE 5:0b0651ac7832 313 // Check for collisions between humans and enemies that squash.
RichardE 5:0b0651ac7832 314 GameObject::FindCollisions( DataForLevel->Humans, LevelData::MaxHumans, &LevelNormal::HandleHumanCollision );
RichardE 5:0b0651ac7832 315 // Check for collisions between player bullets and enemies.
RichardE 5:0b0651ac7832 316 GameObject::FindCollisions( player->GetBullets(), BulletManager::MaxBullets, &LevelNormal::HandleBulletCollision );
RichardE 5:0b0651ac7832 317 #endif
RichardE 5:0b0651ac7832 318 // Redraw the player's score and number of lives.
RichardE 5:0b0651ac7832 319 DrawScoreAndLives();
RichardE 1:dfd5eaaf96a3 320 #if 0
RichardE 5:0b0651ac7832 321 // Draw all the enemies.
RichardE 5:0b0651ac7832 322 GameObject::DrawAll( DataForLevel->Enemies, LevelData::MaxEnemies );
RichardE 5:0b0651ac7832 323 // Draw all the humans.
RichardE 5:0b0651ac7832 324 GameObject::DrawAll( DataForLevel->Humans, LevelData::MaxHumans );
RichardE 5:0b0651ac7832 325 // Draw all the explosions.
RichardE 5:0b0651ac7832 326 GameObject::DrawAll( ExplosionManager::Instance.GetExplosions(), ExplosionManager::MaxExplosions );
RichardE 5:0b0651ac7832 327 #endif
RichardE 5:0b0651ac7832 328 // Draw the player.
RichardE 5:0b0651ac7832 329 player->Draw( gd );
RichardE 5:0b0651ac7832 330 // Draw the player's bullets.
RichardE 6:8bbdb70bc11c 331 GameObject::DrawAll( gd, player->GetBullets(), BulletManager::MaxBullets );
RichardE 5:0b0651ac7832 332 // Increment the frame counter.
RichardE 5:0b0651ac7832 333 FrameCounter++;
RichardE 5:0b0651ac7832 334 // After first redraw play level start sound and wait for it to end.
RichardE 5:0b0651ac7832 335 if( firstDraw ) {
RichardE 5:0b0651ac7832 336 // PlaySoundAndWait( Sounds::StartLevel );
RichardE 5:0b0651ac7832 337 firstDraw = false;
RichardE 1:dfd5eaaf96a3 338 }
RichardE 5:0b0651ac7832 339 // If player was killed then play death march and wait for it to finish.
RichardE 5:0b0651ac7832 340 if( playerIsDead ) {
RichardE 5:0b0651ac7832 341 #ifdef CHATTY
RichardE 5:0b0651ac7832 342 pc.puts( "Player got killed.\r\n" );
RichardE 5:0b0651ac7832 343 #endif
RichardE 5:0b0651ac7832 344 // Player got killed.
RichardE 5:0b0651ac7832 345 // PlaySoundAndWait( Sounds::PlayerDead );
RichardE 5:0b0651ac7832 346 // One less life for player.
RichardE 5:0b0651ac7832 347 if( player->Lives > 0 ) {
RichardE 5:0b0651ac7832 348 player->Lives--;
RichardE 5:0b0651ac7832 349 }
RichardE 5:0b0651ac7832 350 // Game is over when player has no more lives.
RichardE 5:0b0651ac7832 351 gameIsOver = ( player->Lives == 0 );
RichardE 5:0b0651ac7832 352 // If game is not over then re-initialise level using any remaining enemies.
RichardE 5:0b0651ac7832 353 if( ! gameIsOver ) {
RichardE 5:0b0651ac7832 354 #ifdef CHATTY
RichardE 5:0b0651ac7832 355 pc.puts( "Game is over.\r\n" );
RichardE 5:0b0651ac7832 356 #endif
RichardE 5:0b0651ac7832 357 // Remove all objects that do not survive a level restart (like enemy bullets).
RichardE 5:0b0651ac7832 358 GameObject::RemoveUnretainedObjects( DataForLevel->Enemies, LevelData::MaxEnemies );
RichardE 5:0b0651ac7832 359 InitialiseLevel( gd );
RichardE 5:0b0651ac7832 360 DrawLevel();
RichardE 5:0b0651ac7832 361 gd->waitvblank();
RichardE 5:0b0651ac7832 362 playerIsDead = false;
RichardE 5:0b0651ac7832 363 firstDraw = true;
RichardE 5:0b0651ac7832 364 }
RichardE 5:0b0651ac7832 365 }
RichardE 5:0b0651ac7832 366 else {
RichardE 5:0b0651ac7832 367 #if 0
RichardE 5:0b0651ac7832 368 // Move all the enemies and check if all dead.
RichardE 5:0b0651ac7832 369 allEnemiesAreDead = ! GameObject::MoveAll( DataForLevel->Enemies, LevelData::MaxEnemies );
RichardE 5:0b0651ac7832 370 // If there are still some enemies alive then check if those that remain are indestructable.
RichardE 5:0b0651ac7832 371 // If only indestructable enemies survive then act as if all enemies are dead.
RichardE 5:0b0651ac7832 372 // You need to do this or you would never be able to complete a level that had indestructable
RichardE 5:0b0651ac7832 373 // enemies on it.
RichardE 5:0b0651ac7832 374 if( ! allEnemiesAreDead ) {
RichardE 5:0b0651ac7832 375 allEnemiesAreDead = EnemyObject::AreAllIndestructable(
RichardE 6:8bbdb70bc11c 376 (const EnemyObject**)DataForLevel->Enemies,
RichardE 6:8bbdb70bc11c 377 LevelData::MaxEnemies
RichardE 6:8bbdb70bc11c 378 );
RichardE 5:0b0651ac7832 379 }
RichardE 5:0b0651ac7832 380 // Move all the humans.
RichardE 5:0b0651ac7832 381 GameObject::MoveAll( DataForLevel->Humans, LevelData::MaxHumans );
RichardE 5:0b0651ac7832 382 // Move (update) all the explosions.
RichardE 5:0b0651ac7832 383 GameObject::MoveAll( ExplosionManager::Instance.GetExplosions(), ExplosionManager::MaxExplosions );
RichardE 5:0b0651ac7832 384 #endif
RichardE 5:0b0651ac7832 385 // Read the player's controls.
RichardE 5:0b0651ac7832 386 player->ReadControls();
RichardE 5:0b0651ac7832 387 // Move the player.
RichardE 5:0b0651ac7832 388 player->Move();
RichardE 5:0b0651ac7832 389 // Move the player's bullets.
RichardE 5:0b0651ac7832 390 GameObject::MoveAll( player->GetBullets(), BulletManager::MaxBullets );
RichardE 0:5fa232ee5fdf 391 }
RichardE 1:dfd5eaaf96a3 392 }
RichardE 5:0b0651ac7832 393 // Player completed level or game is over.
RichardE 5:0b0651ac7832 394 return gameIsOver ? GameOver : Completed;
RichardE 0:5fa232ee5fdf 395 }
RichardE 5:0b0651ac7832 396 else {
RichardE 5:0b0651ac7832 397 // Level data or player were not specified.
RichardE 5:0b0651ac7832 398 return Completed;
RichardE 5:0b0651ac7832 399 }
RichardE 0:5fa232ee5fdf 400 }
RichardE 0:5fa232ee5fdf 401