#include "View.h" #include "CameraBase.h" #include "SimpleConsoleOverlay.h" #include "IMGUIControls.h" #include "keytable.h" #include "DrawingsGL.h" #include "Engine.h" #include "Physics.h" #include "Model.h" #include "Controller.h" #include "EventBase.h" #include "Game.h" #include "ShipEntity.h" #include "AsteroidEntity.h" #include "AsteroidsEvents.h" #include "RocketEntity.h" #include #include // #define DRAW_BOUNDARIES #ifdef DRAW_BOUNDARIES #include "coll2d.h" #include "DrawingsGL.h" #endif using namespace std; namespace asteroids { int View::OnInit (int argc, char* argv[]) { ViewBase::OnInit (argc, argv); /* // We want the console mConsoleOverlay = boost::shared_ptr (new Engine::SimpleConsoleOverlay); // We also want to display the log bar mConsoleOverlay->SetDrawLogBar (true); mOverlayManager.Register (mConsoleOverlay, GameStateMainMenu); */ LoadFont("AldotheApache.ttf size=20 color=#000000"); button_width = 250; button_height = 40; // This is a simple star field that makes the game so spacy int i; for (i = 0; i < 200; i++) { BackgroundStar star; star.position[0] = rand() / float(RAND_MAX) * 1.2; star.position[1] = rand() / float(RAND_MAX) * 1.2; star.position[2] = rand() / float(RAND_MAX) * 1.2; mBackgroundStars.push_back (star); } // Editor default variables mEditorEntityId = 0; mEditorState = EditorStateUnknown; mGUIShipSprite.LoadFromPNG(Engine::GetResourceFullPath("/data/textures/ship.png")); mGUIShipSprite.SetScale (0.1); mAsteroidSprite.LoadFromPNG (Engine::GetResourceFullPath("/data/textures/asteroid.png")); mShipSprite.LoadFromPNG (Engine::GetResourceFullPath("/data/textures/ship.png")); mShipThrustSprite.LoadFromPNG (Engine::GetResourceFullPath("/data/textures/ship_thrust.png")); mShipThrustSprite.SetAnimation (4, 8); mShipPartsSprite.LoadFromPNG (Engine::GetResourceFullPath("/data/textures/ship_parts.png")); mShipPartsSprite.SetSubSpriteCount (10); Engine::RegisterListener (this, EventAccelerateStart); Engine::RegisterListener (this, EventAccelerateStop); Engine::RegisterListener (this, EventShipExplode); Engine::RegisterListener (this, EventPlayerDied); Engine::RegisterListener (this, EventGameOver); Engine::RegisterListener (this, EventLevelComplete); PushViewState (ViewStateMainMenu); return 0; } void View::OnDestroy() { mBackgroundStars.clear(); mShipPartsEntityIds.clear(); Engine::ViewBase::OnDestroy(); } bool View::OnReceiveEvent (const Engine::EventBasePtr &event) { switch (event->mEventType) { case EventAccelerateStart: case EventAccelerateStop: if (event->mEventType == EventAccelerateStart) mShipThrustSprite.ResetAnimation(); Engine::LogDebug ("Received Acceleration Event: %d", event->mEventType); return true; break; case EventLevelComplete: PushViewState(ViewStateLevelComplete); GetController()->ResetPlayerEntity(); break; case EventGameOver: mFadeTimerSecValue = 2.; PopViewState(); PushViewState(ViewStateGameOver); GetController()->ResetPlayerEntity(); break; case EventPlayerDied: mFadeTimerSecValue = 2.; PushViewState(ViewStatePlayerDied); GetController()->ResetPlayerEntity(); break; case EventShipExplode: { // This event is fired when the ship explodes. Note: this event is not // sufficient for EventPlayerDied! Engine::LogDebug ("Received PlayerDied Event: %d", event->mEventType); // insert sprits that contains parts of the ship Engine::EntityBase *ship_entity = Engine::GetEntity (event->mEventUnsignedInt); vector3d position = ship_entity->mPhysicState->mPosition; vector3d orientation = ship_entity->mPhysicState->mOrientation; vector3d velocity = ship_entity->mPhysicState->mVelocity; vector3d rel_velocity = event->mVector3d; unsigned int i; mShipPartsEntityIds.clear(); for (i = 0; i < mShipPartsSprite.GetSubSpriteCount(); i++) { Engine::EntityBase* part_sprite_particle = Engine::CreateEntity (GameEntityTypeShipPart); part_sprite_particle->mPhysicState->mPosition = position; part_sprite_particle->mPhysicState->mOrientation = orientation; vector3d part_velocity ( rel_velocity[0] * (rand()/float(RAND_MAX)) * 1.7, 0., rel_velocity[2] * (rand()/float(RAND_MAX)) * 1.5 ); part_sprite_particle->mPhysicState->mVelocity = part_velocity; part_sprite_particle->mPhysicState->mAngleVelocity = (rand()/float(RAND_MAX) - 0.5 ) * 100.; mShipPartsEntityIds.push_back(part_sprite_particle->mId); } // We do not need the entity anymore Engine::KillEntity(event->mEventUnsignedInt); return true; break; } default: Engine::LogWarning ("Received Event with type %d but don't know what to do with it!", event->mEventType); break; } return false; } /* * Module specific functions */ void View::UpdateCamera () { mCamera->SetEye ( 0., 9.5, 0. ); mCamera->SetPointOfIntrest ( 0., 0., 0. ); mCamera->SetUp ( 0., 0., -1. ); mCamera->Update (); } void View::DrawStars() { unsigned int i; float world_width, world_height; world_width = static_cast(mModel)->GetWorldWidth(); world_height = static_cast(mModel)->GetWorldHeight(); vector3d velocity (1., 0., 0.); glPushMatrix(); glTranslatef(-world_width * 0.5, 0, -world_height * 0.5); glColor3f (1., 1., 1.); glPointSize(2.); glBegin(GL_POINTS); float z_value; for (i = 0; i < mBackgroundStars.size(); i++) { // glPointSize (2. + 300. *mBackgroundStars.at(i).position[1]); z_value = mBackgroundStars.at(i).position[1] + 0.1; glColor3f (z_value, z_value, z_value); glVertex3f (mBackgroundStars.at(i).position[0] * world_width, -1., mBackgroundStars.at(i).position[2] * world_height); mBackgroundStars.at(i).position -= vector3d(Engine::GetFrameDuration() * 0.7 * mBackgroundStars.at(i).position[1] / world_width, 0., 0.); // we move the stars a little more such that they are not blende out too early // \todo compute proper bounds from Physics world size! if (mBackgroundStars.at(i).position[0] < -0.1) mBackgroundStars.at(i).position[0] += 1.2; if (mBackgroundStars.at(i).position[0] >= 1.1) mBackgroundStars.at(i).position[0] -= 1.2; } glEnd(); glPopMatrix(); } void View::Draw() { PreDraw(); mFadeTimerSecValue -= GetModel()->GetFrameDuration(); // Actual Drawing UpdateCamera (); if (mDrawGrid) DrawGrid (); /* if (mDrawAxis) DrawAxis (); */ std::map::iterator entity_iterator; Model *game_model = static_cast (mModel); unsigned int game_state = game_model->GetGameState(); DrawStars (); if ( game_state == GameStateRunning || GetViewState() == ViewStateEditor) { DrawWorld (); } DrawUi (); // Perform post-Draw actions PostDraw(); } void View::DrawWorld() { std::map::iterator entity_iterator; Model *game_model = static_cast (mModel); ViewBase::DrawWorld(); for (entity_iterator = game_model->mEntities.begin (); entity_iterator != game_model->mEntities.end(); entity_iterator++) { Engine::EntityBase* entity = entity_iterator->second; // Perform multiple drawing if the entity is at the border Physics* game_physics = (Physics*) game_model->mPhysics; float world_width = game_physics->GetWorldWidth(); float world_height = game_physics->GetWorldHeight(); // if we are in Edit mode and are currently editing the velocity we must // make sure that we display it if (GetViewState() == ViewStateEditor) { if (mEditorState == EditorStateEntityVelocity) { DrawVector (entity->mPhysicState->GetPosition(), entity->mPhysicState->GetPosition() + entity->mPhysicState->GetVelocity()); } } // Drawing at the original position: glPushMatrix (); glTranslatef (entity->mPhysicState->mPosition[0], entity->mPhysicState->mPosition[1], entity->mPhysicState->mPosition[2]); glRotatef(entity->mPhysicState->mOrientation[0], 0., 0., 1.); glRotatef(entity->mPhysicState->mOrientation[1], 0., 1., 0.); glRotatef(entity->mPhysicState->mOrientation[2], 1., 0., 0.); glColor3f (1., 1., 1.); DrawEntity (entity); glPopMatrix (); // If we move out the right side if (entity->mPhysicState->mPosition[0] + entity->mPhysicState->mRadius * 2 >= world_width * 0.5) { glPushMatrix (); glTranslatef (entity->mPhysicState->mPosition[0] - world_width, entity->mPhysicState->mPosition[1], entity->mPhysicState->mPosition[2]); glRotatef(entity->mPhysicState->mOrientation[0], 0., 0., 1.); glRotatef(entity->mPhysicState->mOrientation[1], 0., 1., 0.); glRotatef(entity->mPhysicState->mOrientation[2], 1., 0., 0.); glColor3f (1., 1., 1.); DrawEntity (entity); glPopMatrix (); } // if we move out the left side if (entity->mPhysicState->mPosition[0] - entity->mPhysicState->mRadius * 2 < - world_width * 0.5) { glPushMatrix (); glTranslatef (entity->mPhysicState->mPosition[0] + world_width, entity->mPhysicState->mPosition[1], entity->mPhysicState->mPosition[2]); glRotatef(entity->mPhysicState->mOrientation[0], 0., 0., 1.); glRotatef(entity->mPhysicState->mOrientation[1], 0., 1., 0.); glRotatef(entity->mPhysicState->mOrientation[2], 1., 0., 0.); glColor3f (1., 1., 1.); DrawEntity (entity); glPopMatrix (); } // If we move out the bottom side if (entity->mPhysicState->mPosition[2] + entity->mPhysicState->mRadius * 2 >= world_height * 0.5) { glPushMatrix (); glTranslatef (entity->mPhysicState->mPosition[0], entity->mPhysicState->mPosition[1], entity->mPhysicState->mPosition[2] - world_height); glRotatef(entity->mPhysicState->mOrientation[0], 0., 0., 1.); glRotatef(entity->mPhysicState->mOrientation[1], 0., 1., 0.); glRotatef(entity->mPhysicState->mOrientation[2], 1., 0., 0.); glColor3f (1., 1., 1.); DrawEntity (entity); glPopMatrix (); } // if we move out the left side if (entity->mPhysicState->mPosition[2] - entity->mPhysicState->mRadius * 2 < - world_height* 0.5) { glPushMatrix (); glTranslatef (entity->mPhysicState->mPosition[0], entity->mPhysicState->mPosition[1], entity->mPhysicState->mPosition[2] + world_height); glRotatef(entity->mPhysicState->mOrientation[0], 0., 0., 1.); glRotatef(entity->mPhysicState->mOrientation[1], 0., 1., 0.); glRotatef(entity->mPhysicState->mOrientation[2], 1., 0., 0.); glColor3f (1., 1., 1.); DrawEntity (entity); glPopMatrix (); } } } /* * Userinterface */ void View::DrawUi () { glClearColor (0.1, 0.1, 0.1, 1.); screen_right = static_cast (Engine::GetWindowWidth()); screen_bottom = static_cast (Engine::GetWindowHeight()); // we switch to orthographic projection and draw the contents of the 2d // overlay on top of the previous drawings glMatrixMode (GL_PROJECTION); glPushMatrix (); glLoadIdentity (); // first we have to get the size of the current viewport to set up the // orthographic projection correctly GLint viewport[4]; glGetIntegerv(GL_VIEWPORT, viewport); gluOrtho2D (viewport[0], viewport[2], viewport[3], viewport[1]); glMatrixMode (GL_MODELVIEW); glPushMatrix (); glLoadIdentity (); unsigned int game_state = GetModel()->GetGameState(); SelectFont("console.ttf"); SetFontJustification (Engine::FontJustificationLeft); GetController()->EnableTextinput(true); ViewState current_view_state = GetViewState(); SelectFont ("console.ttf size=12"); Engine::GUI::Label (99999, GetStringViewState(current_view_state), 8, 16); switch (current_view_state) { case ViewStateMainMenu: DrawUiMainMenu(); break; case ViewStateGameRunning: DrawUiGameRunning(); break; case ViewStatePaused: DrawUiGamePaused(); break; case ViewStatePlayerDied: DrawUiPlayerDied(); break; case ViewStateLevelComplete: DrawUiLevelComplete(); break; case ViewStateShowHighscore: DrawUiHighscore(); break; case ViewStateOptions: DrawUiOptions(); break; case ViewStateEnterPlayername: DrawUiEnterPlayername(); break; case ViewStateGameOver: DrawUiGameOver(); break; case ViewStateEditor: DrawUiEditor(); break; default: Engine::LogWarning ("Trying to draw unknown ViewState: %s (%d)", GetStringViewState (game_state), game_state); break; } glPopMatrix (); glMatrixMode (GL_PROJECTION); glPopMatrix (); glMatrixMode (GL_MODELVIEW); } void View::DrawPageTitle (const std::string& title) { SelectFont("console.ttf size=46 color=#808080"); float width, height; DrawGLStringMeasure(title.c_str(), &width, &height); float xpos = (screen_right - width) * 0.5 - 40; float ypos = 180; Engine::GUI::Label (4, title.c_str(), xpos - 2, ypos + 2); SelectFont("console.ttf size=46 color=#ffffff"); Engine::GUI::Label (4, title.c_str(), xpos, ypos); } void View::DrawUiMainMenu() { DrawPageTitle ("Asteroids"); SelectFont("console.ttf size=23"); if (Engine::GUI::Button (1, "New Game", screen_right * 0.5 - 100, 200, button_width, button_height)) { PushViewState(ViewStateEnterPlayername); } if (Engine::GUI::Button (2, "Options", screen_right * 0.5 - 100, 250, button_width, button_height)) { PushViewState (ViewStateOptions); } if (Engine::GUI::Button (3, "Highscores", screen_right * 0.5 - 100, 300, button_width, button_height)) { PushViewState(ViewStateShowHighscore); } if (Engine::GUI::Button (6, "E", screen_right - 48, 20, 32, button_height)) { PushViewState(ViewStateEditor); } if (Engine::GUI::Button (4, "Quit", screen_right * 0.5 - 100, 380, button_width, button_height)) { Engine::RunCommand("quit"); } } void View::DrawUiGameRunning() { // We choose a different font and also draw it aligned to the right as this // looks nicer with the points SelectFont ("AldotheApache.ttf size=20 color=#ffffff"); SetFontJustification (Engine::FontJustificationRight); std::ostringstream out_stream; out_stream << GetModel()->GetPlayerLives() << " x "; DrawGLString (screen_right - 64, screen_bottom - 20, out_stream.str().c_str()); mGUIShipSprite.DrawAt2D (screen_right - 32 - 10, screen_bottom - 16); out_stream.str(""); out_stream << GetModel()->GetPoints(); DrawGLString (screen_right - 30, 40, out_stream.str().c_str()); // revert the font justification SetFontJustification (Engine::FontJustificationLeft); if (Engine::GUI::CheckKeyPress(SDLK_ESCAPE)) { PushViewState(ViewStatePaused); GetModel()->SetGameState(GameStatePaused); } } void View::DrawUiGameOver() { DrawPageTitle ("Game Over"); SelectFont("console.ttf size=23 color=#ffffff"); if (GetModel()->GetPlayerLives() == 0) { Engine::GUI::LabelCentered(5, "That was pathetic!", screen_right * 0.5, screen_bottom * 0.5 - 8); } else { Engine::GUI::LabelCentered (6, "You earned yourself the", screen_right * 0.5, screen_bottom * 0.5 - 32); Engine::GUI::LabelCentered (7, "You Rock(TM) award.", screen_right * 0.5, screen_bottom * 0.5 + 0); Engine::GUI::LabelCentered (8, "Go tell your friends.", screen_right * 0.5, screen_bottom * 0.5 + 32); } if (mFadeTimerSecValue > 0.) return; if (Engine::GUI::Button (2, "Continue...", (screen_right - button_width) * 0.5, screen_bottom * 0.5 + 80, button_width, button_height)) { // We do not want the background to show the remaining bits of the game GetModel()->SetGameState(GameStatePaused); PopViewState(); PushViewState(ViewStateShowHighscore); } } void View::DrawUiLevelComplete() { DrawPageTitle ("Level Complete!"); SelectFont ("console.ttf size=23"); if(Engine::GUI::Button (1, "Next level ...", (screen_right - button_width) * 0.5, screen_bottom * 0.5 + 60, button_width, button_height)) { PopViewState(); // we have to take care when we are testing the level to not proceed to // the next level... if (GetViewState() == ViewStateEditor) { GetModel()->SetGameState(GameStatePaused); if (mEditorState == EditorStateTest) { GetModel()->DoLoadLevel("level_edit_temp.txt"); mEditorState = EditorStateUnknown; } } else { GetModel()->ProceedToNextLevel(); } } } void View::DrawUiGamePaused() { DrawPageTitle ("Game Paused"); SelectFont ("console.ttf size=23"); if (Engine::GUI::Button (1, "Resume Game", screen_right * 0.5 - 100, 200, button_width, button_height)) { PopViewState(); GetModel()->SetGameState(GameStateRunning); } if (Engine::GUI::Button (2, "Options", screen_right * 0.5 - 100, 250, button_width, button_height)) { PushViewState (ViewStateOptions); } if (Engine::GUI::Button (3, "Abort Game", screen_right * 0.5 - 100, 300, button_width, button_height)) { ResetViewState(); PushViewState(ViewStateMainMenu); GetModel()->SetGameState(GameStatePaused); } if (Engine::GUI::Button (4, "Quit", screen_right * 0.5 - 100, 380, button_width, button_height)) { Engine::RunCommand("quit"); } } void View::DrawUiPlayerDied() { DrawPageTitle ("You died!"); SelectFont ("console.ttf size=23"); if (mFadeTimerSecValue > 0.) return; if (Engine::GUI::Button (1, "Continue", screen_right * 0.5 - 100, 380, button_width, button_height)) { PopViewState(); // we have to take care when we are testing the level to not proceed to // the next level... if (GetViewState() == ViewStateEditor) { GetModel()->SetGameState(GameStatePaused); if (mEditorState == EditorStateTest) { GetModel()->DoLoadLevel("level_edit_temp.txt"); mEditorState = EditorStateUnknown; } } else { GetModel()->ReloadLevel(); GetModel()->SetGameState(GameStateRunning); } } } /** \brief Draws an entry in the form .... * * The amount of dots is also computed within this function. Not necessarily * fast, however it works for now. */ void View::DrawHighscoreEntry (float x, float y, float entry_width, const std::string &name, unsigned int points) { const float width_buffer = 30.; float width, height; float name_width, points_value_width; // Measure and draw the name DrawGLStringMeasure (name.c_str(), &name_width, &height); name_width = fabsf(name_width); Engine::DrawGLString ( x, y, name.c_str()); // Compute the width of the points value when it is printed out std::ostringstream points_value_stream; points_value_stream << points; DrawGLStringMeasure (points_value_stream.str().c_str(), &points_value_width, &height); points_value_width = fabsf(points_value_width); // Compute the amount of dots. This is done by iteratively adding a dot '.' // to a stream and check whether it has the desired width. float dots_width = 0.; std::ostringstream dots_stream; while (ceil(name_width) + dots_width + points_value_width + width_buffer < entry_width) { dots_stream << "."; DrawGLStringMeasure (dots_stream.str().c_str(), &dots_width, &height); dots_width = fabsf(dots_width); } // Drawing of the dots and the points value Engine::DrawGLString ( x + entry_width - points_value_width - dots_width - 10, y, dots_stream.str().c_str()); Engine::DrawGLString ( x + entry_width - points_value_width, y, points_value_stream.str().c_str()); } void View::DrawUiHighscore() { DrawPageTitle ("Highscores"); SelectFont ("console.ttf size=23"); unsigned int entry_length = 32; float char_width, height; DrawGLStringMeasure ("M", &char_width, &height); height = fabsf(height); float entry_width = fabsf(char_width * entry_length); float x = screen_right * 0.5 - entry_width * 0.5; float y = screen_bottom * 0.5 - 8 - 128; // then we do the drawings y += 60; std::list::iterator highscore_iter = GetModel()->mHighscoreList.begin(); SetFontJustification(Engine::FontJustificationLeft); unsigned int i = 0; while (highscore_iter != GetModel()->mHighscoreList.end()) { // Check whether we have to highlight an entry (such as when entering // the name) if (GetModel()->mNewestHighscoreEntryIndex < GetModel()->mHighscoreList.size() && GetModel()->mNewestHighscoreEntryIndex == i) { // we highlight the newest entry SelectFont("console.ttf color=#e8d500 size=23"); } else { SelectFont("console.ttf color=#ffffff size=23"); } DrawHighscoreEntry ( x, y, entry_width, highscore_iter->name, highscore_iter->points); // go down one line y += height * 1.3; i++; highscore_iter++; } if (Engine::GUI::Button (1, "Back to Menu", screen_right * 0.5 - 250 * 0.5, y + 16, button_width, button_height)) { PopViewState(); } } void View::DrawUiOptions() { DrawPageTitle ("Options"); SelectFont ("console.ttf size=23"); Engine::GUI::Label (10, "Effects Volume: ", screen_right * 0.5 - 150, 240); float effects_volume = Engine::GetEffectsVolume(); if (Engine::GUI::VerticalSlider (1, screen_right * 0.5 - 100, 250, 250, 16, 0., 1., effects_volume)) { Engine::LogDebug ("Setting effects volume to: %f", effects_volume); Engine::SetEffectsVolume(effects_volume); } Engine::GUI::Label (11, "Music Volume: ", screen_right * 0.5 - 150, 300); float music_volume = Engine::GetMusicVolume(); if (Engine::GUI::VerticalSlider (2, screen_right * 0.5 - 100, 310, 250, 16, 0., 1., music_volume)) { Engine::LogDebug ("Setting music volume to: %f", music_volume); Engine::SetMusicVolume(music_volume); } if (Engine::GUI::Button (5, "Back", screen_right * 0.5 - 100, 380, button_width, button_height)) { PopViewState(); } } void View::DrawUiEnterPlayername() { DrawPageTitle ("Asteroids"); SelectFont ("console.ttf size=23"); // Enter your name std::string player_name = GetModel()->GetPlayerName(); SelectFont("console.ttf size=23"); Engine::GUI::Label (1, "Enter your name: ", screen_right * 0.5 - 220, 250); if (Engine::GUI::LineEdit (2, screen_right * 0.5 + 20, 238, player_name, 16)) { GetModel()->SetPlayerName(player_name); } if (Engine::GUI::Button (3, "Start Game", screen_right - 180 - 20, 500, 180, 40)) { PopViewState(); PushViewState(ViewStateGameRunning); GetModel()->OnNewGame(); GetModel()->SetGameState(GameStateRunning); } if (Engine::GUI::Button (5, "Back", 20, 500, 180, 40)) { PopViewState(); } } void View::DrawUiEditor() { // DrawPageTitle ("Editor"); SelectFont ("console.ttf size=23"); // Special case: if we get here and are currently in the editor state // EditorStateTest, then we returned from our test. In this case we have to // reset the editor state if (mEditorState == EditorStateTest) { // mEditorState = EditorStateUnknown; // Engine::LogMessage ("Returned from testing"); } // The close button if (Engine::GUI::Button (1, "X", screen_right - 48, 20, 32, button_height) || Engine::GUI::CheckKeyPress(SDLK_ESCAPE)) { if (mEditorState == EditorStateTest) { mEditorState = EditorStateUnknown; GetModel()->DoLoadLevel("level_edit_temp.txt"); GetModel()->SetGameState(GameStatePaused); } else { PopViewState(); } } if (mEditorState != EditorStateTest) { if (Engine::GUI::Button (2, "+", 30, 20, 32, button_height)) { mEditorState = EditorStateAddEntity; } if (Engine::GUI::Button (3, "M", 70, 20, 32, button_height)) { mEditorState = EditorStateMoveEntity; } if (Engine::GUI::Button (4, "V", 110, 20, 32, button_height)) { mEditorState = EditorStateEntityVelocity; } if (Engine::GUI::Button (5, "S", 150, 20, 32, button_height)) { mEditorState = EditorStateSave; } if (Engine::GUI::Button (6, "L", 190, 20, 32, button_height)) { mEditorState = EditorStateLoad; } if (Engine::GUI::Button (7, "T", 230, 20, 32, button_height)) { mEditorState = EditorStateTest; GetModel()->DoSaveLevel("level_edit_temp.txt"); GetModel()->SetGameState(GameStateRunning); } } std::ostringstream mouse_pos_str; vector3d mouse_world_pos; Controller* controller = GetController(); controller->GetMouseWorldPosition(mouse_world_pos); mouse_pos_str << mouse_world_pos[0] << "," << mouse_world_pos[2]; if (mEditorState == EditorStateAddEntity) { SelectFont ("console.ttf size=12"); Engine::GUI::Label (9999, "Adding", 128, 16); if (Engine::GUI::CheckKeyPress(MouseButtonLeft)) { // if there is no entity so far we create a player, otherwise we create // an asteroid Engine::EntityBase* entity = NULL; GameEntityType entity_type = GameEntityTypeShip; if (GetModel()->GetPlayerEntityId() != 0) { entity = Engine::CreateEntity(GameEntityTypeAsteroid); entity->mPhysicState->SetVelocity (vector3d (0., 0., -1.)); } else { entity = Engine::CreateEntity(GameEntityTypeShip); GetModel()->SetPlayerEntityId(entity->mId); entity->mPhysicState->SetOrientation (vector3d (0., 90., 0.)); } // Now we want to insert an Asteroid at the given position entity->mPhysicState->SetPosition (vector3d (mouse_world_pos[0], 0., mouse_world_pos[2])); mEditorState = EditorStateUnknown; } } if (mEditorState == EditorStateMoveEntity) { SelectFont ("console.ttf size=12"); Engine::GUI::Label (9999, "Moving", 128, 16); if (controller->GetButtonState(MouseButtonLeft)) { // Check if there is an entity near the given position Engine::EntityBase* asteroid = Engine::GetEntityAt (mouse_world_pos); if (asteroid) { mEditorEntityId = asteroid->mId; } } if (mEditorEntityId != 0) { Engine::EntityBase* asteroid = Engine::GetEntity (mEditorEntityId); asteroid->mPhysicState->SetPosition (mouse_world_pos); } if (!controller->GetButtonState(MouseButtonLeft)) { if (mEditorEntityId != 0) { mEditorEntityId = 0; } } } if (mEditorState == EditorStateEntityVelocity) { SelectFont ("console.ttf size=12"); Engine::GUI::Label (9999, "Velocity", 128, 16); if (mEditorEntityId == 0) { if (controller->GetButtonState(MouseButtonLeft)) { // Check if there is an entity near the given position Engine::EntityBase* asteroid = Engine::GetEntityAt (mouse_world_pos); if (asteroid) { mEditorEntityId = asteroid->mId; } } } if (mEditorEntityId != 0) { Engine::EntityBase* asteroid = Engine::GetEntity (mEditorEntityId); vector3d new_velocity = mouse_world_pos - asteroid->mPhysicState->GetPosition(); new_velocity[1] = 0.; asteroid->mPhysicState->SetVelocity (new_velocity); if (!controller->GetButtonState(MouseButtonLeft)) { if (mEditorEntityId != 0) { mEditorEntityId = 0; } } } } if (mEditorState == EditorStateSave) { glColor3f (0.2, 0.2, 0.2); Engine::GUI::DrawRoundedBlock (140, 150, screen_right - 280, 200); Engine::GUI::Label (9999, "Saving", 128, 16); SelectFont ("console.ttf size=23"); Engine::GUI::Label(51, "Filename: ", 145, 180); std::string level_name = GetModel()->GetLevelName(); glColor3f (1., 1., 1.); if (Engine::GUI::LineEdit(52, 145, 210, level_name, 32)) GetModel()->SetLevelName(level_name); if (Engine::GUI::Button (54, "Save", 145, 300, button_width, button_height)) { GetModel()->DoSaveLevel((level_name + std::string(".txt")).c_str()); Engine::LogMessage ("Save"); mEditorState = EditorStateUnknown; } if (Engine::GUI::Button (55, "Cancel", screen_right - 140 - 5 - button_width, 300, button_width, button_height)) mEditorState = EditorStateUnknown; } if (mEditorState == EditorStateLoad) { glColor3f (0.2, 0.2, 0.2); Engine::GUI::DrawRoundedBlock (140, 150, screen_right - 280, 200); Engine::GUI::Label (9999, "Loading", 128, 16); SelectFont ("console.ttf size=23"); Engine::GUI::Label(51, "Filename: ", 145, 180); std::string level_name = GetModel()->GetLevelName(); glColor3f (1., 1., 1.); if (Engine::GUI::LineEdit(52, 145, 210, level_name, 32)) GetModel()->SetLevelName(level_name); if (Engine::GUI::Button (54, "Load", 145, 300, button_width, button_height)) { GetModel()->DoLoadLevel((level_name + std::string(".txt")).c_str()); Engine::LogMessage ("Load"); mEditorState = EditorStateUnknown; } if (Engine::GUI::Button (55, "Cancel", screen_right - 140 - 5 - button_width, 300, button_width, button_height)) mEditorState = EditorStateUnknown; } if (controller->GetButtonState(MouseButtonRight) || controller->GetButtonState(SDLK_ESCAPE) ) { mEditorState = EditorStateUnknown; } } /* * Entities */ void View::DrawEntity (Engine::EntityBase *entity) { if (entity->mType == GameEntityTypeAsteroid) DrawAsteroid ((AsteroidEntity*) entity); else if (entity->mType == GameEntityTypeShip) DrawShip ((ShipEntity*) entity); else if (entity->mType == GameEntityTypeRocket) DrawRocket ((RocketEntity*) entity); else if (entity->mType == GameEntityTypeShipPart) DrawShipPart (entity); else { Engine::LogError ("Cannot draw entity: unknown type '%d'", entity->mType); } } /// \todo: Update of the animation ?? void View::DrawShip (ShipEntity *ship) { if (!ship->mAlive) return; mShipSprite.SetScale (2. * ship->mPhysicState->mRadius / mShipSprite.GetHeight()); mShipThrustSprite.SetScale (2. * ship->mPhysicState->mRadius / mShipSprite.GetHeight()); if (ship->mState == ShipEntity::Accelerating) { mShipThrustSprite.UpdateAnimation (Engine::GetFrameDuration()); mShipThrustSprite.DrawAt(-0.5, 0., 0.); } mShipSprite.DrawAt(0., 0., 0.); #ifdef DRAW_BOUNDARIES glColor3f (1., 1., 1.); DrawCircle (ship->mPhysicState->mRadius, 20); #endif } void View::DrawAsteroid (AsteroidEntity *asteroid) { mAsteroidSprite.SetScale (2. * asteroid->mPhysicState->mRadius / mAsteroidSprite.GetWidth()); mAsteroidSprite.DrawAt(0., 0., 0.); #ifdef DRAW_BOUNDARIES glColor3f (1., 1., 1.); DrawCircle (asteroid->mPhysicState->mRadius, 20); #endif } void View::DrawRocket (RocketEntity *rocket) { glColor3f (1., 1., 1.); glBegin (GL_QUADS); glVertex3f (-0.25, 0., 0.05); glVertex3f (0.05, 0., 0.05); glVertex3f (0.05, 0., -0.05); glVertex3f (-0.25, 0., -0.05); glEnd (); } void View::DrawShipPart (Engine::EntityBase *entity) { unsigned int i; mShipPartsSprite.SetScale (1. / mShipSprite.GetHeight()); for (i = 0; i < mShipPartsEntityIds.size(); i++) { if (mShipPartsEntityIds.at(i) == entity->mId) { mShipPartsSprite.DrawSubAt (i, 0., 0., 0.); } } #ifdef DRAW_BOUNDARIES glColor3f (1., 1., 1.); DrawCircle (entity->mPhysicState->mRadius, 20); #endif } }