/*! -------------------------------------------------------------------- \file world.cpp \brief Encapsulate a world \author Roy Thompson \date 2002-11-09 // ------------------------------------------------------------------*/ #ifndef IGNORE_DEPEND #include #include #endif #include "world.h" #include "playership.h" #include "input.h" #include "missle.h" #include "game.h" #include "sound.h" #include "model.h" //! initialize singleton static variable World *World::s_pWorld = 0; //--------------------------------------------------------------------- // World // Method: Init // //! initialize world data structures // //--------------------------------------------------------------------- bool World::Init(const char* skyboxPath) { bool bError = false; // initalize skybox data if (!_skybox.Init(skyboxPath)) { cerr << "World: ERROR initializing skybox" << endl; bError = true; } #if 0 if (!theModels.Init()) { cerr << "Error loading models" << endl; bError = true; } #endif _lastShot = 0.0; _totalTime = 0.0; _spacejunk = new Spacejunk(1000); _livesLeft = 3; _score = 0; _state = COUNTDOWN; _countTime = 5.0; _levelChange = false; _justDied = false; return (!bError); } void World::NewLevel(int levelNum) { _curLevel = levelNum; _numEnemies = _levels[levelNum].numEnemies; //if (_enemies != NULL) // delete _enemies; _enemies = new EnemyShip[_numEnemies]; if (_enemiesAlive != NULL) delete _enemiesAlive; _enemiesAlive = new bool[_numEnemies]; for (int i=0; i < _numEnemies; i++) { _enemies[i].SetPosition(_levels[levelNum].enemies[i].startPos); _enemies[i].SetMaxVelocity(_levels[levelNum].enemies[i].speed); _enemies[i].SetMissleDamage(_levels[levelNum].enemies[i].damage); _enemiesAlive[i] = true; } } void World::RestartGame() { _justDied = false; _curLevel = 0; _livesLeft = 3; _state = COUNTDOWN; _countTime = 4.0; _score = 0; thePlayer.Restart(); NewLevel(0); _levelChange = false; } void World::RestartLevel() { //cout << "Restarting Level" << endl; thePlayer.Restart(); thePlayer.ResetOrientation(); theMissles.Restart(); for (int i=0; i < _numEnemies; i++) { _enemies[i].Restart(); _enemies[i].ClearExplosion(); _enemies[i].SetPosition(_levels[_curLevel].enemies[i].startPos); _enemiesAlive[i] = true; } } bool World::LevelComplete() { for (int i=0; i < _numEnemies; i++) if (_enemiesAlive[i]) return false; return true; } inline bool READ_STRING(istream &is, char* pString) { is >> pString; // ignore commented lines /* if (pString[0] == '-' && pString[1] == '-') while (pString[0] != '\n') { cout << pString[0] << endl; is >> pString; } */ return is.good(); } void drawString (char *s) { unsigned int i; for (i = 0; i < strlen (s); i++) { glutBitmapCharacter (GLUT_BITMAP_HELVETICA_18, s[i]); } }; void drawStringBig (char *s) { unsigned int i; for (i = 0; i < strlen (s); i++) { //glutBitmapCharacter (GLUT_BITMAP_HELVETICA_18, s[i]); glutBitmapCharacter (GLUT_BITMAP_TIMES_ROMAN_24, s[i]); } }; void World::OrthoMode(int left, int top, int right, int bottom) { glMatrixMode(GL_PROJECTION); glPushMatrix(); glLoadIdentity(); glOrtho(left,right,bottom,top,0,1); glMatrixMode(GL_MODELVIEW); glLoadIdentity(); glDisable(GL_DEPTH_TEST); } void World::PerspectiveMode() { glMatrixMode(GL_PROJECTION); glPopMatrix(); glMatrixMode(GL_MODELVIEW); glEnable(GL_DEPTH_TEST); } //--------------------------------------------------------------------- // World // Method: Render // //! render the world data to current rendering window // //--------------------------------------------------------------------- bool World::Render() { if (!_skybox.Render()) cerr << "World: ERROR rendering skybox" << endl; GLfloat ambient[] = {0.5, 0.5, 0.5}; glEnable(GL_LIGHTING); glEnable(GL_LIGHT0); glLightfv(GL_LIGHT0, GL_AMBIENT, ambient); glLightfv(GL_LIGHT0, GL_DIFFUSE, ambient); glLightfv(GL_LIGHT0, GL_SPECULAR, ambient); glLightModelfv(GL_LIGHT_MODEL_AMBIENT, ambient); _spacejunk->Render(); theMissles.Render(); for (int i=0; i<_numEnemies; i++) _enemies[i].Render(); thePlayer.Render(); // render all text, cockpit, etc here (ortho mode) OrthoMode(0,0, theGame.GetWidth(), theGame.GetHeight()); glDisable(GL_LIGHTING); glDisable(GL_TEXTURE_2D); glColor3f(0.0,1.0,0.0); char str[50]; glRasterPos2f (50.0, 50.0); sprintf(str, "Score: %d", _score); drawString(str); glRasterPos2f (50.0, 75.0); sprintf(str, "Lives Left: %d", _livesLeft); drawString(str); glRasterPos2f(theGame.GetWidth()-130.0,50.0); float vel = (thePlayer.velocity > 0.0) ? thePlayer.velocity : 0.0; sprintf(str, "Speed: %.2f", vel*100.0); drawString(str); glColor3f(0.0,1.0,0.0); glRasterPos2f(50.0,100.0); int numAlive = 0; for (int i=0; i<_numEnemies; i++) { if (_enemies[i].IsAlive()) numAlive++; } sprintf(str, "Enemies Alive: %d", numAlive); drawString(str); if (thePlayer.health < 0.3) glColor3f(1.0,0.0,0.0); glRasterPos2f(50.0,125.0); sprintf(str, "Health: %.0f%%", thePlayer.health*100.0); drawString(str); float midx = theGame.GetWidth()/2.0 - 10.0; float midy = theGame.GetHeight() / 2.0; glColor3f(0.0,1.0,0.0); if (!thePlayer.IsAlive()) { glRasterPos2f(midx-30, midy-50); drawStringBig("You Lose!"); glRasterPos2f(midx-80, midy-10); drawStringBig("Click Mouse to restart"); } else if (_state == WINNER && _countTime > 0.0) { glRasterPos2f(midx-30, midy-90); drawStringBig("You Win!"); glRasterPos2f(midx-50, midy-50); sprintf(str, "Final Score: %d", _score); drawStringBig(str); glRasterPos2f(midx-80, midy-10); drawStringBig("Click Mouse to restart"); } glColor3f(0.0,1.0,0.0); if (_state == COUNTDOWN) { glRasterPos2f(midx-70,midy-70); if (_levelChange) { sprintf(str, "Level %d starts in:", _curLevel+1); drawStringBig(str); } else { if (_justDied) { glColor3f(1.0,0.0,0.0); glRasterPos2f(midx-50,midy-130); drawStringBig("You Died!!!"); glColor3f(0.0,1.0,0.0); glRasterPos2f(midx-50,midy-100); sprintf(str, "Lifes Left: %d", _livesLeft); drawStringBig(str); } glColor3f(0.0,1.0,0.0); glRasterPos2f(midx-70,midy-70); drawStringBig("Game Starts in:"); } glColor3f(0.0, 0.0, 1.0); glRasterPos2f(midx,midy-30); sprintf(str, "%d", (int) _countTime); drawStringBig(str); } glEnable(GL_LIGHTING); glEnable(GL_TEXTURE_2D); PerspectiveMode(); return true; } //--------------------------------------------------------------------- // World // Method: UpdateState // //! update world state for single game loop iteration // //--------------------------------------------------------------------- void World::UpdateState(float timeElapsed) { int midx = glutGet(GLUT_WINDOW_WIDTH) / 2; int midy = glutGet(GLUT_WINDOW_HEIGHT) / 2; float movex = theInput.GetMouseX() - midx; float movey = theInput.GetMouseY() - midy; glutWarpPointer(midx, midy); _totalTime += timeElapsed; _countTime -= timeElapsed; if ((_state == GAMEOVER || _state == WINNER) && _countTime <= 0.0) { if (theInput.IsButtonPressed(0)) RestartGame(); } else if (_state == COUNTDOWN) { if (_countTime <= 0.0) _state = PLAYING; } else if (_state == PLAYING || _state == CHANGELEVEL) { if (LevelComplete() && _state != CHANGELEVEL) { _curLevel++; _score += _curLevel * 500; if (_curLevel < _numLevels) { _levelChange = true; _state = CHANGELEVEL; _countTime = 3.0; } else { _score += _livesLeft * 2000; _state = WINNER; _countTime = 5.0; } } else if (thePlayer.IsAlive()) { if (_state == CHANGELEVEL) { _countTime -= timeElapsed; if (_countTime < 0.0) { _state = COUNTDOWN; NewLevel(_curLevel); _countTime = 4.0; thePlayer.ResetOrientation(); _justDied = false; } } if (_totalTime > 1.0) { // make sure everything is loaded right first if (theInput.IsButtonPressed(2)) thePlayer.rollinc -= movex * timeElapsed; else thePlayer.yawinc -= movex * timeElapsed; thePlayer.pitchinc += movey * timeElapsed; if (theInput.IsKeyPressed(32)) { thePlayer.velinc += timeElapsed / 40.0; } if (theInput.IsButtonPressed(0) && _lastShot > 0.3) { theMissles.AddMissle(thePlayer.GetPosition()+(thePlayer.GetDirection() * 11.0), thePlayer.GetDirection(), 300.0, 2.0, 0.5); _lastShot = 0.0; } } // update player location thePlayer.UpdateState(timeElapsed, theInput.IsButtonPressed(2)); for (int i=0; i<_numEnemies; i++) _enemies[i].UpdateState(timeElapsed); theMissles.UpdateState(timeElapsed); for (int i=0; i<_numEnemies; i++) { // check for a collision with each of the enemies for (int j=i+1; j<_numEnemies; j++) { if (_enemies[i].IsCollision(_enemies[j].GetBoundingVol())) { Math3d::M3d dist = _enemies[i].GetPosition() - _enemies[j].GetPosition(); dist.normalize(); float dp = dist * _enemies[j].GetDirection(); //cout << "DOT PROD: " << dp << endl; if (dp > 0.5) _enemies[j].velocity = 0.0; dist = _enemies[j].GetPosition() - _enemies[i].GetPosition(); dist.normalize(); dp = dist * _enemies[i].GetDirection(); if (dp > 0.5) _enemies[i].velocity = 0.0; } } if (_enemies[i].IsAlive()) { if (thePlayer.IsCollision(_enemies[i].GetBoundingVol())) { Math3d::M3d dist = _enemies[i].GetPosition() - thePlayer.GetPosition(); dist.normalize(); float dp = dist * thePlayer.GetDirection(); //cout << "DOT PROD: " << dp << endl; if (dp > 0.5) thePlayer.velocity = 0.0; dist = thePlayer.GetPosition() - _enemies[i].GetPosition(); dist.normalize(); dp = dist * _enemies[i].GetDirection(); if (dp > 0.5) _enemies[i].velocity = 0.0; //cout << "Collision Detected" << endl; } float missleHit = theMissles.IsCollision(_enemies[i].GetBoundingVol()); if (missleHit > 0.0) { //cout << "Missle HIT!!!" << endl; _enemies[i].Hit(missleHit); } missleHit = theMissles.IsCollision(thePlayer.GetBoundingVol()); if (missleHit > 0.0) thePlayer.Hit(missleHit); } else { // see if the enemy was alive on the last pass if (_enemiesAlive[i]) { _enemiesAlive[i] = false; _score += _levels[_curLevel].enemies[i].killPoints; } } } } else { if (_livesLeft > 0) { RestartLevel(); _livesLeft--; _justDied = true; _state = COUNTDOWN; _countTime = 3.0; _levelChange = false; } else { _countTime = 3.0; _state = GAMEOVER; } } } // put a limit on the firing rate _lastShot += timeElapsed; } bool World::_ReadLevel(istream &is) { cerr << "Number of Levels: "; char tempBuf[256]; if (!READ_STRING(is, tempBuf)) { cerr << "ERROR" << endl; return false; } sscanf(tempBuf, "%d", &_numLevels); cerr << _numLevels << endl; _levels = new Level[_numLevels]; // actually read in the level descriptions for (int i=0; i<_numLevels; i++) { cerr << "------ Level " << (i+1) << " Description -----" << endl; cerr << "Number of Enemies: "; if (!READ_STRING(is, tempBuf)) { cerr << "ERROR" << endl; return false; } sscanf(tempBuf, "%d", &_levels[i].numEnemies); cerr << _levels[i].numEnemies << endl; _levels[i].enemies = new Enemy[_levels[i].numEnemies]; for (int j = 0; j < _levels[i].numEnemies; j++) { cerr << "-- Enemy " << (j+1) << " --" << endl; cerr << "Start Position: "; if (!READ_STRING(is, tempBuf)) { cerr << "ERROR" << endl; return false; } int tempx, tempy, tempz; sscanf(tempBuf, "%d", &tempx); if (!READ_STRING(is, tempBuf)) { cerr << "ERROR" << endl; return false; } sscanf(tempBuf, "%d", &tempy); if (!READ_STRING(is, tempBuf)) { cerr << "ERROR" << endl; return false; } sscanf(tempBuf, "%d", &tempz); _levels[i].enemies[j].startPos = Math3d::M3d(tempx, tempy, tempz); cerr << _levels[i].enemies[j].startPos << endl; cerr << "Max Speed: "; if (!READ_STRING(is, tempBuf)) { cerr << "ERROR" << endl; return false; } sscanf(tempBuf, "%f", &_levels[i].enemies[j].speed); cerr << _levels[i].enemies[j].speed << endl; cerr << "Damage: "; if (!READ_STRING(is, tempBuf)) { cerr << "ERROR" << endl; return false; } sscanf(tempBuf, "%f", &_levels[i].enemies[j].damage); cerr << _levels[i].enemies[j].damage << endl; cerr << "Kill Points: "; if (!READ_STRING(is, tempBuf)) { cerr << "ERROR" << endl; return false; } sscanf(tempBuf, "%d", &_levels[i].enemies[j].killPoints); cerr << _levels[i].enemies[j].killPoints << endl; } cerr << endl; } return true; }