fysxasteroids/asteroids/View.cc

648 lines
18 KiB
C++

#include "View.h"
#include "CameraBase.h"
#include "SimpleConsoleOverlay.h"
#include "IMGUIControls.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");
// 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);
star.position[1] = rand() / float(RAND_MAX);
star.position[2] = rand() / float(RAND_MAX);
mBackgroundStars.push_back (star);
}
mGUIShipSprite.LoadFromPNG("./data/textures/ship.png");
mGUIShipSprite.SetScale (0.1);
mAsteroidSprite.LoadFromPNG ("./data/textures/asteroid.png");
mShipSprite.LoadFromPNG ("./data/textures/ship.png");
mShipThrustSprite.LoadFromPNG ("./data/textures/ship_thrust.png");
mShipThrustSprite.SetAnimation (4, 8);
mShipPartsSprite.LoadFromPNG ("./data/textures/ship_parts.png");
mShipPartsSprite.SetSubSpriteCount (10);
Engine::RegisterListener (this, EventAccelerateStart);
Engine::RegisterListener (this, EventAccelerateStop);
Engine::RegisterListener (this, EventShipExplode);
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 EventShipExplode:
if (event->mEventType == EventShipExplode) {
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;
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;
part_sprite_particle->mPhysicState->mVelocity = velocity;
part_sprite_particle->mPhysicState->mVelocity = vector3d (velocity[0] * (rand()/float(RAND_MAX)) * 1.7, 0., velocity[2] * (rand()/float(RAND_MAX)) * 1.5);
part_sprite_particle->mPhysicState->mAngleVelocity = (rand()/float(RAND_MAX) - 0.5 ) * 100.;
mShipPartsEntityIds.push_back(part_sprite_particle->mId);
}
}
Engine::LogDebug ("Received Ship Explode Event: %d", event->mEventType);
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.);
if (mBackgroundStars.at(i).position[0] < 0.)
mBackgroundStars.at(i).position[0] += 1.;
if (mBackgroundStars.at(i).position[0] >= 1.)
mBackgroundStars.at(i).position[0] -= 1.;
}
glEnd();
glPopMatrix();
}
void View::Draw() {
PreDraw();
// Actual Drawing
UpdateCamera ();
if (mDrawGrid)
DrawGrid ();
/*
if (mDrawAxis)
DrawAxis ();
*/
DrawWorld ();
DrawUi ();
// mOverlayManager.Draw();
// Perform post-Draw actions
PostDraw();
}
void View::DrawWorld() {
std::map<unsigned int, Engine::EntityBase*>::iterator entity_iterator;
Model *game_model = static_cast<Model*> (mModel);
DrawStars ();
if ( game_model->GetGameState() != GameStateRunning) {
return;
}
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();
// 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);
switch (game_state) {
case GameStateMainMenu:
DrawUiMainMenu();
break;
case GameStateRunning:
DrawUiGameRunning();
break;
case GameStatePaused:
DrawUiGamePaused();
break;
case GameStatePlayerDied:
DrawUiPlayerDied();
break;
case GameStateLevelComplete:
DrawUiLevelComplete();
break;
case GameStateShowHighscore:
DrawUiHighscore();
break;
case GameStateEnterPlayername:
DrawUiEnterPlayername();
break;
case GameStateGameOver:
DrawUiGameOver();
break;
default:
Engine::LogWarning ("Trying to draw unknown GameState: %s (%d)",
GetStringGameState (game_state), game_state);
break;
}
glPopMatrix ();
glMatrixMode (GL_PROJECTION);
glPopMatrix ();
glMatrixMode (GL_MODELVIEW);
}
void View::DrawUiMainMenu() {
Engine::GUI::Label (4, "A s t e r o i d s", screen_right * 0.5 - 100, 180);
if (Engine::GUI::Button (1, "New Game", screen_right * 0.5 - 100, 200, 250, 40)) {
GetModel()->SetGameState(GameStateEnterPlayername);
}
if (Engine::GUI::Button (2, "Highscores", screen_right * 0.5 - 100, 250, 250, 40)) {
GetModel()->SetGameState(GameStateShowHighscore);
}
if (Engine::GUI::Button (3, "Quit", screen_right * 0.5 - 100, 330, 250, 40)) {
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))
GetModel()->SetGameState(GameStatePaused);
}
void View::DrawUiGameOver() {
Engine::GUI::Label (4, "G a m e O v e r", screen_right * 0.5 - 100, 180);
if (GetModel()->GetPlayerLives() == 0) {
Engine::GUI::Label(5, "That was pathetic!", screen_right * 0.5 - 80, screen_bottom * 0.5 - 8);
} else {
Engine::GUI::Label (6, "You earned yourself the",
screen_right * 0.5 - 80,
screen_bottom * 0.5 - 32);
Engine::GUI::Label (7, "You Rock(TM) award.",
screen_right * 0.5 - 60,
screen_bottom * 0.5 + 0);
Engine::GUI::Label (8, "Go tell your friends.",
screen_right * 0.5 - 70,
screen_bottom * 0.5 + 32);
}
if (Engine::GUI::Button (2, "Continue...",
screen_right * 0.5 - 100,
screen_bottom * 0.5 + 60, 250, 40)) {
GetModel()->SetGameState(GameStateShowHighscore);
}
}
void View::DrawUiLevelComplete() {
Engine::GUI::Label (4, "Level Complete!", screen_right * 0.5 - 100, 180);
Engine::GUI::Label (6, "Congratulations - You rock!", screen_right * 0.5 - 80, screen_bottom * 0.5 -16);
if(Engine::GUI::Button (1, "Next level ...", screen_right * 0.5 - 80, screen_bottom * 0.5 - 48, 250, 40)) {
GetModel()->SetGameState(GameStateRunning);
}
}
void View::DrawUiGamePaused() {
Engine::GUI::Label (4, "- P a u s e d -", screen_right * 0.5 - 100, 180);
if (Engine::GUI::Button (1, "Resume Game", screen_right * 0.5 - 100, 200, 250, 40)) {
GetModel()->SetGameState(GameStateRunning);
}
if (Engine::GUI::Button (2, "Abort Game", screen_right * 0.5 - 100, 250, 250, 40)) {
GetModel()->SetGameState(GameStateMainMenu);
}
if (Engine::GUI::Button (3, "Quit", screen_right * 0.5 - 100, 330, 250, 40)) {
Engine::RunCommand("quit");
}
}
void View::DrawUiPlayerDied() {
Engine::GUI::Label (4, "You died ...", screen_right * 0.5 - 40, screen_bottom * 0.5 - 8 - 32);
if (Engine::GUI::Button (1, "Continue", screen_right * 0.5 - 100, 200, 250, 40)) {
GetModel()->SetGameState(GameStateRunning);
}
}
void View::DrawUiHighscore() {
float x = screen_right * 0.5 - 100;
float y = screen_bottom * 0.5 - 8 - 128;
// then we do the drawings
Engine::DrawGLString ( x, y, "A s t e r o i d s");
y += 30;
Engine::DrawGLString ( x, y, "Highscore");
y += 30;
std::list<Model::HighscoreEntry>::iterator highscore_iter = GetModel()->mHighscoreList.begin();
SetFontJustification(Engine::FontJustificationLeft);
unsigned int entry_length = 32;
unsigned int i = 0;
while (highscore_iter != GetModel()->mHighscoreList.end()) {
// compute the number of digits
unsigned int digits = 1;
unsigned int temp_val = highscore_iter->points;
while (temp_val > 0) {
temp_val /= 10;
digits ++;
}
// output of the name
std::ostringstream out_stream;
out_stream << highscore_iter->name;
// add dots to fill the line
temp_val = entry_length - out_stream.str().size() - digits;
for (temp_val; temp_val > 0; temp_val--) {
out_stream << ".";
}
out_stream << highscore_iter->points;
// Check whether we have to highlight an entry (such as when entering
// the name)
if (GetModel()->mNewestHighscoreEntryIndex < GetModel()->mHighscoreList.size()
&& GetModel()->mNewestHighscoreEntryIndex == i) {
SelectFont("console.ttf color=#e8d500");
Engine::DrawGLString ( x, y, out_stream.str().c_str());
SelectFont("console.ttf color=#ffffff");
} else {
Engine::DrawGLString ( x, y, out_stream.str().c_str());
}
// go down one line
y += 16;
i++;
highscore_iter++;
}
if (Engine::GUI::Button (1, "Back to MainMenu", x + 16, y + 16, 250, 40)) {
GetModel()->SetGameState(GameStateMainMenu);
}
}
void View::DrawUiEnterPlayername() {
Engine::GUI::Label (4, "A s t e r o i d s", screen_right * 0.5 - 100, 180);
// Enter your name
std::string player_name = GetModel()->GetPlayerName();
SelectFont("console.ttf");
Engine::GUI::Label (1, "Enter your name: ", screen_right * 0.5 - 100, 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 - 150 - 20, 500, 150, 40)) {
GetModel()->SetGameState(GameStateRunning);
}
if (Engine::GUI::Button (5, "Back", 20, 500, 150, 40)) {
GetModel()->SetGameState(GameStateMainMenu);
}
}
/*
* 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
}
}