]> git.localhorst.tv Git - sdl-test8.git/blobdiff - src/pong/Match.cpp
added collision engine, more or less stole gameplay from sdl-test7
[sdl-test8.git] / src / pong / Match.cpp
diff --git a/src/pong/Match.cpp b/src/pong/Match.cpp
new file mode 100644 (file)
index 0000000..5754b36
--- /dev/null
@@ -0,0 +1,213 @@
+/*
+ * 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 app::Timer;
+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)
+, thirdBall(5)
+, leftPaddle(10, 100)
+, rightPaddle(10, 100)
+, topWall(800, 10)
+, bottomWall(800, 10)
+, leftWall(10, 480)
+, rightWall(10, 480)
+, entities()
+, collisions()
+, updateScore(true) {
+
+       if (!scoreFont) {
+               throw runtime_error("failed to load score font");
+       }
+
+       ball.Translate(Entity::Vector(400, 240));
+       ball.Accelerate(Entity::Vector(180, 180));
+//     ball.SetMaxVelocity(500.0f);
+
+       secondBall.Translate(Entity::Vector(300, 240));
+       secondBall.Accelerate(Entity::Vector(-50, -50), 1);
+//     secondBall.SetMaxVelocity(600.0f);
+
+       thirdBall.Translate(Entity::Vector(200, 440));
+       thirdBall.Accelerate(Entity::Vector(60, 40));
+
+       leftPaddle.Translate(Entity::Vector(5, 200));
+       rightPaddle.Translate(Entity::Vector(795, 280));
+
+       leftPaddle.SetMovementSpeed(Entity::Vector(0, paddleSpeed));
+       rightPaddle.SetMovementSpeed(Entity::Vector(0, paddleSpeed));
+
+       topWall.Translate(Entity::Vector(400, -5));
+       rightWall.Translate(Entity::Vector(805, 240));
+       bottomWall.Translate(Entity::Vector(400, 485));
+       leftWall.Translate(Entity::Vector(-5, 240));
+
+       entities.reserve(9);
+       entities.push_back(&ball);
+       entities.push_back(&secondBall);
+       entities.push_back(&thirdBall);
+       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(const Timer &timer) {
+       UpdateEntities(timer);
+       CheckCollisions(timer);
+       HandleCollisions(timer);
+}
+
+void Match::UpdateEntities(const Timer &timer) {
+       for (vector<Entity *>::const_iterator i(entities.begin()), end(entities.end()); i != end; ++i) {
+               (*i)->Update(timer);
+       }
+}
+
+void Match::CheckCollisions(const Timer &timer) {
+       Entity::Ray 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)->CheckCollision(**j, normal)) {
+                               collisions.push_back(Collision(*i, *j, normal));
+                       }
+               }
+       }
+}
+
+void Match::HandleCollisions(const Timer &timer) {
+       for (vector<Collision>::const_iterator i(collisions.begin()), end(collisions.end()); i != end; ++i) {
+               Entity::CollisionResponse(*(i->left), i->normal, *(i->right));
+       }
+       // TODO: resolve collisions of static objects
+       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);
+       }
+       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);
+}
+
+}