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 14:40:47 2013 +0000
Revision:
5:0b0651ac7832
Parent:
1:dfd5eaaf96a3
Child:
6:8bbdb70bc11c
Now got first real level starting and player can be controlled using joysticks. No bullets, enemies, humans or sound yet.

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 5:0b0651ac7832 331 GameObject::DrawAll( 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 5:0b0651ac7832 376 (const EnemyObject**)DataForLevel->Enemies,
RichardE 5:0b0651ac7832 377 LevelData::MaxEnemies
RichardE 5:0b0651ac7832 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