fysxasteroids/asteroids/View.cc

1065 lines
30 KiB
C++

#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 <GL/gl.h>
#include <GL/glu.h>
// #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<Engine::SimpleConsoleOverlay> (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:
if (GetModel()->GetGameState() == GameStateRunning) {
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<Model*>(mModel)->GetWorldWidth();
world_height = static_cast<Model*>(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<unsigned int, Engine::EntityBase*>::iterator entity_iterator;
Model *game_model = static_cast<Model*> (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<unsigned int, Engine::EntityBase*>::iterator entity_iterator;
Model *game_model = static_cast<Model*> (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<float> (Engine::GetWindowWidth());
screen_bottom = static_cast<float> (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);
GetController()->ResetLevel();
}
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 <name> .... <points>
*
* 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<Model::HighscoreEntry>::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");
// The close button
if (Engine::GUI::Button (1, "X", screen_right - 48, 20, 32, button_height)
|| Engine::GUI::CheckKeyPressed(SDLK_ESCAPE)) {
if (mEditorState == EditorStateTest) {
mEditorState = EditorStateUnknown;
GetModel()->DoLoadLevel("level_edit_temp.txt");
GetModel()->SetGameState(GameStatePaused);
return;
} else {
PopViewState();
}
}
if (mEditorState != EditorStateTest) {
if (Engine::GUI::Button (2, "Add", 30, 20, 50, button_height)) {
mEditorState = EditorStateAddEntity;
Engine::LogDebug ("Editor state now Add");
return;
}
if (Engine::GUI::Button (3, "Del", 85, 20, 50, button_height)) {
mEditorState = EditorStateDelEntity;
Engine::LogDebug ("Editor state now Del");
return;
}
if (Engine::GUI::Button (4, "Move", 140, 20, 65, button_height)) {
mEditorState = EditorStateMoveEntity;
Engine::LogDebug ("Editor state now Move");
return;
}
if (Engine::GUI::Button (5, "Spd", 210, 20, 50, button_height)) {
mEditorState = EditorStateEntityVelocity;
Engine::LogDebug ("Editor state now Add");
return;
}
if (Engine::GUI::Button (6, "Save", 265, 20, 65, button_height)) {
mEditorState = EditorStateSave;
Engine::LogDebug ("Editor state now Save");
return;
}
if (Engine::GUI::Button (7, "Load", 335, 20, 65, button_height)) {
mEditorState = EditorStateLoad;
Engine::LogDebug ("Editor state now Load");
return;
}
// we only show the Test button when there is actually something to play
// (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)) {
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::CheckKeyPressed(MouseButtonLeft)) {
// if there is no entity so far we create a player, otherwise we create
// an asteroid
Engine::EntityBase* entity = NULL;
if (GetModel()->GetPlayerEntityId() != Engine::NullEntityId) {
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]));
}
}
if (mEditorState == EditorStateDelEntity) {
SelectFont ("console.ttf size=12");
Engine::GUI::Label (9999, "Deleting", 128, 16);
if (Engine::GUI::CheckKeyPressed(MouseButtonLeft)) {
// Check if there is an entity near the given position
Engine::EntityBase* entity = Engine::GetEntityAt (mouse_world_pos);
if (entity && entity->mType == GameEntityTypeAsteroid) {
Engine::LogMessage ("Killing entity with id %u", entity->mId);
GetModel()->UnregisterEntity (entity->mId);
}
}
}
if (mEditorState == EditorStateMoveEntity) {
SelectFont ("console.ttf size=12");
Engine::GUI::Label (9999, "Moving", 128, 16);
if (Engine::GUI::CheckKeyPress(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 (!Engine::GUI::CheckKeyPress(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 (Engine::GUI::CheckKeyPress(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 (!Engine::GUI::CheckKeyPress(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::FileExists (level_name + std::string(".txt"))) {
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 (Engine::GUI::CheckKeyPressed(MouseButtonRight)
|| Engine::GUI::CheckKeyPressed(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
}
}