//Name: GAMELOOP.cpp //Description: This class puts together every object, interact them // and manages the game. The game core. // //Copyright 2004 Francis Huang, All Rights Reserved. //______________________________________________________________________________ #include "GAMELOOP.h" //__________________________________________________________________________ bool GAMELOOP::isSingletonCreated = false; //Singleton init. GAMELOOP* GAMELOOP::singletonInstance = NULL; //____________________________________________________________________________ GAMELOOP* GAMELOOP::CreateSingleton() //Create singleton instance. { if(!isSingletonCreated) { isSingletonCreated = true; singletonInstance = new GAMELOOP(); } if(!singletonInstance) { MessageBox(g_hWindow, "Create gameloop object failed!", "Error", MB_OK | MB_ICONINFORMATION); PostQuitMessage(0); g_errorLog.OutputError("Create gameloop object failed!"); } return singletonInstance; } //____________________________________________________________________________ GAMELOOP::GAMELOOP(): bat(new BAT()), level(LEVEL::CreateSingleton()), ball(new BALL()), world(new WORLD()), timeMachine(TIMEMACHINE::CreateSingleton()), highScore(HIGHSCORE::CreateSingleton()), menu(new MENU()), scoreBoard(new SCOREBOARD()), movie(new MOVIE()), boomBox(new BOOMBOX()), option(OPTION::CreateSingleton()), fontGenerator(FONTGENERATOR::CreateSingleton()), bitmapGenerator(BITMAPGENERATOR::CreateSingleton()), isNewGame(true), isIntroMovie(true), isGameConquered(false), isHighScoreTable(false), isOption(false), isEndMovie(false), isMenu(true), levelAt(1), scoreAt(0), lifeAt(3) { } //______________________________________________________________________________ GAMELOOP::~GAMELOOP() { FreeUselessPlayThings(); isSingletonCreated = false; } //______________________________________________________________________________ void GAMELOOP::Init() { fontGenerator->Init(); //Must be initialized before other font related object. bitmapGenerator->Init(); //Must be initialized before other bitmap related object. timeMachine->Init(); ball->Init(); bat->Init(*bitmapGenerator); world->Init(*bitmapGenerator); level->Init(*bitmapGenerator); boomBox->Init(); highScore->Init(*fontGenerator); menu->Init(*fontGenerator); scoreBoard->Init(*fontGenerator); movie->Init(*fontGenerator); option->Init(isHighSpeedOption, isMusicOption, isSoundOption, *fontGenerator); //timeBeginPeriod(1); } //______________________________________________________________________________ void GAMELOOP::LoopForever() { //1 //---------------------------------------- if(isIntroMovie) //Play introduction movie for a while when game first start. { movie->Intro(); MovieExit(isIntroMovie, isEndMovie); } //2 //---------------------------------------- if(isEndMovie) //Play end movie for a while when game completed. { movie->End(); MovieExit(isIntroMovie, isEndMovie); } //3 //---------------------------------------- //---------------------------------------- //---------------------------------------- ManagePlayThings(); //The core of the game. //---------------------------------------- //---------------------------------------- //4 //---------------------------------------- Cheat(); //Cheat codes must be here for the loop to be function properly. //5 //---------------------------------------- if(!level->GetLifeState()) //If one level is completed. { boomBox->playClapSound(); RestartPlayThings(); } level->Coordinate(isNewGame, isGameConquered, lifeAt, levelAt); //Levels coordination. //6 //---------------------------------------- if(isNewGame) //Start a new game with 3 new balls. { scoreAt = 0; lifeAt = 3; isNewGame = !isNewGame; FreeUselessPlayThings(); RestartPlayThings(); } //7 //---------------------------------------- if(isGameConquered) //If user conquered the game. { lifeAt = -1; } //8 //---------------------------------------- if(lifeAt > 0) //High score table display during gameplay. { if(isHighScoreTable) //Display high score table. highScore->Display(isHighScoreTable); } //9 //---------------------------------------- if(lifeAt <=0) //When run out of life. { //a---------------------------------------- if(!isHighScoreTable) //Get name if high score. { if(highScore->IsHighScore(scoreAt)) { DialogBox(GetModuleHandle(NULL), MAKEINTRESOURCE(IDD_NAME), g_hWindow, AboutDlgProc); highScore->NewHighScore(scoreAt, g_playerName); highScore->Save(); } } //b---------------------------------------- isHighScoreTable = true; if(!isIntroMovie && !isEndMovie && !isOption && !isMenu && isHighScoreTable) //Display high score table. { highScore->Display(isHighScoreTable); } //c---------------------------------------- if(!isHighScoreTable) //After return button pressed, exit high score table. { isNewGame = true; //Reset the game state. scoreAt = 0; lifeAt = 3; if(isGameConquered) { isGameConquered = false; isEndMovie = true; } isMenu = true; } } //10//---------------------------------------- EscKey(isMenu); //When escape key pressed, pop up menu. if(isMenu) //This is a protection interlock for a menu overlapping problem in windows xp probably due to timing problem { isOption = false; isHighScoreTable = false; } if(!isIntroMovie && !isEndMovie && isMenu && !isOption && !isHighScoreTable) { menu->Display(isNewGame, isMenu, isHighScoreTable, isOption); } if(!isIntroMovie && !isEndMovie && isOption && !isMenu && !isHighScoreTable) { option->Update(isOption, isMenu, isHighSpeedOption, isMusicOption, isSoundOption); } if(!isIntroMovie && !isEndMovie && !isMenu && !isOption && !isHighScoreTable) { scoreBoard->Display(lifeAt, scoreAt, levelAt); } boomBox->LoopForever(isMusicOption, isSoundOption); timeMachine->CalculateFrameRate(); //timeMachine->ClampFrameRate(0.015f); //Clamp frame rate at 66 fps, or 0.015 seconds per frame. 13/4/04 This function does not work with graphics card. } //______________________________________________________________________________ void GAMELOOP::ManagePlayThings() { static bool newBallFlag = true; //A new ball but not a new game. 3 balls/life in a game. //1---------------------------------------- if(newBallFlag ) //If a new ball, reset play things. { RestartPlayThings(); newBallFlag = !newBallFlag; } //2---------------------------------------- if(!ball->GetLifeState() || !bat->GetLifeState()) //If ball falls off or bat hit by bomb, they die. { boomBox->playOwSound(); newBallFlag = true; lifeAt --; } //3---------------------------------------- if(!isIntroMovie && !isEndMovie && !isMenu && !isHighScoreTable && !isOption) //Block off the background so we can see menu and high score. { UpdatePlayThings(); } //4---------------------------------------- PauseUnpausePlayThings(); /* static float UpdateTimer = timeGetTime(); // Limit all frame updates to plaything objects movement. if(timeGetTime() < UpdateTimer + 33) // 13/4/04 Modification since timeMachine->ClampFrameRate() seems to fail on video cards. return; //19/4/04 Lose it, doesn't work UpdateTimer = timeGetTime(); //float currentTime = timeMachine->GetTime()*0.001f; //For time based movement. 19.4.04 float currentTime = timeGetTime()*0.0000004f; //For time based movement. 19.4.04 static float lastFrameTime; static float frameInterval = currentTime - lastFrameTime; lastFrameTime = currentTime;*/ //4---------------------------------------- if(!isIntroMovie && !isEndMovie && !isMenu && !isHighScoreTable && !isOption) { InteractPlayThings(); ball->SetHighSpeedOption(isHighSpeedOption); //ball->Move(frameInterval); ball->Move(); //bat->Move(frameInterval); bat->Move(); for(iBomb=vBomb.begin(); iBomb < vBomb.end(); ++iBomb) { //(*iBomb)->Move(frameInterval); (*iBomb)->Move(); } for(iExplosion=vExplosion.begin(); iExplosion < vExplosion.end(); ++iExplosion) { //(*iExplosion)->Move(frameInterval); (*iExplosion)->Move(); } } } //______________________________________________________________________________ void GAMELOOP::RestartPlayThings() //Whenever a new game starts. { ball->Restart(); bat->Restart(); ball->BringToLife(); bat->BringToLife(); FreeUselessPlayThings(); } //______________________________________________________________________________ void GAMELOOP::UpdatePlayThings() { level->Update(); bat->Update(); world->SetLevelAt(levelAt); world->Update(); ball->Update(); for(iBomb=vBomb.begin(); iBomb < vBomb.end(); ++iBomb) { (*iBomb)->Update(); } for(iExplosion=vExplosion.begin(); iExplosion < vExplosion.end(); ++iExplosion) { (*iExplosion)->Update(); if(!(*iExplosion)->GetLifeState()) //If explosion fade off, free the explosion memory. { EXPLOSION* temp = *iExplosion; vExplosion.erase(iExplosion); delete temp; temp = NULL; } if(iExplosion == vExplosion.end() ) break; } } //______________________________________________________________________________ void GAMELOOP::PauseUnpausePlayThings() { if(isMenu || isHighScoreTable) //Unpause when menu or high score table is off. { ball->Pause(); bat->Pause(); for(iBomb=vBomb.begin(); iBomb < vBomb.end(); ++iBomb) { (*iBomb)->Pause(); } } //---------------------------------------- if(!isMenu && !isHighScoreTable) //Pause when menu or high score table is on. { ball->UnPause(); bat->UnPause(); for(iBomb=vBomb.begin(); iBomb < vBomb.end(); ++iBomb) { (*iBomb)->UnPause(); } } } //______________________________________________________________________________ void GAMELOOP::InteractPlayThings() { //1---------------------------------------- if(level->Collision(*ball)) //If level collide with ball. { boomBox->playBoxHitSound(); //a---------------------------------------- if(level->GetScoringState()) //if level hit, add some score. { ++scoreAt; level->NoScoring(); } //b---------------------------------------- if(level->GetBombingState()) //If level's red block hit, init bombs. { vBomb.push_back(new BOMB(*level, *bitmapGenerator)); level->DeactivateBomb(); } //c---------------------------------------- vExplosion.push_back(new EXPLOSION(*level, *bitmapGenerator)); //if level hit, init explosion. //d---------------------------------------- ball->ResolveCollision(*level); //Resolve collision by exchanging collision response speed factors. } //2---------------------------------------- if(bat->Collision(*ball)) //If bat collide with ball. { boomBox->playBatHitSound(); ball->ResolveCollision(*bat); } //3---------------------------------------- if(world->Collision(*ball)) //If ball collide with world. { boomBox->playWallHitSound(); ball->ResolveCollision(*world); } //4---------------------------------------- for(iBomb=vBomb.begin(); iBomb < vBomb.end(); ++iBomb) { if((*iBomb)->Collision(*bat)) //If bombs collide with bat. { bat->ResolveCollision(**iBomb); for(iBomb=vBomb.begin(); iBomb < vBomb.end(); ++iBomb) { (*iBomb)->ExpelFarAway(); //If collide with bat, expel bombs far away to avoid collision errors. } } } //5---------------------------------------- for(iBomb=vBomb.begin(); iBomb < vBomb.end(); ++iBomb) { if(world->Collision(**iBomb)) //If bombs collision with world free up some memory. { PLAYTHING* temp = *iBomb; vBomb.erase(iBomb); delete temp; temp = NULL; } } } //______________________________________________________________________________ void GAMELOOP:: EscKey(bool &isMenu) //When escape key pressed, pop up menu. { static bool isEscape; if(KEYSTATE(VK_ESCAPE) && !isEscape) { if(!isHighScoreTable) isMenu = true; isEscape = true; } if(!KEYSTATE(VK_ESCAPE)) { isEscape = false; } } //______________________________________________________________________________ void GAMELOOP::FreeUselessPlayThings() { for(iBomb=vBomb.begin(); iBomb < vBomb.end(); ++iBomb) { //Free up bombs. PLAYTHING* temp = *iBomb; vBomb.erase(iBomb); delete temp; temp = NULL; if(iBomb == vBomb.end()) break; } for(iExplosion=vExplosion.begin(); iExplosion < vExplosion.end(); ++iExplosion) { //Free up explosions. EXPLOSION* temp = *iExplosion; vExplosion.erase(iExplosion); delete temp; temp = NULL; if(iExplosion == vExplosion.end()) break; } } //______________________________________________________________________________ void GAMELOOP::Cheat() //Cheat codes for testing, troubleshooting, and donation. { static bool isLifeCheat; static bool isScoreCheat; static bool isLevelCheat; //1---------------------------------------- if(KEYSTATE(VK_F12) && !isLifeCheat) { ++lifeAt; isLifeCheat = true; } if(!KEYSTATE(VK_F12)) isLifeCheat = false; //2---------------------------------------- if(KEYSTATE(VK_F9) && !isLevelCheat) { level->Kill(); isLevelCheat = true; } if(!KEYSTATE(VK_F9)) isLevelCheat = false; //3---------------------------------------- if(KEYSTATE(VK_F11) && !isScoreCheat) { ++scoreAt; isScoreCheat = true; } if(!KEYSTATE(VK_F11)) isScoreCheat = false; } //______________________________________________________________________________ bool GAMELOOP::Pause(const int pauseTime) { return true; } //______________________________________________________________________________ void GAMELOOP::MovieExit(bool &isIntroMovie, bool &isEndMovie) { static bool isEscKey = false; if(KEYSTATE(VK_ESCAPE) && !isEscKey) { isEscKey = true; isIntroMovie = false; isEndMovie = false; } if(!KEYSTATE(VK_ESCAPE)) { isEscKey = false; } } //______________________________________________________________________________ void GAMELOOP::Exit() { //timeEndPeriod(1); } //______________________________________________________________________________ //______________________________________________________________________________ //______________________________________________________________________________ //______________________________________________________________________________ //______________________________________________________________________________ */ //______________________________________________________________________________ //______________________________________________________________________________ //______________________________________________________________________________ //______________________________________________________________________________ //______________________________________________________________________________