+/*
+ * Match.cpp
+ *
+ * Created on: Apr 9, 2012
+ * Author: holy
+ */
+
+#include "Match.h"
+
+#include "../app/Control.h"
+
+#include <sstream>
+#include <stdexcept>
+#include <utility>
+#include <SDL/SDL.h>
+
+using app::Control;
+using game::Collision;
+using game::Entity;
+using std::runtime_error;
+using std::stringstream;
+using std::vector;
+
+
+namespace pong {
+
+Match::Match(void)
+: ctrl(0)
+, scoreFont(TTF_OpenFont("data/font/Magra-Regular.ttf", 30))
+, leftScoreText(0)
+, rightScoreText(0)
+, paddleSpeed(150)
+, worldWidth(800)
+, worldHeight(480)
+, ball(10)
+, secondBall(7)
+, leftPaddle(Entity::Vector(10, 100))
+, rightPaddle(Entity::Vector(10, 100))
+, topWall(Entity::Vector(800, 10))
+, bottomWall(Entity::Vector(800, 10))
+, leftWall(Entity::Vector(10, 480))
+, rightWall(Entity::Vector(10, 480))
+, entities()
+, collisions()
+, updateScore(true) {
+
+ if (!scoreFont) {
+ throw runtime_error("failed to load score font");
+ }
+
+ ball.SetPosition(Entity::Vector(400, 240));
+ ball.SetVelocity(Entity::Vector(180, 180));
+ ball.SetMaxVelocity(500.0f);
+
+ secondBall.SetPosition(Entity::Vector(300, 240));
+ secondBall.SetVelocity(Entity::Vector(-20, -20));
+ secondBall.SetMaxVelocity(600.0f);
+
+ leftPaddle.SetPosition(Entity::Vector(0, 200));
+ rightPaddle.SetPosition(Entity::Vector(790, 280));
+
+ leftPaddle.SetMovementSpeed(Entity::Vector(0, paddleSpeed));
+ rightPaddle.SetMovementSpeed(Entity::Vector(0, paddleSpeed));
+
+ leftPaddle.SetStatic();
+ rightPaddle.SetStatic();
+
+ topWall.SetPosition(Entity::Vector(0, -10));
+ rightWall.SetPosition(Entity::Vector(800, 0));
+ bottomWall.SetPosition(Entity::Vector(0, 480));
+ leftWall.SetPosition(Entity::Vector(-10, 0));
+
+ topWall.SetStatic();
+ rightWall.SetStatic();
+ bottomWall.SetStatic();
+ leftWall.SetStatic();
+
+ entities.reserve(8);
+ entities.push_back(&ball);
+ entities.push_back(&secondBall);
+ entities.push_back(&leftPaddle);
+ entities.push_back(&rightPaddle);
+ entities.push_back(&topWall);
+ entities.push_back(&bottomWall);
+ entities.push_back(&leftWall);
+ entities.push_back(&rightWall);
+
+ collisions.reserve(2 * entities.size());
+}
+
+Match::~Match(void) {
+
+}
+
+
+void Match::EnterState(Control *c, SDL_Surface *screen) {
+ ctrl = c;
+}
+
+void Match::ExitState(void) {
+ if (scoreFont) {
+ TTF_CloseFont(scoreFont);
+ scoreFont = 0;
+ }
+}
+
+void Match::HandleEvent(const SDL_Event &e) {
+ if (e.type == SDL_KEYDOWN) {
+ if (e.key.keysym.sym == SDLK_w) {
+ leftPaddle.StartMovingUp();
+ } else if (e.key.keysym.sym == SDLK_s) {
+ leftPaddle.StartMovingDown();
+ } else if (e.key.keysym.sym == SDLK_UP) {
+ rightPaddle.StartMovingUp();
+ } else if (e.key.keysym.sym == SDLK_DOWN) {
+ rightPaddle.StartMovingDown();
+ }
+ } else if (e.type == SDL_KEYUP) {
+ if (e.key.keysym.sym == SDLK_w) {
+ leftPaddle.StopMovingUp();
+ } else if (e.key.keysym.sym == SDLK_s) {
+ leftPaddle.StopMovingDown();
+ } else if (e.key.keysym.sym == SDLK_UP) {
+ rightPaddle.StopMovingUp();
+ } else if (e.key.keysym.sym == SDLK_DOWN) {
+ rightPaddle.StopMovingDown();
+ } else if (e.key.keysym.sym == SDLK_q) {
+ if (ctrl) ctrl->Quit();
+ }
+ }
+}
+
+void Match::UpdateWorld(float deltaT) {
+ UpdateEntities(deltaT);
+ CheckCollisions(deltaT);
+ HandleCollisions(deltaT);
+}
+
+void Match::UpdateEntities(float deltaT) {
+ for (vector<Entity *>::const_iterator i(entities.begin()), end(entities.end()); i != end; ++i) {
+ (*i)->Update(deltaT);
+ }
+}
+
+void Match::CheckCollisions(float deltaT) {
+ Entity::Vector normal;
+ for (vector<Entity *>::const_iterator i(entities.begin()), end(entities.end()); i != end; ++i) {
+ for (vector<Entity *>::const_iterator j(i + 1); j != end; ++j) {
+ if ((*i)->Overlaps(**j, normal)) {
+ if ((*i)->IsDynamic()) {
+ (*i)->Move(normal);
+ while ((*i)->Overlaps(**j, normal)) {
+ (*i)->Move(normal);
+ }
+ } else if ((*j)->IsDynamic()) {
+ (*j)->Move(normal);
+ while ((*j)->Overlaps(**i, normal)) {
+ (*j)->Move(normal);
+ }
+ } else {
+ (*i)->Revert(deltaT);
+ (*j)->Revert(deltaT);
+ }
+ collisions.push_back(Collision(*i, *j, normal));
+ }
+ }
+ }
+}
+
+void Match::HandleCollisions(float deltaT) {
+ for (vector<Collision>::const_iterator i(collisions.begin()), end(collisions.end()); i != end; ++i) {
+ i->left->Collide(*(i->right), i->normal);
+ i->right->Collide(*(i->left), -(i->normal));
+ i->left->PostCollide();
+ i->right->PostCollide();
+
+ }
+ if (!collisions.empty()) {
+ updateScore = true;
+ }
+ collisions.clear();
+}
+
+
+void Match::Render(SDL_Surface *screen) {
+ SDL_FillRect(screen, 0, SDL_MapRGB(screen->format, 0, 0, 0));
+ for (vector<Entity *>::const_iterator i(entities.begin()), end(entities.end()); i != end; ++i) {
+ (*i)->Render(screen);
+ }
+ RenderHUD(screen);
+}
+
+void Match::RenderHUD(SDL_Surface *screen) {
+ if (updateScore) {
+ UpdateScore(screen);
+ updateScore = false;
+ }
+ RenderScore(screen);
+}
+
+void Match::RenderScore(SDL_Surface *screen) {
+ SDL_Rect dest = { 2, 2, 0, 0 };
+ SDL_BlitSurface(leftScoreText, 0, screen, &dest);
+
+ dest.x = screen->w - rightScoreText->w - 2;
+ SDL_BlitSurface(rightScoreText, 0, screen, &dest);
+}
+
+void Match::UpdateScore(SDL_Surface *screen) {
+ if (!scoreFont) return;
+ if (leftScoreText) SDL_FreeSurface(leftScoreText);
+ if (rightScoreText) SDL_FreeSurface(rightScoreText);
+
+ SDL_Color color;
+ color.r = 0xFF;
+ color.g = 0xFF;
+ color.b = 0xFF;
+
+ stringstream s;
+ s << rightWall.HitCount();
+ leftScoreText = TTF_RenderUTF8_Blended(scoreFont, s.str().c_str(), color);
+
+ s.str("");
+ s << leftWall.HitCount();
+ rightScoreText = TTF_RenderUTF8_Blended(scoreFont, s.str().c_str(), color);
+}
+
+}