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
Diff: LevelNormal.cpp
- Revision:
- 5:0b0651ac7832
- Parent:
- 1:dfd5eaaf96a3
- Child:
- 6:8bbdb70bc11c
--- a/LevelNormal.cpp Sat Jun 08 11:24:05 2013 +0000 +++ b/LevelNormal.cpp Sat Jun 08 14:40:47 2013 +0000 @@ -9,12 +9,19 @@ * */ +// Define this for debugging messages. +#define CHATTY + +#ifdef CHATTY + #include "mbed.h" + extern Serial pc; +#endif + #include "LevelNormal.h" -#if 0 - #include "GameObjectLocator.h" - #include "FrameCounter.h" - #include "SpriteNumber.h" -#endif +#include "GameObjectLocator.h" +#include "FrameCounter.h" +#include "SpriteNumber.h" +#include "ArenaConst.h" // Current instance being processed. LevelNormal *LevelNormal::currentInstance; @@ -22,93 +29,96 @@ /***************/ /* CONSTRUCTOR */ /***************/ -LevelNormal::LevelNormal() { +LevelNormal::LevelNormal() +{ } /**************/ /* DESTRUCTOR */ /**************/ -LevelNormal::~LevelNormal() { +LevelNormal::~LevelNormal() +{ } /********************/ /* INITIALISE LEVEL */ /********************/ -void LevelNormal::InitialiseLevel( void ) { -#if 0 +// Pass pointer to Gameduino to draw on in gd. +void LevelNormal::InitialiseLevel( Gameduino *gd ) +{ // Note that if you re-arrange the following code you may need to adjust the // SpriteNumber enumeration in SpriteNumber.h. - UInt8 spriteNumber = FirstEnemySprite; - // Initialise enemies. - GameObject::InitialiseAll( DataForLevel->Enemies, LevelData::MaxEnemies, &spriteNumber ); - // Initialise humans. + UInt8 spriteNumber = FirstEnemySprite; + // Initialise enemies. + GameObject::InitialiseAll( DataForLevel->Enemies, LevelData::MaxEnemies, &spriteNumber ); + // Initialise humans. spriteNumber = FirstHumanSprite; - GameObject::InitialiseAll( DataForLevel->Humans, LevelData::MaxHumans, &spriteNumber ); - // Use next free sprite number for player. - player->SpriteNumber = PlayerSprite; - // Do futher initialisation for all enemies. - EnemyObject *object; - for( UInt8 e = 0; e < LevelData::MaxEnemies; ++e ) { - object = (EnemyObject*)DataForLevel->Enemies[ e ]; - if( object != (EnemyObject*)NULL ) { + GameObject::InitialiseAll( DataForLevel->Humans, LevelData::MaxHumans, &spriteNumber ); + // Use next free sprite number for player. + player->SpriteNumber = PlayerSprite; + // Do futher initialisation for all enemies. +#if 0 + EnemyObject *object; + for( UInt8 e = 0; e < LevelData::MaxEnemies; ++e ) { + object = (EnemyObject*)DataForLevel->Enemies[ e ]; + if( object != (EnemyObject*)NULL ) { // Get enemy to chase the player. - object->SetChaseObject( player ); + object->SetChaseObject( player ); // Pass array of all enemies to this enemy. object->Enemies = DataForLevel->Enemies; // If enemy is a brain then tell it about the humans to chase. if( object->GetEnemyType() == Brain ) { ((BrainObject*)object)->HumansToChase = DataForLevel->Humans; } + } } - } - // Put player in the centre of the arena. - player->Xco = PLAYER_START_X; - player->Yco = PLAYER_START_Y; - // Kill off all player's bullets. - player->KillAllBullets(); - // Kill off all explosions. - ExplosionManager::Instance.KillAllExplosions(); #endif + // Put player in the centre of the arena. + player->Xco = PLAYER_START_X; + player->Yco = PLAYER_START_Y; + // Kill off all player's bullets. + player->KillAllBullets( gd ); + // Kill off all explosions. + // ExplosionManager::Instance.KillAllExplosions(); } /**********************************/ /* DRAW SCORE AND NUMBER OF LIVES */ /**********************************/ -void LevelNormal::DrawScoreAndLives( void ) { -#if 0 - GDExtra::WriteBCDNumber( 16, 0, player->Score, 8 ); - // Display number of lives but limit this to 20 lives displayed. - UInt8 lives = ( player->Lives > 20 ) ? 20 : player->Lives; - GD.fill( RAM_PIC + VISIBLE_CHAR_WIDTH - lives, MiniPlayer, lives ); -#endif +void LevelNormal::DrawScoreAndLives( void ) +{ + GDExtra::WriteBCDNumber( gd, 16, 0, player->Score, 8 ); + // Display number of lives but limit this to 20 lives displayed. + UInt8 lives = ( player->Lives > 20 ) ? 20 : player->Lives; + gd->fill( Gameduino::RAM_PIC + VISIBLE_CHAR_WIDTH - lives, MiniPlayer, lives ); } /******************/ /* DRAW THE LEVEL */ /******************/ -void LevelNormal::DrawLevel( void ) { - // Set screen background to black. - gd->wr( Gameduino::BG_COLOR, Gameduino::RGB( 0, 0, 0 ) ); - // Clear the screen to zero characters. - GDExtra::ClearScreen( gd, TransparentChar ); - // Hide all sprties. - GDExtra::HideAllSprites( gd ); - // Display level number. - GDExtra::WriteProgString( gd, 0, 0, StringData::LevelString ); - GDExtra::WriteUInt16( gd, 6, 0, LevelNumber, 10, 2 ); - // Display score. - GDExtra::WriteProgString( gd, 10, 0, StringData::ScoreString ); - #if 0 - // Update score and lives. - DrawScoreAndLives(); - // Draw border around screen. - CharFrame::Draw( - ARENA_BORDER_X, - ARENA_BORDER_Y, - ARENA_BORDER_WIDTH, - ARENA_BORDER_HEIGHT - ); - #endif +void LevelNormal::DrawLevel( void ) +{ + // Set screen background to black. + gd->wr( Gameduino::BG_COLOR, Gameduino::RGB( 0, 0, 0 ) ); + // Clear the screen to zero characters. + GDExtra::ClearScreen( gd, TransparentChar ); + // Hide all sprties. + GDExtra::HideAllSprites( gd ); + // Display level number. + GDExtra::WriteProgString( gd, 0, 0, StringData::LevelString ); + GDExtra::WriteUInt16( gd, 6, 0, LevelNumber, 10, 2 ); + // Display score. + GDExtra::WriteProgString( gd, 10, 0, StringData::ScoreString ); + // Update score and lives. + DrawScoreAndLives(); + // Draw border around screen. + CharFrame::Draw( + gd, + ARENA_BORDER_X, + ARENA_BORDER_Y, + ARENA_BORDER_WIDTH, + ARENA_BORDER_HEIGHT + ); } /************************************************/ @@ -116,16 +126,17 @@ /************************************************/ // Pass index of human in level's humans array in humanIndex. // Pass sprite number of sprite that it hit in spriteNumber. -void LevelNormal::HandleHumanCollision( UInt8 humanIndex, UInt8 spriteNumber ) { +void LevelNormal::HandleHumanCollision( UInt8 humanIndex, UInt8 spriteNumber ) +{ #if 0 - // Point to array of enemy object pointers. - GameObject **enemies = currentInstance->DataForLevel->Enemies; - EnemyObject *enemy; - UInt8 enemyIndex, mutantIndex; - // Find an enemy with given sprite number. - if( GameObject::FindSpriteNumber( enemies, LevelData::MaxEnemies, spriteNumber, &enemyIndex ) ) { - // Found enemy. Check if it squashes humans. - enemy = (EnemyObject*)enemies[ enemyIndex ]; + // Point to array of enemy object pointers. + GameObject **enemies = currentInstance->DataForLevel->Enemies; + EnemyObject *enemy; + UInt8 enemyIndex, mutantIndex; + // Find an enemy with given sprite number. + if( GameObject::FindSpriteNumber( enemies, LevelData::MaxEnemies, spriteNumber, &enemyIndex ) ) { + // Found enemy. Check if it squashes humans. + enemy = (EnemyObject*)enemies[ enemyIndex ]; // Get hold of the human that is doomed. GameObject **humans = currentInstance->DataForLevel->Humans; HumanObject *human = (HumanObject*)humans[ humanIndex ]; @@ -136,8 +147,7 @@ human->CurrentState = HumanObject::Dead; // Make a noise. SoundManager::Instance.PlaySound( Sounds::HumanDies, 0, 0 ); - } - else if( enemy->GetEnemyType() == Brain ) { + } else if( enemy->GetEnemyType() == Brain ) { // Kill human by inserting a null into humans array. humans[ humanIndex ] = (GameObject*)NULL; // Find a free slot for a new enemy. @@ -150,8 +160,7 @@ mutant->Start( human, currentInstance->player ); // Make a noise. // TODO : SoundManager::Instance.PlaySound( Sounds::HumanMutates, 0, 0 ); - } - else { + } else { // Could not find a free slot for a new enemy so just erase the human sprite. GDExtra::HideSprite( human->SpriteNumber ); } @@ -166,16 +175,17 @@ /********************************************************/ // Pass index of bullet in player's bullet array in bulletIndex. // Pass sprite number of sprite that it hit in spriteNumber. -void LevelNormal::HandleBulletCollision( UInt8 bulletIndex, UInt8 spriteNumber ) { +void LevelNormal::HandleBulletCollision( UInt8 bulletIndex, UInt8 spriteNumber ) +{ #if 0 - // Point to array of enemy object pointers. - GameObject **enemies = currentInstance->DataForLevel->Enemies; - EnemyObject *enemy; - UInt8 enemyIndex; - // Find an enemy with given sprite number. - if( GameObject::FindSpriteNumber( enemies, LevelData::MaxEnemies, spriteNumber, &enemyIndex ) ) { - // Found enemy. Check if it is indestructable. - enemy = (EnemyObject*)enemies[ enemyIndex ]; + // Point to array of enemy object pointers. + GameObject **enemies = currentInstance->DataForLevel->Enemies; + EnemyObject *enemy; + UInt8 enemyIndex; + // Find an enemy with given sprite number. + if( GameObject::FindSpriteNumber( enemies, LevelData::MaxEnemies, spriteNumber, &enemyIndex ) ) { + // Found enemy. Check if it is indestructable. + enemy = (EnemyObject*)enemies[ enemyIndex ]; if( enemy->HitPoints != EnemyObject::Indestructable ) { // Enemy is not indestructable. Decrement hit points and die when it reaches zero. enemy->HitPoints--; @@ -196,7 +206,7 @@ SoundManager::Instance.PlaySound( Sounds::Explosion, 0, 0 ); // Start explosion animation using coordinates of enemy. ExplosionManager::Instance.StartExplosion( enemy->Xco, enemy->Yco ); - } + } #endif } @@ -204,29 +214,30 @@ /* CHECK FOR COLLISIONS BETWEEN PLAYER AND OTHER OBJECTS */ /*********************************************************/ // Pass pointer to a flag that will be set true if player is dead in isDead parameter. -void LevelNormal::CheckPlayerCollisions( bool *isDead ) { +void LevelNormal::CheckPlayerCollisions( bool *isDead ) +{ #if 0 - UInt8 enemyIndex, humanIndex; - // Check if player sprite has hit another sprite. - UInt8 hitSpriteNumber = GD.rd( COLLISION + player->SpriteNumber ); - // If you get 0xFF then no collision found. - if( hitSpriteNumber != 0xFF ) { - // Check for collision with an enemy. - if( - GameObject::FindSpriteNumber( - DataForLevel->Enemies, LevelData::MaxEnemies, hitSpriteNumber, &enemyIndex - ) - ) { - // Hit an enemy. Player is dead. - *isDead = true; - } - // Check for collision with a human that has not already been rescued or killed. - else if( - GameObject::FindSpriteNumber( - DataForLevel->Humans, LevelData::MaxHumans, hitSpriteNumber, &humanIndex - ) - ) { - HumanObject *human = (HumanObject*)DataForLevel->Humans[ humanIndex ]; + UInt8 enemyIndex, humanIndex; + // Check if player sprite has hit another sprite. + UInt8 hitSpriteNumber = GD.rd( COLLISION + player->SpriteNumber ); + // If you get 0xFF then no collision found. + if( hitSpriteNumber != 0xFF ) { + // Check for collision with an enemy. + if( + GameObject::FindSpriteNumber( + DataForLevel->Enemies, LevelData::MaxEnemies, hitSpriteNumber, &enemyIndex + ) + ) { + // Hit an enemy. Player is dead. + *isDead = true; + } + // Check for collision with a human that has not already been rescued or killed. + else if( + GameObject::FindSpriteNumber( + DataForLevel->Humans, LevelData::MaxHumans, hitSpriteNumber, &humanIndex + ) + ) { + HumanObject *human = (HumanObject*)DataForLevel->Humans[ humanIndex ]; if( human->CurrentState == HumanObject::WalkingAbout ) { // Change human state to rescued. human->CurrentState = HumanObject::Rescued; @@ -235,8 +246,8 @@ // Make a noise. SoundManager::Instance.PlaySound( Sounds::RescueHuman, 0, 0 ); } - } - } + } + } #endif } @@ -244,23 +255,24 @@ /* WAIT UNTIL SLOT FREE FOR A NEW SOUND, PLAY IT AND WAIT FOR ALL SOUNDS TO FINISH */ /***********************************************************************************/ // Pass sound to play in soundToPlay parameter. -void LevelNormal::PlaySoundAndWait( const UInt8 *soundToPlay ) { +void LevelNormal::PlaySoundAndWait( const UInt8 *soundToPlay ) +{ #if 0 - // Keep trying to play sound until it works and meanwhile - // keep currently playing sounds going. - while( ! SoundManager::Instance.PlaySound( soundToPlay, 0, 0 ) ) { - // Update sound manager. - SoundManager::Instance.Update(); - // Wait for frame flyback. - GD.waitvblank(); - } - // Now wait until all sounds have finished. - while( SoundManager::Instance.CountSoundsPlaying() > 0 ) { - // Update sound manager. - SoundManager::Instance.Update(); - // Wait for frame flyback. - GD.waitvblank(); - } + // Keep trying to play sound until it works and meanwhile + // keep currently playing sounds going. + while( ! SoundManager::Instance.PlaySound( soundToPlay, 0, 0 ) ) { + // Update sound manager. + SoundManager::Instance.Update(); + // Wait for frame flyback. + GD.waitvblank(); + } + // Now wait until all sounds have finished. + while( SoundManager::Instance.CountSoundsPlaying() > 0 ) { + // Update sound manager. + SoundManager::Instance.Update(); + // Wait for frame flyback. + GD.waitvblank(); + } #endif } @@ -271,108 +283,119 @@ // This method should be called from the Play method after the // level data has been initialised and the return value returned // by the Play method. -Level::LevelExitCode LevelNormal::PlayLoop( void ) { - // Do nothing if Gameduino has not been specified, level data is NULL or player has not been specified. - if( ( gd != (Gameduino*)NULL ) /* || ( DataForLevel != (LevelData*)NULL ) || ( player == (PlayerObject*)NULL ) */ ) { - // Point static pointer to current instance. - currentInstance = this; - // Do some initialisation first. - InitialiseLevel(); - // Redraw the screen. - DrawLevel(); - // Wait for frame flyback once before entering loop so collision data is recalculated. - // At this point there should not be any sprites on the screen so no collisions - // should be found. - gd->waitvblank(); +Level::LevelExitCode LevelNormal::PlayLoop( void ) +{ + // Do nothing if Gameduino has not been specified, level data is NULL or player has not been specified. + if( ( gd != (Gameduino*)NULL ) || ( DataForLevel != (LevelData*)NULL ) || ( player == (PlayerObject*)NULL ) ) { + // Point static pointer to current instance. + currentInstance = this; + // Do some initialisation first. + InitialiseLevel( gd ); + // Redraw the screen. + DrawLevel(); + // Wait for frame flyback once before entering loop so collision data is recalculated. + // At this point there should not be any sprites on the screen so no collisions + // should be found. + gd->waitvblank(); + // Repeat until all enemies are dead or player is dead. + bool allEnemiesAreDead = false; + bool playerIsDead = false; + bool gameIsOver = false; + bool firstDraw = true; + while( ! allEnemiesAreDead && ! gameIsOver ) { + // Update sound manager. + // SoundManager::Instance.Update(); + // Wait for frame flyback. + gd->waitvblank(); + // Check for collisions between player and other objects. + CheckPlayerCollisions( &playerIsDead ); +#if 0 + // Check for collisions between humans and enemies that squash. + GameObject::FindCollisions( DataForLevel->Humans, LevelData::MaxHumans, &LevelNormal::HandleHumanCollision ); + // Check for collisions between player bullets and enemies. + GameObject::FindCollisions( player->GetBullets(), BulletManager::MaxBullets, &LevelNormal::HandleBulletCollision ); +#endif + // Redraw the player's score and number of lives. + DrawScoreAndLives(); #if 0 - // Repeat until all enemies are dead or player is dead. - bool allEnemiesAreDead = false; - bool playerIsDead = false; - bool gameIsOver = false; - bool firstDraw = true; - while( ! allEnemiesAreDead && ! gameIsOver ) { - // Update sound manager. - SoundManager::Instance.Update(); - // Wait for frame flyback. - GD.waitvblank(); - // Check for collisions between player and other objects. - CheckPlayerCollisions( &playerIsDead ); - // Check for collisions between humans and enemies that squash. - GameObject::FindCollisions( DataForLevel->Humans, LevelData::MaxHumans, &LevelNormal::HandleHumanCollision ); - // Check for collisions between player bullets and enemies. - GameObject::FindCollisions( player->GetBullets(), BulletManager::MaxBullets, &LevelNormal::HandleBulletCollision ); - // Redraw the player's score and number of lives. - DrawScoreAndLives(); - // Draw all the enemies. - GameObject::DrawAll( DataForLevel->Enemies, LevelData::MaxEnemies ); - // Draw all the humans. - GameObject::DrawAll( DataForLevel->Humans, LevelData::MaxHumans ); - // Draw all the explosions. - GameObject::DrawAll( ExplosionManager::Instance.GetExplosions(), ExplosionManager::MaxExplosions ); - // Draw the player. - player->Draw(); - // Draw the player's bullets. - GameObject::DrawAll( player->GetBullets(), BulletManager::MaxBullets ); - // Increment the frame counter. - FrameCounter++; - // After first redraw play level start sound and wait for it to end. - if( firstDraw ) { - PlaySoundAndWait( Sounds::StartLevel ); - firstDraw = false; - } - // If player was killed then play death march and wait for it to finish. - if( playerIsDead ) { - // Player got killed. - PlaySoundAndWait( Sounds::PlayerDead ); - // One less life for player. - if( player->Lives > 0 ) { - player->Lives--; + // Draw all the enemies. + GameObject::DrawAll( DataForLevel->Enemies, LevelData::MaxEnemies ); + // Draw all the humans. + GameObject::DrawAll( DataForLevel->Humans, LevelData::MaxHumans ); + // Draw all the explosions. + GameObject::DrawAll( ExplosionManager::Instance.GetExplosions(), ExplosionManager::MaxExplosions ); +#endif + // Draw the player. + player->Draw( gd ); + // Draw the player's bullets. + GameObject::DrawAll( player->GetBullets(), BulletManager::MaxBullets ); + // Increment the frame counter. + FrameCounter++; + // After first redraw play level start sound and wait for it to end. + if( firstDraw ) { + // PlaySoundAndWait( Sounds::StartLevel ); + firstDraw = false; } - // Game is over when player has no more lives. - gameIsOver = ( player->Lives == 0 ); - // If game is not over then re-initialise level using any remaining enemies. - if( ! gameIsOver ) { - // Remove all objects that do not survive a level restart (like enemy bullets). - GameObject::RemoveUnretainedObjects( DataForLevel->Enemies, LevelData::MaxEnemies ); - InitialiseLevel(); - DrawLevel(); - GD.waitvblank(); - playerIsDead = false; - firstDraw = true; + // If player was killed then play death march and wait for it to finish. + if( playerIsDead ) { + #ifdef CHATTY + pc.puts( "Player got killed.\r\n" ); + #endif + // Player got killed. + // PlaySoundAndWait( Sounds::PlayerDead ); + // One less life for player. + if( player->Lives > 0 ) { + player->Lives--; + } + // Game is over when player has no more lives. + gameIsOver = ( player->Lives == 0 ); + // If game is not over then re-initialise level using any remaining enemies. + if( ! gameIsOver ) { + #ifdef CHATTY + pc.puts( "Game is over.\r\n" ); + #endif + // Remove all objects that do not survive a level restart (like enemy bullets). + GameObject::RemoveUnretainedObjects( DataForLevel->Enemies, LevelData::MaxEnemies ); + InitialiseLevel( gd ); + DrawLevel(); + gd->waitvblank(); + playerIsDead = false; + firstDraw = true; + } + } + else { +#if 0 + // Move all the enemies and check if all dead. + allEnemiesAreDead = ! GameObject::MoveAll( DataForLevel->Enemies, LevelData::MaxEnemies ); + // If there are still some enemies alive then check if those that remain are indestructable. + // If only indestructable enemies survive then act as if all enemies are dead. + // You need to do this or you would never be able to complete a level that had indestructable + // enemies on it. + if( ! allEnemiesAreDead ) { + allEnemiesAreDead = EnemyObject::AreAllIndestructable( + (const EnemyObject**)DataForLevel->Enemies, + LevelData::MaxEnemies + ); + } + // Move all the humans. + GameObject::MoveAll( DataForLevel->Humans, LevelData::MaxHumans ); + // Move (update) all the explosions. + GameObject::MoveAll( ExplosionManager::Instance.GetExplosions(), ExplosionManager::MaxExplosions ); +#endif + // Read the player's controls. + player->ReadControls(); + // Move the player. + player->Move(); + // Move the player's bullets. + GameObject::MoveAll( player->GetBullets(), BulletManager::MaxBullets ); } } - else { - // Move all the enemies and check if all dead. - allEnemiesAreDead = ! GameObject::MoveAll( DataForLevel->Enemies, LevelData::MaxEnemies ); - // If there are still some enemies alive then check if those that remain are indestructable. - // If only indestructable enemies survive then act as if all enemies are dead. - // You need to do this or you would never be able to complete a level that had indestructable - // enemies on it. - if( ! allEnemiesAreDead ) { - allEnemiesAreDead = EnemyObject::AreAllIndestructable( - (const EnemyObject**)DataForLevel->Enemies, - LevelData::MaxEnemies - ); - } - // Move all the humans. - GameObject::MoveAll( DataForLevel->Humans, LevelData::MaxHumans ); - // Move (update) all the explosions. - GameObject::MoveAll( ExplosionManager::Instance.GetExplosions(), ExplosionManager::MaxExplosions ); - // Read the player's controls. - player->ReadControls(); - // Move the player. - player->Move(); - // Move the player's bullets. - GameObject::MoveAll( player->GetBullets(), BulletManager::MaxBullets ); - } + // Player completed level or game is over. + return gameIsOver ? GameOver : Completed; } -#endif - // Player completed level or game is over. - return /* gameIsOver ? GameOver : */ Completed; - } - else { - // Level data or player were not specified. - return Completed; - } + else { + // Level data or player were not specified. + return Completed; + } }