--- /dev/null
+/*
+ * Application.cpp
+ *
+ * Created on: Apr 8, 2012
+ * Author: holy
+ */
+
+#include "Application.h"
+
+#include "State.h"
+
+#include <cassert>
+
+namespace app {
+
+Application::Application(sdl::InitScreen *screen, State *initialState)
+: screen(screen)
+, states()
+, timer()
+, last(SDL_GetTicks()) {
+ assert(screen && "cannot create application without screen");
+ assert(initialState && "cannot create application without initial state");
+ RealPushState(initialState);
+}
+
+Application::~Application(void) {
+ PopAllStates();
+}
+
+
+State *Application::CurrentState(void) {
+ return states.top();
+}
+
+void Application::ChangeState(State *s) {
+ RealPopState();
+ RealPushState(s);
+}
+
+void Application::PushState(State *s) {
+ RealPushState(s);
+}
+
+void Application::RealPushState(State *s) {
+ states.push(s);
+ s->EnterState(this, screen->Screen());
+}
+
+void Application::PopState(void) {
+ RealPopState();
+}
+
+void Application::RealPopState(void) {
+ if (states.empty()) return;
+ states.top()->ExitState();
+ delete states.top();
+ states.pop();
+}
+
+void Application::Quit(void) {
+ PopAllStates();
+}
+
+void Application::PopAllStates(void) {
+ while (!states.empty()) {
+ RealPopState();
+ }
+}
+
+
+void Application::Run(void) {
+ while (CurrentState()) {
+ Loop();
+ }
+}
+
+void Application::Loop(void) {
+ Uint32 now(SDL_GetTicks());
+ Uint32 deltaT(now - last);
+ if (deltaT > 34) deltaT = 34;
+
+ HandleEvents();
+ UpdateWorld(deltaT);
+ Render();
+
+ last = now;
+}
+
+
+void Application::HandleEvents(void) {
+ if (!CurrentState()) return;
+ SDL_Event event;
+ while (SDL_PollEvent(&event)) {
+ switch (event.type) {
+ case SDL_QUIT:
+ PopAllStates();
+ break;
+ default:
+ CurrentState()->HandleEvent(event);
+ break;
+ }
+ }
+}
+
+void Application::UpdateWorld(Uint32 deltaT) {
+ if (!CurrentState()) return;
+ for (Uint32 i(0); i < deltaT; ++i) {
+ timer.Update(0.001);
+ CurrentState()->UpdateWorld(timer);
+ }
+}
+
+void Application::Render(void) {
+ if (!CurrentState()) return;
+ CurrentState()->Render(screen->Screen());
+ screen->Flip();
+}
+
+}
--- /dev/null
+/*
+ * Application.h
+ *
+ * Created on: Apr 8, 2012
+ * Author: holy
+ */
+
+#ifndef APP_APPLICATION_H_
+#define APP_APPLICATION_H_
+
+#include "Control.h"
+#include "Timer.h"
+#include "../sdl/InitScreen.h"
+
+#include <stack>
+#include <SDL/SDL.h>
+
+
+namespace app {
+
+class State;
+
+class Application
+: public Control {
+
+ public:
+ explicit Application(sdl::InitScreen *screen, State *initialState);
+ virtual ~Application(void);
+ private:
+ Application(const Application &);
+ Application &operator =(const Application &);
+
+ public:
+ void Run(void);
+ void Loop(void);
+
+ public:
+ virtual void ChangeState(State *);
+ virtual void PushState(State *);
+ virtual void PopState(void);
+ virtual void Quit(void);
+
+ private:
+ State *CurrentState(void);
+ void RealPushState(State *);
+ void RealPopState(void);
+ void PopAllStates(void);
+
+ private:
+ void HandleEvents(void);
+ void UpdateWorld(Uint32 deltaT);
+ void Render(void);
+
+ private:
+ sdl::InitScreen *screen;
+ std::stack<State *> states;
+ Timer timer;
+ Uint32 last;
+
+};
+
+}
+
+#endif /* APP_APPLICATION_H_ */
--- /dev/null
+/*
+ * Control.h
+ *
+ * Created on: Apr 19, 2012
+ * Author: holy
+ */
+
+#ifndef APP_CONTROL_H_
+#define APP_CONTROL_H_
+
+namespace app {
+
+class State;
+
+class Control {
+
+ public:
+ virtual ~Control(void) { };
+
+ public:
+ virtual void ChangeState(State *) = 0;
+ virtual void PushState(State *) = 0;
+ virtual void PopState(void) = 0;
+ virtual void Quit(void) = 0;
+};
+
+}
+
+#endif /* APP_CONTROL_H_ */
--- /dev/null
+/*
+ * State.h
+ *
+ * Created on: Apr 8, 2012
+ * Author: holy
+ */
+
+#ifndef APP_APPLICATIONSTATE_H_
+#define APP_APPLICATIONSTATE_H_
+
+#include <SDL/SDL.h>
+
+namespace app {
+
+class Control;
+class Timer;
+
+class State {
+
+ public:
+ virtual ~State(void) { };
+
+ public:
+ virtual void EnterState(Control *ctrl, SDL_Surface *screen) = 0;
+ virtual void ExitState(void) = 0;
+
+ virtual void HandleEvent(const SDL_Event &) = 0;
+ virtual void UpdateWorld(const Timer &) = 0;
+ virtual void Render(SDL_Surface *) = 0;
+
+};
+
+}
+
+#endif /* APP_STATE_H_ */
--- /dev/null
+/*
+ * Timer.cpp
+ *
+ * Created on: Apr 25, 2012
+ * Author: holy
+ */
+
+#include "Timer.h"
+
+namespace app {
+
+void Timer::Update(double dt) {
+ delta = dt * scale;
+ elapsed += dt;
+}
+
+double Timer::Elapsed(void) const {
+ return elapsed * delta;
+}
+
+} /* namespace app */
--- /dev/null
+/*
+ * Timer.h
+ *
+ * Created on: Apr 25, 2012
+ * Author: holy
+ */
+
+#ifndef APP_TIMER_H_
+#define APP_TIMER_H_
+
+namespace app {
+
+class Timer {
+
+ public:
+ explicit Timer(double scale = 1.0, double initialTime = 0.0)
+ : scale(scale), elapsed(initialTime), delta(0.0) { };
+
+ public:
+ void Update(double dt);
+
+ public:
+ double DeltaT(void) const { return delta; };
+ double Elapsed(void) const;
+
+ private:
+ double scale, elapsed, delta;
+
+};
+
+}
+
+#endif /* APP_TIMER_H_ */
--- /dev/null
+/*
+ * Collision.h
+ *
+ * Created on: Apr 22, 2012
+ * Author: holy
+ */
+
+#ifndef GAME_COLLISION_H_
+#define GAME_COLLISION_H_
+
+#include "Entity.h"
+
+
+namespace game {
+
+class Collision {
+
+ public:
+ Collision(Entity *left, Entity *right, const Entity::Ray &normal) : left(left), right(right), normal(normal) { };
+ ~Collision(void) { };
+
+ public:
+ Entity *left, *right;
+ Entity::Ray normal;
+
+};
+
+}
+
+#endif /* GAME_COLLISION_H_ */
--- /dev/null
+/*
+ * Entity.cpp
+ *
+ * Created on: Apr 25, 2012
+ * Author: holy
+ */
+
+#include "Entity.h"
+
+#include "../app/Timer.h"
+#include "../geometry/constants.h"
+
+#include <limits>
+
+using geometry::PI;
+using std::numeric_limits;
+
+namespace game {
+
+
+void Entity::Update(const app::Timer &timer) {
+ translation += linearVelocity * timer.DeltaT();
+ rotation += angularVelocity * timer.DeltaT();
+ if (rotation > 2.0 * PI) {
+ rotation -= 2.0 * PI;
+ } else if (rotation < -(2.0 * PI)) {
+ rotation += 2.0 * PI;
+ }
+ shape->Translate(linearVelocity * timer.DeltaT());
+ shape->Rotate(angularVelocity * timer.DeltaT());
+}
+
+bool Entity::CheckCollision(const Entity &other, Ray &ray) {
+ return shape->CheckCollision(*other.shape, ray);
+}
+
+
+Entity::Vector Entity::VelocityAt(const Vector &p) const {
+ if (angularVelocity == 0 || p == translation) return linearVelocity;
+
+ Vector v(linearVelocity);
+ Vector pRelative(p - translation);
+ v += pRelative.Rotate90() * angularVelocity;
+ return v;
+}
+
+
+void Entity::Rotate(Scalar d) {
+ rotation += d;
+ shape->Rotate(d);
+}
+
+void Entity::Translate(const Vector &d) {
+ translation += d;
+ shape->Translate(d);
+}
+
+void Entity::Accelerate(const Vector &dvl, Scalar dva) {
+ linearVelocity += dvl;
+ angularVelocity += dva;
+}
+
+
+void Entity::CollisionResponse(Entity &a, const Ray &na, Entity &b) {
+ if (a.mass == numeric_limits<Scalar>::infinity()
+ && b.mass == numeric_limits<Scalar>::infinity()) {
+ // special case: collision of two infinitely heavy entities
+ InfInfCollisionResponse(a, na, b);
+ return;
+ }
+
+ const Scalar e(1);
+
+ const Vector va(a.LinearVelocity());
+ const Vector vb(b.LinearVelocity());
+ const Scalar wa(a.AngularVelocity());
+ const Scalar wb(b.AngularVelocity());
+
+ const Vector vap(a.VelocityAt(na.Origin()));
+ const Vector vbp(b.VelocityAt(na.Origin()));
+ const Vector vab = vap - vbp;
+
+ const Vector rap90((na.Origin() - a.Origin()).Rotate90());
+ const Vector rbp90((na.Origin() - b.Origin()).Rotate90());
+
+ const Scalar ia(a.Mass());
+ const Scalar ib(b.Mass());
+
+ const Scalar rap90dotN(rap90.Dot(na.Direction()));
+ const Scalar rbp90dotN(rbp90.Dot(na.Direction()));
+
+ const Scalar j(
+ (((-(1 + e)) * vab).Dot(na.Direction()))
+ / (na.Direction().Dot(na.Direction() * ((1.0 / a.Mass()) + (1.0 / b.Mass())))
+ + ((rap90dotN * rap90dotN) / ia)
+ + ((rbp90dotN * rbp90dotN) / ib) ));
+
+ const Vector va2(va + ((j / a.Mass()) * na.Direction()));
+ const Vector vb2(vb - ((j / b.Mass()) * na.Direction()));
+ const Scalar wa2(wa + ((rap90.Dot(j * na.Direction())) / ia));
+ const Scalar wb2(wb - ((rbp90.Dot(j * na.Direction())) / ib));
+
+ a.linearVelocity = va2;
+ a.angularVelocity = wa2;
+ b.linearVelocity = vb2;
+ b.angularVelocity = wb2;
+}
+
+void Entity::InfInfCollisionResponse(Entity &a, const Ray &na, Entity &b) {
+ // If both elements are standing still or both are moving, move them away
+ // from each other. Otherwise, move the moving one.
+ if ((a.linearVelocity == Vector() && b.linearVelocity == Vector())
+ || (a.linearVelocity != Vector() && b.linearVelocity != Vector())) {
+ a.Translate(na.Direction());
+ b.Translate(-na.Direction());
+ Ray n;
+ while (a.shape->CheckCollision(*b.shape, n)) {
+ a.Translate(n.Direction());
+ b.Translate(-n.Direction());
+ }
+ } else if (a.linearVelocity == Vector()) {
+ b.Translate(-na.Direction());
+ Ray n;
+ while (b.shape->CheckCollision(*a.shape, n)) {
+ b.Translate(n.Direction());
+ }
+ } else {
+ a.Translate(na.Direction());
+ Ray n;
+ while (a.shape->CheckCollision(*b.shape, n)) {
+ a.Translate(n.Direction());
+ }
+ }
+}
+
+}
--- /dev/null
+/*
+ * Entity.h
+ *
+ * Created on: Apr 25, 2012
+ * Author: holy
+ */
+
+#ifndef GAME_ENTITY_H_
+#define GAME_ENTITY_H_
+
+#include "../shape/Shape.h"
+
+#include <SDL/SDL.h>
+
+namespace app { class Timer; }
+
+
+namespace game {
+
+class Entity {
+
+ friend std::ostream &operator <<(std::ostream &, const Entity &);
+
+ public:
+ typedef shape::Shape::Scalar Scalar;
+ typedef shape::Shape::Vector Vector;
+ typedef shape::Shape::Ray Ray;
+
+ public:
+ static void CollisionResponse(Entity &a, const Entity::Ray &na, Entity &b);
+
+ public:
+ explicit Entity(shape::Shape *s, Scalar mass = 1.0) : shape(s), mass(mass) { };
+ virtual ~Entity(void) { };
+
+ public:
+ void Update(const app::Timer &);
+ bool CheckCollision(const Entity &, Ray &);
+
+ public:
+ virtual void Collide(Entity &other, const Ray &) { };
+ virtual void Render(SDL_Surface *dest) const { };
+
+ public:
+ const Vector &Origin(void) const { return translation; };
+ const Vector &LinearVelocity(void) const { return linearVelocity; };
+ Scalar Angle(void) const { return rotation; };
+ Scalar AngularVelocity(void) const { return angularVelocity; };
+ Vector VelocityAt(const Vector &p) const;
+ const Scalar Mass(void) const { return mass; };
+
+ public:
+ void Rotate(Scalar);
+ void Translate(const Vector &);
+ void Accelerate(const Vector &linear, Scalar angular = 0);
+
+ private:
+ static void InfInfCollisionResponse(Entity &a, const Entity::Ray &na, Entity &b);
+
+ private:
+ shape::Shape *shape;
+ Vector translation, linearVelocity;
+ Scalar rotation, angularVelocity, mass;
+
+};
+
+
+inline std::ostream &operator <<(std::ostream &out, const Entity &e) {
+ return out << *e.shape;
+}
+
+}
+
+#endif /* GAME_ENTITY_H_ */
--- /dev/null
+/*
+ * Ray2D.h
+ *
+ * Created on: Apr 25, 2012
+ * Author: holy
+ */
+
+#ifndef GEOMETRY_RAY2D_H_
+#define GEOMETRY_RAY2D_H_
+
+#include "Vector2D.h"
+
+namespace geometry {
+
+template<typename Scalar>
+class Ray2D {
+
+ public:
+ explicit Ray2D(const Vector2D<Scalar> &directionUnit = Vector2D<Scalar>(), const Vector2D<Scalar> &origin = Vector2D<Scalar>())
+ : direction(directionUnit), origin(origin) { };
+
+ public:
+ Vector2D<Scalar> &Direction(void) { return direction; };
+ Vector2D<Scalar> &Origin(void) { return origin; };
+ const Vector2D<Scalar> &Direction(void) const { return direction; };
+ const Vector2D<Scalar> &Origin(void) const { return origin; };
+
+ private:
+ Vector2D<Scalar> direction, origin;
+
+};
+
+}
+
+#endif /* GEOMETRY_RAY2D_H_ */
--- /dev/null
+/*
+ * Vector.h
+ *
+ * Created on: Apr 23, 2012
+ * Author: holy
+ */
+
+#ifndef GEOMETRY_VECTOR2D_H_
+#define GEOMETRY_VECTOR2D_H_
+
+#include <cmath>
+#include <ostream>
+
+
+namespace geometry {
+
+template<typename Scalar>
+class Vector2D {
+
+ public:
+ Vector2D(void) : x(), y() { };
+ Vector2D(Scalar x, Scalar y) : x(x), y(y) { };
+
+ public:
+ Scalar X(void) const { return x; };
+ Scalar Y(void) const { return y; };
+
+ public:
+ Scalar Dot(const Vector2D<Scalar> &o) const { return (X() * o.X()) + (Y() * o.Y()); };
+ Scalar LengthSquared(void) const { return Dot(*this); };
+ Scalar Length(void) const { return std::sqrt(LengthSquared()); };
+
+ public:
+ Vector2D<Scalar> &Unify(void) {
+ if (LengthSquared() == Scalar()) return *this;
+ *this /= Length();
+ return *this;
+ };
+ Vector2D<Scalar> Unit(void) const {
+ if (LengthSquared() == Scalar()) return *this;
+ return *this / Length();
+ };
+ Vector2D<Scalar> &Reflect(const Vector2D<Scalar> &normal);
+ Vector2D<Scalar> &Rotate90(void) {
+ return *this = Vector2D<Scalar>(-Y(), X());
+ };
+ Vector2D<Scalar> &Rotate(Scalar by) {
+ Scalar sine(std::sin(by)), cosine(std::cos(by));
+ return *this = Vector2D<Scalar>(X() * cosine - Y() * sine, X() * sine + y * cosine);
+ };
+
+ public:
+ Vector2D<Scalar> &operator +=(const Vector2D<Scalar> &o) {
+ x += o.X();
+ y += o.Y();
+ return *this;
+ };
+ Vector2D<Scalar> &operator -=(const Vector2D<Scalar> &o) {
+ x -= o.X();
+ y -= o.Y();
+ return *this;
+ };
+ template<typename T>
+ Vector2D<Scalar> &operator +=(T s) { x += s; y += s; return *this; };
+ template<typename T>
+ Vector2D<Scalar> &operator -=(T s) { x -= s; y -= s; return *this; };
+ template<typename T>
+ Vector2D<Scalar> &operator *=(T s) { x *= s; y *= s; return *this; };
+ template<typename T>
+ Vector2D<Scalar> &operator /=(T s) { x /= s; y /= s; return *this; };
+
+ private:
+ Scalar x, y;
+
+};
+
+template<typename Scalar>
+inline Vector2D<Scalar> &Vector2D<Scalar>::Reflect(const Vector2D<Scalar> &normal) {
+ Scalar doubleDot(2 * Dot(normal));
+ x -= doubleDot * normal.X();
+ y -= doubleDot * normal.Y();
+ return *this;
+};
+
+
+template<typename Scalar>
+inline bool operator ==(const Vector2D<Scalar> &lhs, const Vector2D<Scalar> &rhs) {
+ return lhs.X() == rhs.X() && lhs.Y() == rhs.Y();
+};
+
+template<typename Scalar>
+inline bool operator !=(const Vector2D<Scalar> &lhs, const Vector2D<Scalar> &rhs) {
+ return !(lhs == rhs);
+};
+
+template<typename Scalar>
+inline Vector2D<Scalar> operator +(const Vector2D<Scalar> &v) {
+ return v;
+};
+template<typename Scalar>
+inline Vector2D<Scalar> operator -(const Vector2D<Scalar> &v) {
+ return Vector2D<Scalar>(-v.X(), -v.Y());
+};
+
+template<typename Scalar>
+inline Vector2D<Scalar> operator +(const Vector2D<Scalar> &lhs, const Vector2D<Scalar> &rhs) {
+ Vector2D<Scalar> temp(lhs);
+ temp += rhs;
+ return temp;
+};
+template<typename Scalar>
+inline Vector2D<Scalar> operator -(const Vector2D<Scalar> &lhs, const Vector2D<Scalar> &rhs) {
+ Vector2D<Scalar> temp(lhs);
+ temp -= rhs;
+ return temp;
+};
+
+template<typename VScalar, typename SScalar>
+inline Vector2D<VScalar> operator +(const Vector2D<VScalar> &v, SScalar s) {
+ Vector2D<VScalar> temp(v);
+ temp += s;
+ return temp;
+};
+template<typename VScalar, typename SScalar>
+inline Vector2D<VScalar> operator -(const Vector2D<VScalar> &v, SScalar s) {
+ Vector2D<VScalar> temp(v);
+ temp -= s;
+ return temp;
+};
+
+template<typename VScalar, typename SScalar>
+inline Vector2D<VScalar> operator +(SScalar s, const Vector2D<VScalar> &v) {
+ Vector2D<VScalar> temp(v);
+ temp += s;
+ return temp;
+};
+template<typename VScalar, typename SScalar>
+inline Vector2D<VScalar> operator -(SScalar s, const Vector2D<VScalar> &v) {
+ Vector2D<VScalar> temp(v);
+ temp -= s;
+ return temp;
+};
+
+template<typename VScalar, typename SScalar>
+inline Vector2D<VScalar> operator *(const Vector2D<VScalar> &v, SScalar s) {
+ Vector2D<VScalar> temp(v);
+ temp *= s;
+ return temp;
+};
+template<typename VScalar, typename SScalar>
+inline Vector2D<VScalar> operator *(SScalar s, const Vector2D<VScalar> &v) {
+ Vector2D<VScalar> temp(v);
+ temp *= s;
+ return temp;
+};
+template<typename VScalar, typename SScalar>
+inline Vector2D<VScalar> operator /(const Vector2D<VScalar> &v, SScalar s) {
+ Vector2D<VScalar> temp(v);
+ temp /= s;
+ return temp;
+};
+template<typename VScalar, typename SScalar>
+inline Vector2D<VScalar> operator /(SScalar s, const Vector2D<VScalar> &v) {
+ Vector2D<VScalar> temp(v);
+ temp /= s;
+ return temp;
+};
+
+
+template<typename Scalar>
+std::ostream &operator <<(std::ostream &out, const Vector2D<Scalar> &v) {
+ return out << '<' << v.X() << '|' << v.Y() << '>';
+}
+
+}
+
+#endif /* GEOMETRY_VECTOR2D_H_ */
--- /dev/null
+/*
+ * constants.h
+ *
+ * Created on: Apr 26, 2012
+ * Author: holy
+ */
+
+#ifndef GEOMETRY_CONSTANTS_H_
+#define GEOMETRY_CONSTANTS_H_
+
+#include <cmath>
+
+
+namespace geometry {
+
+const double PI(std::atan(1.0) * 4.0);
+
+}
+
+
+#endif /* GEOMETRY_CONSTANTS_H_ */
--- /dev/null
+/*
+ * Ball.cpp
+ *
+ * Created on: Apr 9, 2012
+ * Author: holy
+ */
+
+#include "Ball.h"
+
+#include "Paddle.h"
+#include "../geometry/constants.h"
+
+#include <cmath>
+#include <SDL/SDL_gfxPrimitives.h>
+
+using game::Entity;
+using geometry::PI;
+
+
+namespace pong {
+
+Ball::Ball(Scalar r)
+: Entity(&shape, 4 * PI * r * r * r / 3)
+, shape(r) {
+
+}
+
+
+void Ball::Render(SDL_Surface *screen) const {
+ circleRGBA(screen, shape.Center().X(), shape.Center().Y(), shape.Radius(), 0xFF, 0xFF, 0xFF, 0xFF);
+ Vector angle(Vector(0, 1).Rotate(Angle()) * shape.Radius() + Origin());
+ lineRGBA(screen, shape.Center().X(), shape.Center().Y(), angle.X(), angle.Y(), 0xFF, 0xFF, 0xFF, 0xFF);
+}
+
+}
--- /dev/null
+/*
+ * Ball.h
+ *
+ * Created on: Apr 9, 2012
+ * Author: holy
+ */
+
+#ifndef PONG_BALL_H_
+#define PONG_BALL_H_
+
+#include "../game/Entity.h"
+#include "../shape/Circle.h"
+
+
+namespace pong {
+
+class Ball
+: public game::Entity {
+
+ public:
+ explicit Ball(Scalar radius);
+ virtual ~Ball(void) { };
+
+ public:
+ virtual void Render(SDL_Surface *dest) const;
+
+ private:
+ shape::Circle shape;
+
+};
+
+}
+
+#endif /* PONG_BALL_H_ */
--- /dev/null
+/*
+ * CountingWall.cpp
+ *
+ * Created on: Apr 17, 2012
+ * Author: holy
+ */
+
+#include "CountingWall.h"
+
+#include <limits>
+
+using game::Entity;
+
+
+namespace pong {
+
+CountingWall::CountingWall(Scalar width, Scalar height)
+: Entity(&shape, std::numeric_limits<Scalar>::infinity())
+, shape(width, height)
+, count(0) {
+
+}
+
+CountingWall::~CountingWall(void) {
+
+}
+
+
+void CountingWall::Collide(Entity &, const Ray &) {
+ ++count;
+}
+
+void CountingWall::Render(SDL_Surface *dest) const {
+
+}
+
+}
--- /dev/null
+/*
+ * CountingWall.h
+ *
+ * Created on: Apr 17, 2012
+ * Author: holy
+ */
+
+#ifndef PONG_COUNTINGWALL_H_
+#define PONG_COUNTINGWALL_H_
+
+#include "../game/Entity.h"
+#include "../shape/AABB.h"
+
+#include <SDL/SDL.h>
+
+namespace pong {
+
+class CountingWall
+: public game::Entity {
+
+ public:
+ CountingWall(Scalar width, Scalar height);
+ virtual ~CountingWall(void);
+
+ public:
+ int HitCount(void) { return count; };
+
+ public:
+ virtual void Collide(Entity &other, const Ray &);
+ virtual void Render(SDL_Surface *dest) const;
+
+ private:
+ shape::AABB shape;
+ int count;
+
+};
+
+}
+
+#endif /* PONG_COUNTINGWALL_H_ */
--- /dev/null
+/*
+ * 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);
+}
+
+}
--- /dev/null
+/*
+ * Match.h
+ *
+ * Created on: Apr 9, 2012
+ * Author: holy
+ */
+
+#ifndef PONG_MATCH_H_
+#define PONG_MATCH_H_
+
+#include "Ball.h"
+#include "CountingWall.h"
+#include "Paddle.h"
+#include "../app/State.h"
+#include "../game/Collision.h"
+#include "../game/Entity.h"
+
+#include <utility>
+#include <vector>
+#include <SDL/SDL_ttf.h>
+
+
+namespace pong {
+
+class Match
+: public app::State {
+
+ public:
+ Match(void);
+ virtual ~Match(void);
+
+ public:
+ virtual void EnterState(app::Control *ctrl, SDL_Surface *screen);
+ virtual void ExitState(void);
+
+ virtual void HandleEvent(const SDL_Event &);
+ virtual void UpdateWorld(const app::Timer &);
+ virtual void Render(SDL_Surface *);
+
+ private:
+ void UpdateEntities(const app::Timer &);
+ void CheckCollisions(const app::Timer &);
+ void CheckWorldCollisions(const app::Timer &);
+ void HandleCollisions(const app::Timer &);
+ void UpdateScore(SDL_Surface *);
+ void RenderHUD(SDL_Surface *);
+ void RenderScore(SDL_Surface *);
+
+ private:
+ app::Control *ctrl;
+ TTF_Font *scoreFont;
+ SDL_Surface *leftScoreText, *rightScoreText;
+ Sint32 paddleSpeed;
+ Uint32 worldWidth, worldHeight;
+ Ball ball, secondBall, thirdBall;
+ Paddle leftPaddle, rightPaddle;
+ CountingWall topWall, bottomWall, leftWall, rightWall;
+ std::vector<game::Entity *> entities;
+ std::vector<game::Collision> collisions;
+ bool updateScore;
+
+};
+
+}
+
+#endif /* PONG_MATCH_H_ */
--- /dev/null
+/*
+ * Paddle.cpp
+ *
+ * Created on: Apr 10, 2012
+ * Author: holy
+ */
+
+#include "Paddle.h"
+
+#include "Ball.h"
+
+#include <limits>
+
+
+namespace pong {
+
+Paddle::Paddle(Scalar width, Scalar height)
+: Entity(&shape, std::numeric_limits<Scalar>::infinity())
+, shape(width, height) {
+
+}
+
+
+void Paddle::Collide(Entity &other, const Ray &) {
+ if (dynamic_cast<Ball *>(&other)) {
+ Vector distance(other.Origin() - Origin());
+ other.Accelerate(distance.Unit() * 5);
+ }
+}
+
+void Paddle::Render(SDL_Surface *screen) const {
+ SDL_Rect destRect;
+ destRect.x = shape.Left();
+ destRect.y = shape.Top();
+ destRect.w = shape.Width();
+ destRect.h = shape.Height();
+ SDL_FillRect(screen, &destRect, SDL_MapRGB(screen->format, 0xFF, 0xFF, 0xFF));
+}
+
+
+void Paddle::SetMovementSpeed(Vector s) {
+// Vector d(s - movementSpeed);
+ movementSpeed = s;
+// Accelerate(d);
+}
+
+
+void Paddle::StartMovingUp(void) {
+ Accelerate(-movementSpeed);
+}
+
+void Paddle::StopMovingUp(void) {
+ Accelerate(movementSpeed);
+}
+
+void Paddle::StartMovingDown(void) {
+ Accelerate(movementSpeed);
+}
+
+void Paddle::StopMovingDown(void) {
+ Accelerate(-movementSpeed);
+}
+
+}
--- /dev/null
+/*
+ * Paddle.h
+ *
+ * Created on: Apr 10, 2012
+ * Author: holy
+ */
+
+#ifndef PONG_PADDLE_H_
+#define PONG_PADDLE_H_
+
+#include "../game/Entity.h"
+#include "../shape/AABB.h"
+
+
+namespace pong {
+
+class Paddle
+: public game::Entity {
+
+ public:
+ Paddle(Scalar width, Scalar height);
+ virtual ~Paddle(void) { };
+
+ public:
+ virtual void Collide(Entity &other, const Ray &);
+ virtual void Render(SDL_Surface *dest) const;
+
+ public:
+ void SetMovementSpeed(Vector);
+
+ void StartMovingUp(void);
+ void StopMovingUp(void);
+ void StartMovingDown(void);
+ void StopMovingDown(void);
+
+ private:
+ shape::AABB shape;
+ Vector movementSpeed;
+
+};
+
+}
+
+#endif /* PONG_PADDLE_H_ */
--- /dev/null
+//============================================================================
+// Name : sdl-test8.cpp
+// Author : HolySmoke
+// Version : .3
+// Copyright : MINE, ALL MINE!
+// Description : Some pong crap supposed to have somewhat realistic physics.
+//============================================================================
+
+#include "app/Application.h"
+#include "pong/Match.h"
+#include "sdl/InitScreen.h"
+#include "sdl/InitSDL.h"
+#include "sdl/InitTTF.h"
+
+int main(int argc, char *argv[]) {
+ const int width(800);
+ const int height(480);
+
+ sdl::InitSDL initSDL;
+ sdl::InitTTF initTTF;
+ sdl::InitScreen initScreen(width, height);
+
+ app::Application a(&initScreen, new pong::Match);
+ a.Run();
+ return 0;
+}
--- /dev/null
+/*
+ * InitSDL.cpp
+ *
+ * Created on: Apr 22, 2012
+ * Author: holy
+ */
+
+#include "InitSDL.h"
+
+#include <stdexcept>
+
+using std::runtime_error;
+
+
+namespace sdl {
+
+InitSDL::InitSDL(Uint32 flags) {
+ if (SDL_Init(flags) != 0) {
+ throw runtime_error("failed to initialize SDL");
+ }
+}
+
+InitSDL::~InitSDL(void) {
+ SDL_Quit();
+}
+
+}
--- /dev/null
+/*
+ * InitSDL.h
+ *
+ * Created on: Apr 22, 2012
+ * Author: holy
+ */
+
+#ifndef SDL_INITSDL_H_
+#define SDL_INITSDL_H_
+
+#include <SDL/SDL.h>
+
+
+namespace sdl {
+
+class InitSDL {
+
+ public:
+ explicit InitSDL(Uint32 flags = SDL_INIT_EVERYTHING);
+ virtual ~InitSDL(void);
+ private:
+ InitSDL(const InitSDL &);
+ InitSDL &operator =(const InitSDL &);
+
+};
+
+}
+
+#endif /* SDL_INITSDL_H_ */
--- /dev/null
+/*
+ * InitScreen.cpp
+ *
+ * Created on: Apr 22, 2012
+ * Author: holy
+ */
+
+#include "InitScreen.h"
+
+#include <stdexcept>
+
+using std::runtime_error;
+
+
+namespace sdl {
+
+InitScreen::InitScreen(int width, int height, int bpp, Sint32 flags)
+: screen(SDL_SetVideoMode(width, height, bpp, flags)) {
+ if (!screen) {
+ throw runtime_error("failed to open screen");
+ }
+}
+
+InitScreen::~InitScreen(void) {
+
+}
+
+}
--- /dev/null
+/*
+ * InitScreen.h
+ *
+ * Created on: Apr 22, 2012
+ * Author: holy
+ */
+
+#ifndef SDL_INITSCREEN_H_
+#define SDL_INITSCREEN_H_
+
+#include <SDL/SDL.h>
+
+namespace sdl {
+
+class InitScreen {
+
+ public:
+ InitScreen(int width, int height, int bpp = 32, Sint32 flags = SDL_HWSURFACE | SDL_DOUBLEBUF);
+ virtual ~InitScreen(void);
+ private:
+ InitScreen(const InitScreen &);
+ InitScreen &operator =(const InitScreen &);
+
+ public:
+ SDL_Surface *Screen(void) { return screen; };
+ const SDL_Surface *Screen(void) const { return screen; };
+
+ void Flip(void) { SDL_Flip(screen); };
+
+ private:
+ SDL_Surface *screen;
+
+};
+
+}
+
+#endif /* SDL_INITSCREEN_H_ */
--- /dev/null
+/*
+ * InitTTF.cpp
+ *
+ * Created on: Apr 22, 2012
+ * Author: holy
+ */
+
+#include "InitTTF.h"
+
+#include <stdexcept>
+#include <SDL/SDL_ttf.h>
+
+using std::runtime_error;
+
+
+namespace sdl {
+
+InitTTF::InitTTF(void) {
+ if (TTF_Init() != 0) {
+ throw runtime_error("failed to initialize SDL TTF");
+ }
+}
+
+InitTTF::~InitTTF(void) {
+ TTF_Quit();
+}
+
+}
--- /dev/null
+/*
+ * InitTTF.h
+ *
+ * Created on: Apr 22, 2012
+ * Author: holy
+ */
+
+#ifndef SDL_INITTTF_H_
+#define SDL_INITTTF_H_
+
+namespace sdl {
+
+class InitTTF {
+
+ public:
+ InitTTF(void);
+ virtual ~InitTTF(void);
+ private:
+ InitTTF(const InitTTF &);
+ InitTTF &operator =(const InitTTF &);
+
+};
+
+}
+
+#endif /* SDL_INITTTF_H_ */
--- /dev/null
+/*
+ * AABB.cpp
+ *
+ * Created on: Apr 30, 2012
+ * Author: holy
+ */
+
+#include "AABB.h"
+
+#include "Circle.h"
+
+namespace shape {
+
+void AABB::Translate(const Vector &delta) {
+ leftTop += delta;
+ rightBottom += delta;
+}
+
+void AABB::Rotate(Scalar delta) {
+
+}
+
+
+bool AABB::CheckCollision(const Shape &other, Ray &na) const {
+ if (other.CheckCollision(*this, na)) {
+ na.Direction() *= -1;
+ return true;
+ } else {
+ return false;
+ }
+}
+
+bool AABB::CheckCollision(const AABB &other, Ray &na) const {
+ if (Bottom() <= other.Top()) return false;
+ if (other.Bottom() <= Top()) return false;
+ if (Right() <= other.Left()) return false;
+ if (other.Right() <= Left()) return false;
+
+ if (Bottom() <= other.Top() || other.Bottom() <= Top()) {
+ if (Left() < other.Left()) {
+ na.Origin() = Vector(((Top() + Bottom()) / 2 + (other.Top() + other.Bottom()) / 2) / 2, Right());
+ na.Direction() = Vector(-1, 0);
+ } else {
+ na.Origin() = Vector(((Top() + Bottom()) / 2 + (other.Top() + other.Bottom()) / 2) / 2, Left());
+ na.Direction() = Vector(1, 0);
+ }
+ } else {
+ if (Top() < other.Top()) {
+ na.Origin() = Vector(Bottom(), ((Left() + Right()) / 2 + (other.Left() + other.Right()) / 2) / 2);
+ na.Direction() = Vector(0, -1);
+ } else {
+ na.Origin() = Vector(Top(), ((Left() + Right()) / 2 + (other.Left() + other.Right()) / 2) / 2);
+ na.Direction() = Vector(0, 1);
+ }
+ }
+ return true;
+}
+
+bool AABB::CheckCollision(const Circle &other, Ray &na) const {
+ if (other.CheckCollision(*this, na)) {
+ na.Direction() *= -1;
+ return true;
+ } else {
+ return false;
+ }
+}
+
+
+std::ostream &AABB::Write(std::ostream &out) const {
+ return out << "AABB(" << Width() << 'x' << Height() << ", " << Center() << ')';
+}
+
+}
--- /dev/null
+/*
+ * AABB.h
+ *
+ * Created on: Apr 30, 2012
+ * Author: holy
+ */
+
+#ifndef SHAPE_AABB_H_
+#define SHAPE_AABB_H_
+
+#include "Shape.h"
+
+namespace shape {
+
+class AABB
+: public Shape {
+
+ public:
+ AABB(void) { };
+ AABB(Scalar width, Scalar height) : leftTop(-width/2, -height/2), rightBottom(width/2, height/2) { };
+ virtual ~AABB(void) { };
+
+ public:
+ Scalar Left(void) const { return leftTop.X(); };
+ Scalar Top(void) const { return leftTop.Y(); };
+ Scalar Right(void) const { return rightBottom.X(); };
+ Scalar Bottom(void) const { return rightBottom.Y(); };
+
+ Vector Center(void) const { return leftTop + (rightBottom - leftTop) / 2; };
+ Scalar Width(void) const { return Right() - Left(); };
+ Scalar Height(void) const { return Bottom() - Top(); };
+
+ public:
+ virtual void Translate(const Vector &delta);
+ virtual void Rotate(Scalar delta);
+
+ public:
+ virtual bool CheckCollision(const Shape &, Ray &) const;
+ virtual bool CheckCollision(const AABB &, Ray &) const;
+ virtual bool CheckCollision(const Circle &, Ray &) const;
+
+ public:
+ virtual std::ostream &Write(std::ostream &) const;
+
+ private:
+ Vector leftTop, rightBottom;
+
+};
+
+}
+
+#endif /* SHAPE_AABB_H_ */
--- /dev/null
+/*
+ * Circle.cpp
+ *
+ * Created on: Apr 29, 2012
+ * Author: holy
+ */
+
+#include "Circle.h"
+
+#include "AABB.h"
+
+namespace shape {
+
+void Circle::Translate(const Vector &delta) {
+ center += delta;
+}
+
+void Circle::Rotate(Scalar delta) {
+
+}
+
+
+bool Circle::CheckCollision(const Shape &other, Ray &na) const {
+ if (other.CheckCollision(*this, na)) {
+ na.Direction() *= -1;
+ return true;
+ } else {
+ return false;
+ }
+}
+
+bool Circle::CheckCollision(const AABB &other, Ray &na) const {
+ int xZone(
+ center.X() < other.Left() ? 0 : (
+ other.Right() < center.X() ? 2 : 1));
+ int yZone(
+ center.Y() < other.Top() ? 0 : (
+ other.Bottom() < center.Y() ? 2 : 1));
+ int zone(xZone + 3 * yZone);
+
+ if (zone == 4) {
+ na.Origin() = center;
+ na.Direction() = (center - other.Center()).Unit();
+ return true;
+ }
+
+ if (zone % 2) {
+ if (xZone == 1) { // vertical
+ if (Bottom() < other.Top()) return false;
+ if (other.Bottom() < Top()) return false;
+
+ if (Bottom() < other.Bottom()) {
+ na.Origin() = Vector(center.X(), Bottom());
+ na.Direction() = Vector(0, -1);
+ } else {
+ na.Origin() = Vector(center.X(), Top());
+ na.Direction() = Vector(0, 1);
+ }
+
+ return true;
+ } else {
+ if (Right() < other.Left()) return false;
+ if (other.Right() < Left()) return false;
+
+ if (Left() < other.Left()) {
+ na.Origin() = Vector(Left(), center.Y());
+ na.Direction() = Vector(-1, 0);
+ } else {
+ na.Origin() = Vector(Right(), center.Y());
+ na.Direction() = Vector(1, 0);
+ }
+
+ return true;
+ }
+ } else {
+ Vector near(
+ yZone ? other.Right() : other.Left(),
+ xZone ? other.Bottom() : other.Top());
+ Vector distance(Center() - near);
+ Scalar distanceSquared(distance.LengthSquared());
+ if (distanceSquared < (Radius() * Radius())) {
+ na.Origin() = near;
+ na.Direction() = distance.Unit();
+ return true;
+ } else {
+ return false;
+ }
+ }
+}
+
+bool Circle::CheckCollision(const Circle &other, Ray &na) const {
+ const Vector distance(center - other.center);
+ const Scalar distanceSquared(distance.LengthSquared());
+ const Scalar radii(radius + other.radius);
+
+ if (distanceSquared < (radii * radii)) {
+ na.Direction() = distance.Unit();
+ na.Origin() = center + (na.Direction() * radius);
+ return true;
+ } else {
+ return false;
+ }
+}
+
+
+std::ostream &Circle::Write(std::ostream &out) const {
+ return out << "Circle(" << Radius() << ", " << Center() << ')';
+}
+
+}
--- /dev/null
+/*
+ * Circle.h
+ *
+ * Created on: Apr 29, 2012
+ * Author: holy
+ */
+
+#ifndef SHAPE_CIRCLE_H_
+#define SHAPE_CIRCLE_H_
+
+#include "Shape.h"
+
+namespace shape {
+
+class Circle
+: public Shape {
+
+ public:
+ Circle(void) { };
+ explicit Circle(Scalar r, Vector pos = Vector()) : center(pos), radius(r) { };
+ virtual ~Circle(void) { };
+
+ public:
+ const Vector &Center(void) const { return center; };
+ Scalar Radius(void) const { return radius; };
+
+ Scalar Left(void) const { return center.X() - radius; };
+ Scalar Top(void) const { return center.Y() - radius; };
+ Scalar Right(void) const { return center.X() + radius; };
+ Scalar Bottom(void) const { return center.Y() + radius; };
+
+ public:
+ virtual void Translate(const Vector &delta);
+ virtual void Rotate(Scalar delta);
+
+ public:
+ virtual bool CheckCollision(const Shape &, Ray &) const;
+ virtual bool CheckCollision(const AABB &, Ray &) const;
+ virtual bool CheckCollision(const Circle &, Ray &) const;
+
+ public:
+ virtual std::ostream &Write(std::ostream &) const;
+
+ private:
+ Vector center;
+ Scalar radius;
+
+};
+
+}
+
+#endif /* SHAPE_CIRCLE_H_ */
--- /dev/null
+/*
+ * Shape.h
+ *
+ * Created on: Apr 29, 2012
+ * Author: holy
+ */
+
+#ifndef SHAPE_SHAPE_H_
+#define SHAPE_SHAPE_H_
+
+#include "../geometry/Ray2D.h"
+#include "../geometry/Vector2D.h"
+
+#include <ostream>
+
+
+namespace shape {
+
+class AABB;
+class Circle;
+
+class Shape {
+
+ public:
+ typedef float Scalar;
+ typedef geometry::Vector2D<Scalar> Vector;
+ typedef geometry::Ray2D<Scalar> Ray;
+
+ public:
+ virtual ~Shape(void) { };
+
+ public:
+ virtual void Translate(const Vector &delta) = 0;
+ virtual void Rotate(Scalar delta) = 0;
+
+ public:
+ virtual bool CheckCollision(const Shape &, Ray &) const = 0;
+ virtual bool CheckCollision(const AABB &, Ray &) const = 0;
+ virtual bool CheckCollision(const Circle &, Ray &) const = 0;
+
+ public:
+ virtual std::ostream &Write(std::ostream &) const = 0;
+
+};
+
+
+inline std::ostream &operator <<(std::ostream &out, const Shape &s) {
+ return s.Write(out);
+};
+
+}
+
+#endif /* SHAPE_SHAPE_H_ */