SE Team 9 GlobalFlyer Cole Hoosier Ryan Hannebaum Leanne Gray Alex Stampbach
Project Statement GlobalFlyer allows a player to fly a Wright brothers-style airplane in 3D space using the OGRE graphic rendering engine and the FMOD sound system.
Iteration Plans Fixup 1: Get music and sound effects working again 2: Get collision detection with buildings working 3: Update Ogre library versions Visual Environment 1: Add hovering objects to the world 2: Add proximity detection to hovering objects 3: Modify texture of hovering objects based on proximity User Interface 1: Add mouse control of camera 2: Add visually-appealing digital readouts of data the user might want 3: Add the ability to toggle sound, gui, etc.
GlobalFlyer Web Site
The Plan and Analysis
Plan for Iteration 3
Comparisons of Effort
BCWACWEst CompActual Comp Iter 1: Fixup /26/20072/3/2007 Iter 1: Visual /26/20072/10/2007 Iter 1: UI /26/20072/23/2007 Pres /27/20072/23/2007 Iter 2: Fixup & VE - initial research /6/20073/5/ create slides120603/13/20073/12/ collision detection with buildings /20/20073/10/ proximity detection with bubbles120603/27/20073/10/ create OCL120 3/29/20073/26/ test code60 3/30/20073/26/ integrate code60 4/1/20073/26/2007 Iter 2: UI - initial research /6/20073/5/ create slides120603/13/20073/12/ prettify text /20/20073/26/ test readout120903/27/20073/26/ integrate code120303/30/20073/26/2007 Pres 5 - assemble presentation240 4/1/2007 Open House - prepare display /10/20074/9/ rehearse/test presentation12004/13/20074/9/2007 Iter 3: Update Ogre libraries - update libraries and fix code /22/20074/23/ test code and create slides120 4/27/2007 Iter 3: Visual80004/27/20073/10/2007 Iter 3: UI - study methods of toggling settings /22/20074/25/ implement toggling & test120 4/27/20074/25/2007 Pres 6 - assemble presentation240 4/29/2007 Final Docs CD /4/20074/29/2007 Total
Earned Value EV= Budgeted cost of Work Performed over Budgeted at Completion Shows our the gradual completion of tasks over time
Schedule Performance Index SPI= Budgeted Cost of Work Performed over Budgeted Cost of Work Schedule Shows that we are always on or ahead of schedule
Schedule Variance SV= Budgeted Cost of Work Performed minus Budgeted Cost of Work Schedule Show how far ahead of schedule (or right on target) we were
Cost Performance Index CPI= Budgeted Cost of Work Performed over Actual Cost of Work Performed Show us under budget and over budget but finally ending under (just barely)
Cost Variance CV= Budgeted Cost of Work Performed minus Actual Cost of Work Performed Show just how much over and under budget we were
OCL
Areas that lend themselves well to OCL specifications The airplane cannot fly beneath the ground The FMOD sound system shouldn't be re-initialized The bubbles and buildings must be within the boundaries of the world Checking the win-condition for a level, theoretically we would load a new level after hitting all targets
OCL The airplane cannot fly beneath the ground context OgreCharacter::update(elapsedTime, *input) : void post: self.raySceneQuery->forAll( worldFragment.singleIntersection.y < self.mMainNode.getPosition().y )
OCL The FMOD sound system shouldn't be re-initialized context CFMod::InitSoundSystem() : bool pre: self.initialized = false post: self.initialized = true
OCL The bubbles and buildings must be within the boundaries of the world context SampleApplication::createScene() : void post: self.buildings.getBoundingBox->forAll( getMinimum.x >= 0 and getMinimum.z >= 0 and getMaximum.x <= and getMaximum.z <= ) post: self.bubbles.getBoundingBox->forAll( getMinimum.x >= 0 and getMinimum.z >= 0 and getMaximum.x <= and getMaximum.z <= )
OCL Checking the win-condition for a level -- theoretically we would load a new level after hitting all targets context OgreCharacter::targetsRemaining() : int result = self.targetHit->count(false) context OgreCharacter::checkWin() : bool result = self.targetsRemaining = 0 context SampleListener::frameStarted(frameEvent) : void post: self.mChar.checkWin = false
Testing Code void Sound::Play() { debug ("Sound::Play 1"); if (m_pSound != NULL) { debug ("Sound::Play 2a"); m_soundChannel = FSOUND_PlaySound(FSOUND_FREE, m_pSound); } else { debug ("Sound::Play 2b."); } debug ("Sound::Play 3 (last)"); }
Testing Output Airplane::Airplane (only) Airplane::GetPosit (only) Airplane::GetRelVeloc (only) Airplane::GetVeloc (only) Airplane::checkWin (only) Airplane::inObstacle 1 Airplane::inObstacle 2 Airplane::inObstacle 3a Airplane::inObstacle 3b. Airplane::inObstacle 4a Airplane::inObstacle 4b. Airplane::inObstacle 5a Airplane::inObstacle 5b. Airplane::inObstacle 6 (last)
Exceptions to C1 Sound::InitSoundSytem 3a -- would need an invalid version of fmod Sound::InitSoundSytem 4a -- would need a bad version of fmod Sound::Load 3a -- fmod would have to screw up to hit this case Sound::Mute 2b. -- fmod would have to screw up to hit this case Sound::Pause 2b. -- fmod would have to screw up to hit this case Sound::SetLoop 2b. -- fmod would have to screw up to hit this case bool Sound::Load(char *strName) { debug ("Sound::Load 1"); bool retval = false; // set to 'true' if successfully loaded // if FMOD isn't loaded, or strName is invalid, we can't load a sample if (initialized && strName) { debug ("Sound::Load 2a"); m_pSound = FSOUND_Sample_Load(FSOUND_FREE, strName, 0, 0, 0); // make sure we got a valid sound pointer if (!m_pSound ) { debug ("Sound::Load 3a"); // bad news, bail out with an error message DisplayError(); ……..
UML Models
FrameStarted Sequence Diag
Old Class Diagram Overview
New Class Diagram Airplane Sound PhysicsEngine ExtendedFrame Listener Extended Camera GlobalFlyer Level Manager
GlobalFlyer
ExtendedFrameListener
ExtendedCamera
LevelManager
Airplane
PhysicsEngine
Sound
New Features and Updates
Library Update Ogre has updated from to during the year. We thought it might be nice to start next year’s team with updated code.
Where’s the Keyboard? using namespace OIS; void Airplane::Update (Real elapsedTime, Keyboard *keyboard, Mouse *mouse) { … if ( keyboard->isKeyDown(KC_W) …)…. …} airplane.{h,c}
LevelManager Sets up the world –Bubbles –Buildings Format follows: int buildingPositions[MAX_LEVEL][MAX_BUILDINGS][6] = { … {//level 2 {5000, 0, 6000, 50, 950, 3000}, // x, y, z, width, height, length {10000, 0, 6000, 50, 950, 3000}, // 1 {6000, 0, 5000, 3000, 950, 50}, // 2 {6000, 0, 10000, 3000, 950, 50}, {6000, 1000, 6000, 3000, 50, 3000}, {0, 0, 0, 0, 0, 0}, // 5
LevelManager
Camera Controls if (mKeyboard->isKeyDown (KC_F1) && mExCamera) { mExCamera->SetTightness (1.0f); } else if (mKeyboard->isKeyDown (KC_F2) && mExCamera) { mExCamera->SetTightness (0.1f); } else if (mKeyboard->isKeyDown (KC_F3) && mExCamera) { mExCamera->SetTightness (0.05f); } else if (mKeyboard->isKeyDown (KC_F4) && mExCamera) …….. extended_frame_listener.cpp
Camera Controls
Sight & Sound bind keys to toggle cockpit and sound create guard variable to ensure only a single toggle per click
Toggle Cockpit F9
Void ExtendedFrameListener::setTextArea(…Ogre::Overlay* olay){ overlay = olay; … } //toggle GUI if (mInputDevice->isKeyDown (KC_F9) && keyCountGUI >= 0.5) { if (overlay->isVisible()) { overlay->hide(); } else { overlay->show(); } keyCountGUI = 0; }
Toggle Sound (demonstration) F10
Toggle Sound if (mKeyboard->isKeyDown (KC_F10) && mChar && keyCountSound >= 0.5) { bool enabled; enabled = mChar->ToggleSound(); keyCountSound = 0; if (enabled) { status->setCaption("Sound Enabled"); } else { status->setCaption("Sound Disabled"); } } else if (keyCountSound >= 4.0) { status->setCaption(""); } void Airplane::toggleSound() { soundEnabled = !soundEnabled; musicSound.Mute(); if (soundEnabled) { if (crashed) { crashSound.Mute(); } else { engineSound.Play(); } } else { if (crashSoundStarted) { crashSound.Mute(); } else { engineSound.Stop(); }
Protection from Rapid-Fire key press was registering every frame (up to 250 times per second) Introduced timer to guard against this rapid-fire toggling once toggle is registered, cannot be registered again for 0.5 second
The Result:
Who has Questions? -Images from texasbestgrok.mu.nu/images/GF2.jpg