From 57ea0596b87cc903e87d841c7fca8f57025ad062 Mon Sep 17 00:00:00 2001 From: "Martin Felis (berta)" Date: Sat, 12 Feb 2011 15:43:06 +0100 Subject: [PATCH] editor and game improvements - (editor) entities can be rotated - (editor) asteroids get a random angular velocity - (editor) level title and author can be specified - (editor) editor can only be quit when clicking the 'X' button - (game) smaller asteroids have similar velocities as the previous bigger ones --- asteroids/AsteroidEntity.cc | 8 ++-- asteroids/Model.cc | 24 +++++++++++ asteroids/Model.h | 14 +++++++ asteroids/View.cc | 79 +++++++++++++++++++++++++++++++------ asteroids/View.h | 1 + data/levels/level1.txt | 2 + engine/CMakeLists.txt | 1 + engine/ControllerBase.cc | 7 ++++ engine/Engine.h | 1 + engine/IMGUIControls.cc | 19 +++++++++ engine/PhysicsBase.cc | 2 +- engine/ViewBase.cc | 39 +++++++++++++++++- engine/ViewBase.h | 12 ++++++ 13 files changed, 192 insertions(+), 17 deletions(-) diff --git a/asteroids/AsteroidEntity.cc b/asteroids/AsteroidEntity.cc index fbf2cce..abba494 100644 --- a/asteroids/AsteroidEntity.cc +++ b/asteroids/AsteroidEntity.cc @@ -23,13 +23,15 @@ bool AsteroidEntity::CollisionEvent (Engine::EntityBase* entity_state, vector3d int i; for (i = 0; i < mSubAsteroidsCount; i++) { AsteroidEntity *asteroid = (AsteroidEntity*) Engine::CreateEntity (GameEntityTypeAsteroid); + vector3d position (rand()/float(RAND_MAX) * 1. - 0.5, 0., rand()/float(RAND_MAX) * 1. - 0.5); + asteroid->mPhysicState->mPosition = mPhysicState->mPosition + position; + asteroid->mPhysicState->mVelocity = position + mPhysicState->mVelocity * 0.5; + asteroid->mPhysicState->mAngleVelocity = mPhysicState->mAngleVelocity + (rand()/float(RAND_MAX) * 2. - 1) * mPhysicState->mAngleVelocity; + asteroid->mSubAsteroidsCount = 0; asteroid->mPhysicState->mRadius = 2. * mPhysicState->mRadius / mSubAsteroidsCount; static_cast(asteroid->mPhysicState->mShape)->setRadius (asteroid->mPhysicState->mRadius); - asteroid->mPhysicState->mPosition = mPhysicState->mPosition + position; - asteroid->mPhysicState->mVelocity = position; - asteroid->mPhysicState->mAngleVelocity = mPhysicState->mAngleVelocity + (rand()/float(RAND_MAX) * 2. - 1) * mPhysicState->mAngleVelocity; } Engine::KillEntity (mId); diff --git a/asteroids/Model.cc b/asteroids/Model.cc index 2a318ba..eb1df0c 100644 --- a/asteroids/Model.cc +++ b/asteroids/Model.cc @@ -66,6 +66,9 @@ int Model::OnInit (int argc, char* argv[]) { mPlayerName = "Player"; + mLevelAuthor = ""; + mLevelTitle = ""; + Engine::PlayMusic (Engine::GetResourceFullPath("/data/sounds/intro_music.ogg")); Engine::RegisterListener (this, EventAccelerateStart); @@ -266,6 +269,20 @@ int Model::DoLoadLevel (const char* filename) { getline (level_file, entity_type_str); Engine::LogDebug ("Read Comment: %s", entity_type_str.c_str()); continue; + } else if (entity_type_str == "Title") { + std::string level_title; + + getline (level_file, level_title); + level_title = strip_whitespaces (level_title); + SetLevelTitle (level_title); + continue; + } else if (entity_type_str == "Author") { + std::string level_author; + + getline (level_file, level_author); + level_author = strip_whitespaces (level_author); + SetLevelAuthor (level_author); + continue; } GameEntityType entity_type = GameEntityTypeUnknown; @@ -325,6 +342,13 @@ int Model::DoSaveLevel (const char* filename) { level_file << "# Format" << std::endl; level_file << "# " << std::endl; + if (GetLevelTitle() != "") { + level_file << "Title " << mLevelTitle << std::endl; + } + if (GetLevelAuthor() != "") { + level_file << "Author " << mLevelAuthor << std::endl; + } + std::map::iterator iter = mEntities.begin(); unsigned int player_id = GetPlayerEntityId(); diff --git a/asteroids/Model.h b/asteroids/Model.h index 6c6de62..5362bbb 100644 --- a/asteroids/Model.h +++ b/asteroids/Model.h @@ -41,6 +41,18 @@ class Model : public Engine::ModelBase { mLevelName = name; } + std::string GetLevelAuthor() { return mLevelAuthor; }; + void SetLevelAuthor(const std::string &author) { + Engine::LogMessage("new level author: %s", author.c_str()); + mLevelAuthor = author; + } + + std::string GetLevelTitle() { return mLevelTitle; }; + void SetLevelTitle(const std::string &title) { + Engine::LogMessage("new level title: %s", title.c_str()); + mLevelTitle = title; + } + /* Highscore */ struct HighscoreEntry { HighscoreEntry(): name ("unknown"), points (0) { }; @@ -85,6 +97,8 @@ class Model : public Engine::ModelBase { std::string mPlayerName; std::vector mLevelList; std::string mLevelName; + std::string mLevelAuthor; + std::string mLevelTitle; virtual bool OnReceiveEvent (const Engine::EventBasePtr &event); diff --git a/asteroids/View.cc b/asteroids/View.cc index 213bdb8..07c68a2 100644 --- a/asteroids/View.cc +++ b/asteroids/View.cc @@ -149,7 +149,7 @@ bool View::OnReceiveEvent (const Engine::EventBasePtr &event) { 0., rel_velocity[2] * (rand()/float(RAND_MAX)) * 1.5 ); - part_sprite_particle->mPhysicState->mVelocity = part_velocity; + part_sprite_particle->mPhysicState->mVelocity = part_velocity * -1.; part_sprite_particle->mPhysicState->mAngleVelocity = (rand()/float(RAND_MAX) - 0.5 ) * 100.; @@ -767,7 +767,7 @@ void View::DrawUiEnterPlayername() { } void View::DrawUiEditor() { -// DrawPageTitle ("Editor"); + // DrawPageTitle ("Editor"); SelectFont ("console.ttf size=23"); // The close button @@ -780,7 +780,7 @@ void View::DrawUiEditor() { GetModel()->DoLoadLevel("level_edit_temp.txt"); GetModel()->SetGameState(GameStatePaused); return; - } else { + } else if (!Engine::GUI::CheckKeyPressed(SDLK_ESCAPE)){ PopViewState(); } } @@ -804,19 +804,25 @@ void View::DrawUiEditor() { return; } - if (Engine::GUI::CheckButton (5, "Spd", mEditorState == EditorStateEntityVelocity, 210, 20, 50, button_height)) { + if (Engine::GUI::CheckButton (5, "Rot", mEditorState == EditorStateRotateEntity, 210, 20, 50, button_height)) { + mEditorState = EditorStateRotateEntity; + Engine::LogDebug ("Editor state now Move"); + return; + } + + if (Engine::GUI::CheckButton (6, "Spd", mEditorState == EditorStateEntityVelocity, 265, 20, 50, button_height)) { mEditorState = EditorStateEntityVelocity; Engine::LogDebug ("Editor state now Add"); return; } - if (Engine::GUI::Button (6, "Save", 265, 20, 65, button_height)) { + if (Engine::GUI::Button (7, "Save", 325, 20, 65, button_height)) { mEditorState = EditorStateSave; Engine::LogDebug ("Editor state now Save"); return; } - if (Engine::GUI::Button (7, "Load", 335, 20, 65, button_height)) { + if (Engine::GUI::Button (8, "Load", 400, 20, 65, button_height)) { mEditorState = EditorStateLoad; Engine::LogDebug ("Editor state now Load"); return; @@ -826,7 +832,7 @@ void View::DrawUiEditor() { // (i.e. a player entity and at least one asteroid) if (GetModel()->GetPlayerEntityId() != 0 && GetModel()->mAsteroids.size() > 0) { - if (Engine::GUI::Button (8, "Test", 405, 20, 64, button_height)) { + if (Engine::GUI::Button (9, "Test", 475, 20, 64, button_height)) { mEditorState = EditorStateTest; GetModel()->DoSaveLevel("level_edit_temp.txt"); @@ -854,6 +860,7 @@ void View::DrawUiEditor() { if (GetModel()->GetPlayerEntityId() != Engine::NullEntityId) { entity = Engine::CreateEntity(GameEntityTypeAsteroid); entity->mPhysicState->SetVelocity (vector3d (0., 0., -1.)); + entity->mPhysicState->SetAngleVelocity ( (rand()/float(RAND_MAX) - 0.5) * 120); } else { entity = Engine::CreateEntity(GameEntityTypeShip); GetModel()->SetPlayerEntityId(entity->mId); @@ -904,6 +911,41 @@ void View::DrawUiEditor() { } } + if (mEditorState == EditorStateRotateEntity) { + SelectFont ("console.ttf size=12"); + +// static vector3d mouse_start_rotate (0., 0., 0.); + static float start_angle = 0.; + if (mEditorEntityId == 0) { + if (Engine::GUI::CheckKeyPress(MouseButtonLeft)) { + // Check if there is an entity near the given position + Engine::EntityBase* entity = Engine::GetEntityAt (mouse_world_pos); + + if (entity) { + mEditorEntityId = entity->mId; + vector3d mouse_start_rotate = mouse_world_pos - entity->mPhysicState->GetPosition(); + start_angle = atan2 (mouse_start_rotate[0], mouse_start_rotate[2]) * 180 / M_PI - entity->mPhysicState->mOrientation[1]; + } else { + mEditorEntityId = 0; + } + } + } + + if (mEditorEntityId != 0) { + Engine::EntityBase* entity = Engine::GetEntity (mEditorEntityId); + + vector3d new_velocity = mouse_world_pos - entity->mPhysicState->GetPosition(); + new_velocity[1] = 0.; + float angle = atan2 (new_velocity[0], new_velocity[2]) * 180. / M_PI; + + entity->mPhysicState->SetOrientation (vector3d (0., angle - start_angle, 0.)); + + if (!Engine::GUI::CheckKeyPress(MouseButtonLeft)) { + mEditorEntityId = 0; + } + } + } + if (mEditorState == EditorStateEntityVelocity) { SelectFont ("console.ttf size=12"); // Engine::GUI::Label (9999, "Velocity", 128, 16); @@ -935,7 +977,7 @@ void View::DrawUiEditor() { if (mEditorState == EditorStateSave) { glColor3f (0.2, 0.2, 0.2); - Engine::GUI::DrawRoundedBlock (140, 150, screen_right - 280, 200); + Engine::GUI::DrawRoundedBlock (140, 150, screen_right - 280, 280); // Engine::GUI::Label (9999, "Saving", 128, 16); SelectFont ("console.ttf size=23"); @@ -943,16 +985,26 @@ void View::DrawUiEditor() { std::string level_name = GetModel()->GetLevelName(); glColor3f (1., 1., 1.); - if (Engine::GUI::LineEdit(52, 145, 210, level_name, 32)) + if (Engine::GUI::LineEdit(52, 150, 200, level_name, 31)) GetModel()->SetLevelName(level_name); - if (Engine::GUI::Button (54, "Save", 145, 300, button_width, button_height)) { + Engine::GUI::Label(53, "Author: ", 145, 250); + std::string level_author = GetModel()->GetLevelAuthor(); + if (Engine::GUI::LineEdit(531, 150, 270, level_author, 31)) + GetModel()->SetLevelAuthor(level_author); + + Engine::GUI::Label(54, "Level Title: ", 145, 320); + std::string level_title = GetModel()->GetLevelTitle(); + if (Engine::GUI::LineEdit(541, 150, 340, level_title, 31)) + GetModel()->SetLevelTitle(level_title); + + if (Engine::GUI::Button (55, "Save", 145, 380, 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)) + if (Engine::GUI::Button (56, "Cancel", screen_right - 140 - 5 - button_width, 380, button_width, button_height)) mEditorState = EditorStateUnknown; } @@ -981,6 +1033,11 @@ void View::DrawUiEditor() { mEditorState = EditorStateUnknown; } + if (Engine::GUI::CheckKeyPressed(SDLK_ESCAPE)) { + if (mEditorState != EditorStateUnknown) + mEditorState = EditorStateUnknown; + } + if (Engine::GUI::CheckKeyPressed(MouseButtonRight) || Engine::GUI::CheckKeyPressed(SDLK_ESCAPE) ) { mEditorState = EditorStateUnknown; diff --git a/asteroids/View.h b/asteroids/View.h index 84bfc49..929eef9 100644 --- a/asteroids/View.h +++ b/asteroids/View.h @@ -138,6 +138,7 @@ class View : public Engine::ViewBase { EditorStateAddEntity, EditorStateDelEntity, EditorStateMoveEntity, + EditorStateRotateEntity, EditorStateSave, EditorStateEntityVelocity, EditorStateLoad, diff --git a/data/levels/level1.txt b/data/levels/level1.txt index 86e84ac..4137942 100644 --- a/data/levels/level1.txt +++ b/data/levels/level1.txt @@ -1,5 +1,7 @@ # Format # +Title Let's get started... +Author Martin Felis GameEntityTypeShip 1 0 0 0 0 90 0 0 0 0 0 GameEntityTypeAsteroid 0 5 0 -2 0 0 0 -0.2 0 -0.1 -10 GameEntityTypeAsteroid 0 -2 0 2 0 0 0 0.3 0 -0.4 5 diff --git a/engine/CMakeLists.txt b/engine/CMakeLists.txt index d75232b..daf86d0 100644 --- a/engine/CMakeLists.txt +++ b/engine/CMakeLists.txt @@ -37,6 +37,7 @@ SET ( ENGINE_SRCS Engine.cc Logging.cc EnumStrings.cc + Utils.cc ) INCLUDE_DIRECTORIES ( diff --git a/engine/ControllerBase.cc b/engine/ControllerBase.cc index 4a12165..39036d8 100644 --- a/engine/ControllerBase.cc +++ b/engine/ControllerBase.cc @@ -188,6 +188,13 @@ bool ControllerBase::OnKeyDown (const SDL_keysym &keysym) { /** \brief Keyboard processing */ bool ControllerBase::OnKeyUp (const SDL_keysym &keysym) { SetButtonState (keysym.sym, false); + + if (keysym.sym == SDLK_F12) { + if (mView->GetIsFullscreen()) + mView->SetFullscreen(false); + else + mView->SetFullscreen(true); + } uistate.keypressed_set.insert (keysym.sym); diff --git a/engine/Engine.h b/engine/Engine.h index 0c89624..1854074 100644 --- a/engine/Engine.h +++ b/engine/Engine.h @@ -20,6 +20,7 @@ #include "Module.h" #include "EngineEnums.h" +#include "Utils.h" // Some ugly #defines diff --git a/engine/IMGUIControls.cc b/engine/IMGUIControls.cc index 9e0b2ea..32b5396 100644 --- a/engine/IMGUIControls.cc +++ b/engine/IMGUIControls.cc @@ -257,6 +257,12 @@ bool Button (int id, const char* caption, int x, int y, int w, int h) { controller->uistate.hotitem = controller->uistate.lastwidget; controller->uistate.last_keysym = SDLK_CLEAR; break; + case SDLK_TAB: + controller->uistate.last_keysym = SDLK_CLEAR; + controller->uistate.last_unicode = 0; + controller->uistate.hotitem = 0; + controller->uistate.kbditem = 0; + break; case SDLK_RETURN: controller->uistate.last_keysym = SDLK_CLEAR; // As we (probably) exit the current set of widgets, we have to clear @@ -372,6 +378,12 @@ bool CheckButton (int id, const char* caption, bool checked, int x, int y, int w controller->uistate.hotitem = controller->uistate.lastwidget; controller->uistate.last_keysym = SDLK_CLEAR; break; + case SDLK_TAB: + controller->uistate.last_keysym = SDLK_CLEAR; + controller->uistate.last_unicode = 0; + controller->uistate.hotitem = 0; + controller->uistate.kbditem = 0; + break; case SDLK_RETURN: controller->uistate.last_keysym = SDLK_CLEAR; // As we (probably) exit the current set of widgets, we have to clear @@ -478,6 +490,13 @@ bool LineEdit (int id, int x, int y, std::string &text_value, const int &maxleng controller->uistate.kbditem = 0; return false; break; + case SDLK_TAB: + controller->uistate.last_keysym = SDLK_CLEAR; + controller->uistate.last_unicode = 0; + controller->uistate.hotitem = 0; + controller->uistate.kbditem = 0; + return false; + break; case SDLK_RETURN: controller->uistate.last_keysym = SDLK_CLEAR; controller->uistate.last_unicode = 0; diff --git a/engine/PhysicsBase.cc b/engine/PhysicsBase.cc index 4da6627..cc489fb 100644 --- a/engine/PhysicsBase.cc +++ b/engine/PhysicsBase.cc @@ -99,11 +99,11 @@ int PhysicsBase::Simulate (float msec, ModelBase* model) { // if the timestep is too small we simply resolve the collision and // do not move beforehang LogDebug ("Time step too small ==> Resolving Step immediately"); - ResolveCollision (0., entity_a_id, entity_b_id, info); // Send the collision event to the Model (if we have one) if (model) { model->SendEntityCollisionEvent (entity_a_id, entity_b_id, info.time, info.point, info.normal); } + ResolveCollision (0., entity_a_id, entity_b_id, info); // collision_remaining_step -= 1.0e-4; } else { Move (info.time * (1 - alpha)); diff --git a/engine/ViewBase.cc b/engine/ViewBase.cc index dedf2be..fc69333 100644 --- a/engine/ViewBase.cc +++ b/engine/ViewBase.cc @@ -43,13 +43,21 @@ int ViewBase::OnInit (int argc, char* argv[]) { mWindowHeight = VIEW_DEFAULT_HEIGHT; mWindowWidth = VIEW_DEFAULT_WIDTH; + // get and save the screen resolution + mScreenHeight = SDL_GetVideoInfo()->current_h; + mScreenWidth = SDL_GetVideoInfo()->current_w; + + mDrawFullscreen = false; + SDL_GL_SetAttribute( SDL_GL_DOUBLEBUFFER, 1 ); - if( SDL_SetVideoMode( mWindowWidth, mWindowHeight, 16, SDL_OPENGL | SDL_RESIZABLE ) == 0 ) { + if( SDL_SetVideoMode( mWindowWidth, mWindowHeight, 16, SDL_OPENGL ) == 0 ) { LogError ("Video mode set failed: %s", SDL_GetError ()); exit (-1); } + LogMessage ("Resolution is %dx%d", SDL_GetVideoInfo()->current_w, SDL_GetVideoInfo()->current_h); + InitGL (); Resize (mWindowWidth, mWindowHeight); @@ -187,6 +195,28 @@ void ViewBase::PostDraw() { SDL_GL_SwapBuffers (); } +void ViewBase::SetFullscreen (bool fullscreen) { + if (fullscreen && mDrawFullscreen) + return; + + if (!fullscreen && !mDrawFullscreen) + return; + + if (mDrawFullscreen) { + mWindowHeight = VIEW_DEFAULT_HEIGHT; + mWindowWidth = VIEW_DEFAULT_WIDTH; + + mDrawFullscreen = false; + } else { + mWindowWidth = mScreenWidth; + mWindowHeight = mScreenHeight; + + mDrawFullscreen = true; + } + + Resize (mWindowWidth, mWindowHeight); +} + /* Fonts */ /** \brief Parses font specifications strings into its values @@ -401,7 +431,12 @@ void ViewBase::Resize (int width, int height) { * workaround, however since I do not yet run SDL 1.3 I hold on to this. * See http://lists.libsdl.org/pipermail/sdl-libsdl.org/2008-November/067306.html */ - if( SDL_SetVideoMode( mWindowWidth, mWindowHeight, 16, SDL_OPENGL | SDL_RESIZABLE ) == 0 ) { + Uint32 video_flags = SDL_OPENGL; + + if (mDrawFullscreen) + video_flags = video_flags | SDL_FULLSCREEN; + + if( SDL_SetVideoMode( mWindowWidth, mWindowHeight, 16, video_flags) == 0 ) { LogError ("Video mode set failed: %s", SDL_GetError ()); exit (-1); } diff --git a/engine/ViewBase.h b/engine/ViewBase.h index 36c21f5..1f27cc5 100644 --- a/engine/ViewBase.h +++ b/engine/ViewBase.h @@ -26,6 +26,9 @@ class ViewBase : public Module{ /** \brief Resizes the View */ void Resize (int width, int height); + /** \brief Switches to fullscreen */ + void SetFullscreen (bool fullscreen); + bool GetIsFullscreen () { return mDrawFullscreen; }; /** \brief Performs actions before drawing (e.g. timer stuff) */ void PreDraw(); @@ -96,6 +99,8 @@ class ViewBase : public Module{ /** \brief Draws orthographic overlay*/ void DrawOverlay2D (); + bool mDrawFullscreen; + /** \brief Draws a grid of 16 x 16 tiles */ void DrawGrid (); bool mDrawGrid; @@ -114,6 +119,13 @@ class ViewBase : public Module{ unsigned int mWindowHeight; /** \brief The width of the canvas we're drawing on */ unsigned int mWindowWidth; + + /** \brief The height of the screen in pixels */ + unsigned int mScreenHeight; + /** \brief The width of the screen in pixels */ + unsigned int mScreenWidth; + + /** \brief Stores the current frame rate */ int mFrameRate;