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 16:44:54 2013 +0000
Revision:
7:e72691603fd3
Parent:
6:8bbdb70bc11c
Child:
8:82d88f9381f3
Now have grunts wandering around on level 1. They follow the player but since no collision detection logic yet nobody ever gets killed.

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