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:
Tue Jun 04 20:16:33 2013 +0000
Revision:
0:5fa232ee5fdf
Child:
1:dfd5eaaf96a3
Started conversion from Maple version of game. So far Gameduino seems to have been initialised OK and just displays a sign on message. Lots of commented out code.

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