1122 lines
33 KiB
C++
1122 lines
33 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 * -1.;
|
|
|
|
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);
|
|
|
|
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 if (!Engine::GUI::CheckKeyPressed(SDLK_ESCAPE)){
|
|
PopViewState();
|
|
}
|
|
}
|
|
|
|
if (mEditorState != EditorStateTest) {
|
|
if (Engine::GUI::CheckButton (2, "Add", mEditorState == EditorStateAddEntity, 30, 20, 50, button_height)) {
|
|
mEditorState = EditorStateAddEntity;
|
|
Engine::LogDebug ("Editor state now Add");
|
|
return;
|
|
}
|
|
|
|
if (Engine::GUI::CheckButton (3, "Del", mEditorState == EditorStateDelEntity, 85, 20, 50, button_height)) {
|
|
mEditorState = EditorStateDelEntity;
|
|
Engine::LogDebug ("Editor state now Del");
|
|
return;
|
|
}
|
|
|
|
if (Engine::GUI::CheckButton (4, "Move", mEditorState == EditorStateMoveEntity, 140, 20, 65, button_height)) {
|
|
mEditorState = EditorStateMoveEntity;
|
|
Engine::LogDebug ("Editor state now Move");
|
|
return;
|
|
}
|
|
|
|
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 (7, "Save", 325, 20, 65, button_height)) {
|
|
mEditorState = EditorStateSave;
|
|
Engine::LogDebug ("Editor state now Save");
|
|
return;
|
|
}
|
|
|
|
if (Engine::GUI::Button (8, "Load", 400, 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 (9, "Test", 475, 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.));
|
|
entity->mPhysicState->SetAngleVelocity ( (rand()/float(RAND_MAX) - 0.5) * 120);
|
|
} 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 == 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);
|
|
|
|
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, 280);
|
|
// 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, 150, 200, level_name, 31))
|
|
GetModel()->SetLevelName(level_name);
|
|
|
|
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(".map")).c_str());
|
|
Engine::LogMessage ("Save");
|
|
mEditorState = EditorStateUnknown;
|
|
}
|
|
|
|
if (Engine::GUI::Button (56, "Cancel", screen_right - 140 - 5 - button_width, 380, 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(".map"))) {
|
|
if (Engine::GUI::Button (54, "Load", 145, 300, button_width, button_height)) {
|
|
GetModel()->DoLoadLevel((level_name + std::string(".map")).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(SDLK_ESCAPE)) {
|
|
if (mEditorState != EditorStateUnknown)
|
|
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
|
|
}
|
|
|
|
}
|