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
LevelNormal.cpp@7:e72691603fd3, 2013-06-08 (annotated)
- 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?
User | Revision | Line number | New 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 |