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
main
Martin Felis (berta) 2011-02-12 15:43:06 +01:00
parent 42d40befcd
commit 57ea0596b8
13 changed files with 192 additions and 17 deletions

View File

@ -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<coll2d::Sphere*>(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);

View File

@ -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 << "# <Type> <player?> <xpos> <ypos> <zpos> <zrot> <yrot> <xrot> <xvel> <yvel> <zvel> <rotvel>" << std::endl;
if (GetLevelTitle() != "") {
level_file << "Title " << mLevelTitle << std::endl;
}
if (GetLevelAuthor() != "") {
level_file << "Author " << mLevelAuthor << std::endl;
}
std::map<unsigned int, Engine::EntityBase*>::iterator iter = mEntities.begin();
unsigned int player_id = GetPlayerEntityId();

View File

@ -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<std::string> mLevelList;
std::string mLevelName;
std::string mLevelAuthor;
std::string mLevelTitle;
virtual bool OnReceiveEvent (const Engine::EventBasePtr &event);

View File

@ -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;

View File

@ -138,6 +138,7 @@ class View : public Engine::ViewBase {
EditorStateAddEntity,
EditorStateDelEntity,
EditorStateMoveEntity,
EditorStateRotateEntity,
EditorStateSave,
EditorStateEntityVelocity,
EditorStateLoad,

View File

@ -1,5 +1,7 @@
# Format
# <Type> <player?> <xpos> <ypos> <zpos> <zrot> <yrot> <xrot> <xvel> <yvel> <zvel> <rotvel>
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

View File

@ -37,6 +37,7 @@ SET ( ENGINE_SRCS
Engine.cc
Logging.cc
EnumStrings.cc
Utils.cc
)
INCLUDE_DIRECTORIES (

View File

@ -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);

View File

@ -20,6 +20,7 @@
#include "Module.h"
#include "EngineEnums.h"
#include "Utils.h"
// Some ugly #defines

View File

@ -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;

View File

@ -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));

View File

@ -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);
}

View File

@ -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;