From: Daniel Karbach Date: Wed, 25 Apr 2012 19:00:27 +0000 (+0000) Subject: imported current version X-Git-Url: http://git.localhorst.tv/?p=sdl-test7.git;a=commitdiff_plain;h=d6f654935eaa4994e95ce71740e30f917c29e7c3 imported current version --- d6f654935eaa4994e95ce71740e30f917c29e7c3 diff --git a/data/font/Magra-Regular.ttf b/data/font/Magra-Regular.ttf new file mode 100644 index 0000000..6e252b0 Binary files /dev/null and b/data/font/Magra-Regular.ttf differ diff --git a/src/app/Application.cpp b/src/app/Application.cpp new file mode 100644 index 0000000..5b1b359 --- /dev/null +++ b/src/app/Application.cpp @@ -0,0 +1,117 @@ +/* + * Application.cpp + * + * Created on: Apr 8, 2012 + * Author: holy + */ + +#include "Application.h" + +#include "State.h" + +#include + +namespace app { + +Application::Application(sdl::InitScreen *screen, State *initialState) +: screen(screen) +, states() +, 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) { + CurrentState()->UpdateWorld(0.001f); + } +} + +void Application::Render(void) { + if (!CurrentState()) return; + CurrentState()->Render(screen->Screen()); + screen->Flip(); +} + +} diff --git a/src/app/Application.h b/src/app/Application.h new file mode 100644 index 0000000..a8a87c8 --- /dev/null +++ b/src/app/Application.h @@ -0,0 +1,62 @@ +/* + * Application.h + * + * Created on: Apr 8, 2012 + * Author: holy + */ + +#ifndef APP_APPLICATION_H_ +#define APP_APPLICATION_H_ + +#include "Control.h" +#include "../sdl/InitScreen.h" + +#include +#include + + +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 states; + Uint32 last; + +}; + +} + +#endif /* APP_APPLICATION_H_ */ diff --git a/src/app/Control.h b/src/app/Control.h new file mode 100644 index 0000000..b6cd742 --- /dev/null +++ b/src/app/Control.h @@ -0,0 +1,29 @@ +/* + * 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_ */ diff --git a/src/app/State.h b/src/app/State.h new file mode 100644 index 0000000..1c93eeb --- /dev/null +++ b/src/app/State.h @@ -0,0 +1,34 @@ +/* + * State.h + * + * Created on: Apr 8, 2012 + * Author: holy + */ + +#ifndef APP_APPLICATIONSTATE_H_ +#define APP_APPLICATIONSTATE_H_ + +#include + +namespace app { + +class Control; + +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(float deltaT) = 0; + virtual void Render(SDL_Surface *) = 0; + +}; + +} + +#endif /* APP_STATE_H_ */ diff --git a/src/game/Collision.h b/src/game/Collision.h new file mode 100644 index 0000000..2da65a7 --- /dev/null +++ b/src/game/Collision.h @@ -0,0 +1,30 @@ +/* + * 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::Vector &normal) : left(left), right(right), normal(normal) { }; + ~Collision(void) { }; + + public: + Entity *left, *right; + Entity::Vector normal; + +}; + +} + +#endif /* GAME_COLLISION_H_ */ diff --git a/src/game/Entity.cpp b/src/game/Entity.cpp new file mode 100644 index 0000000..d7f0329 --- /dev/null +++ b/src/game/Entity.cpp @@ -0,0 +1,120 @@ +/* + * Entity.cpp + * + * Created on: Apr 9, 2012 + * Author: holy + */ + +#include "Entity.h" + +#include + +#include +using namespace std; + +using geometry::Shape; +using std::numeric_limits; + + +namespace game { + +Entity::Entity(Shape *shape) +: bounds(shape) +, position() +, velocity() +, nextVelocity() +, maxVelocitySquared(numeric_limits::infinity()) +, dynamic(true) +, updateVelocity(false) { + +} + +Entity::Entity(const Vector &position, Shape *shape) +: bounds(shape) +, position(position) +, velocity() +, nextVelocity() +, maxVelocitySquared(numeric_limits::infinity()) +, dynamic(true) +, updateVelocity(false) { + +} + +Entity::~Entity(void) { + +} + + +void Entity::Move(const Vector &delta) { + position += delta; + bounds->SetPosition(position); +} + +void Entity::SetPosition(const Vector &p) { + position = p; + bounds->SetPosition(position); +} + + +void Entity::SetVelocity(const Vector &v) { + if (updateVelocity) { + nextVelocity = v; + } else { + velocity = v; + } +} + + +Entity::Vector Entity::Center(void) const { + return bounds->Center(); +} + + +void Entity::Accelerate(Scalar factor) { + if (updateVelocity) { + Vector scaled(nextVelocity * factor); + float speedSquared(scaled.LengthSquared()); + if (speedSquared <= maxVelocitySquared) { + nextVelocity = scaled; + } + } else { + Vector scaled(velocity * factor); + float speedSquared(scaled.LengthSquared()); + if (speedSquared <= maxVelocitySquared) { + velocity = scaled; + } + } +} + +void Entity::SetMaxVelocity(Scalar max) { + maxVelocitySquared = max * max; +} + + +void Entity::Update(float deltaT) { + if (velocity.X() == Limits::quiet_NaN() || velocity.X() == -Limits::quiet_NaN()) { + cout << "NaN! " << velocity << endl; + } + position += velocity * deltaT; + bounds->SetPosition(position); +} + +void Entity::Revert(float deltaT) { + position -= velocity * deltaT; + bounds->SetPosition(position); +} + +void Entity::Collide(Entity &other, const Vector &normal) { + nextVelocity = velocity; + nextVelocity.Reflect(normal); + updateVelocity = true; +} + +void Entity::PostCollide(void) { + if (updateVelocity) { + velocity = nextVelocity; + updateVelocity = false; + } +} + +} diff --git a/src/game/Entity.h b/src/game/Entity.h new file mode 100644 index 0000000..0bd02ec --- /dev/null +++ b/src/game/Entity.h @@ -0,0 +1,76 @@ +/* + * Entity.h + * + * Created on: Apr 9, 2012 + * Author: holy + */ + +#ifndef GAME_ENTITY_H_ +#define GAME_ENTITY_H_ + +#include "../geometry/Shape.h" +#include "../geometry/Vector2D.h" + +#include +#include +#include + + +namespace game { + +class Entity { + + public: + typedef geometry::Shape::Scalar Scalar; + typedef geometry::Shape::Vector Vector; + typedef geometry::Shape::Limits Limits; + + public: + explicit Entity(geometry::Shape *); + Entity(const Vector &position, geometry::Shape *); + virtual ~Entity(void); + + public: + void Move(const Vector &d); + + void SetPosition(const Vector &); + + public: + const Vector &Position(void) const { return position; }; + Vector Center(void) const; + const Vector &Velocity() const { return velocity; }; + void SetVelocity(const Vector &); + + public: + const geometry::Shape &Bounds(void) const { return *bounds; }; + bool Overlaps(const Entity &other, Vector &normal) { + return bounds->Overlaps(*other.bounds, normal); + }; + + public: + void Update(float deltaT); + void Revert(float deltaT); + virtual void Collide(Entity &, const Vector &normal); + virtual void PostCollide(void); + virtual void Render(SDL_Surface *dest) { }; + + public: + bool IsDynamic(void) const { return dynamic; }; + bool IsStatic(void) const { return !dynamic; }; + void SetDynamic(void) { dynamic = true; }; + void SetStatic(void) { dynamic = false; }; + + public: + void Accelerate(float factor); + void SetMaxVelocity(float); + + private: + geometry::Shape *bounds; + Vector position, velocity, nextVelocity; + Scalar maxVelocitySquared; + bool dynamic, updateVelocity; +}; + +} + +#endif /* GAME_ENTITY_H_ */ diff --git a/src/geometry/AABB.cpp b/src/geometry/AABB.cpp new file mode 100644 index 0000000..e40c69f --- /dev/null +++ b/src/geometry/AABB.cpp @@ -0,0 +1,69 @@ +/* + * AABB.cpp + * + * Created on: Apr 20, 2012 + * Author: holy + */ + +#include "AABB.h" + +#include "Circle.h" +#include "FakeLens.h" + +namespace geometry { + +bool AABB::Overlaps(const Shape &other, Vector &normal) const { + if (other.Overlaps(*this, normal)) { + normal *= -1; + return true; + } else { + return false; + } +} + +bool AABB::Overlaps(const AABB &other, Vector &normal) 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 (HorizontalOverlap(other)) { + if (Top() < other.Top()) { + normal = Vector(0, -1); + } else { + normal = Vector(0, 1); + } + } else { + if (Left() < other.Left()) { + normal = Vector(-1, 0); + } else { + normal = Vector(1, 0); + } + } + + return true; +} + +bool AABB::Overlaps(const Circle &other, Vector &normal) const { + if (other.Overlaps(*this, normal)) { + normal *= -1; + return true; + } else { + return false; + } +} + +bool AABB::Overlaps(const FakeLens &other, Vector &normal) const { + if (other.Overlaps(*this, normal)) { + normal *= -1; + return true; + } else { + return false; + } +} + +std::ostream &AABB::Write(std::ostream &out) const { + return out << "AABB(" << Width() << 'x' << Height() << '+' << X() << '+' << Y() << ')'; +} + +} /* namespace geometry */ diff --git a/src/geometry/AABB.h b/src/geometry/AABB.h new file mode 100644 index 0000000..db009da --- /dev/null +++ b/src/geometry/AABB.h @@ -0,0 +1,96 @@ +/* + * AABB.h + * + * Created on: Apr 10, 2012 + * Author: holy + */ + +#ifndef GEOMETRY_AABB_H_ +#define GEOMETRY_AABB_H_ + +#include "Shape.h" + +#include +#include + + +namespace geometry { + +class AABB +: public Shape { + + public: + AABB(void) : leftTop(), rightBottom() { }; + explicit AABB(const Vector &size) : leftTop(), rightBottom(size) { }; + AABB(const Vector &position, const Vector &size) + : leftTop(position), rightBottom(position + size) { }; + 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(); }; + + Scalar X(void) const { return Left(); }; + Scalar Y(void) const { return Top(); }; + Scalar Width(void) const { return Right() - Left(); }; + Scalar Height(void) const { return Bottom() - Top(); }; + + public: + virtual bool Overlaps(const Shape &other, Vector &normal) const; + virtual bool Overlaps(const AABB &other, Vector &normal) const; + virtual bool Overlaps(const Circle &other, Vector &normal) const; + virtual bool Overlaps(const FakeLens &, Vector &normal) const; + + bool VerticalOverlap(const AABB &other) const { + if (Bottom() < other.Top()) return false; + if (other.Bottom() < Top()) return false; + return true; + }; + bool HorizontalOverlap(const AABB &other) const { + if (Right() < other.Left()) return false; + if (other.Right() < Left()) return false; + return true; + }; + + public: + void Move(const Vector &delta) { + leftTop += delta; + rightBottom += delta; + }; + + void SetBounds(const Vector &position, const Vector &size) { + leftTop = position; + rightBottom = position + size; + }; + void SetPosition(const Vector &position) { + rightBottom = position + (rightBottom - leftTop); + leftTop = position; + }; + void SetSize(const Vector &size) { + rightBottom = leftTop + size; + }; + + virtual Vector Center(void) const { + return leftTop + (rightBottom - leftTop) / 2; + }; + + virtual std::ostream &Write(std::ostream &out) const; + + public: + void WriteRect(SDL_Rect &rect) const { + rect.x = X(); + rect.y = Y(); + rect.w = Width(); + rect.h = Height(); + }; + + private: + Vector leftTop, rightBottom; + +}; + +} + +#endif /* GEOMETRY_AABB_H_ */ diff --git a/src/geometry/Circle.cpp b/src/geometry/Circle.cpp new file mode 100644 index 0000000..7d923a5 --- /dev/null +++ b/src/geometry/Circle.cpp @@ -0,0 +1,109 @@ +/* + * Circle.cpp + * + * Created on: Apr 20, 2012 + * Author: holy + */ + +#include "Circle.h" + +#include "AABB.h" +#include "FakeLens.h" +#include "../game/Entity.h" + + +namespace geometry { + +bool Circle::Overlaps(const Shape &other, Vector &normal) const { + if (other.Overlaps(*this, normal)) { + normal *= -1; + return true; + } else { + return false; + } +} + +bool Circle::Overlaps(const AABB &other, Vector &normal) const { + // fast checks for far away shapes + if (Bottom() <= other.Top()) return false; + if (other.Bottom() <= Top()) return false; + if (Right() <= other.Left()) return false; + if (other.Right() <= Left()) return false; + + int xZone( + X() < other.Left() ? 0 : ( + other.Right() < X() ? 2 : 1)); + int yZone( + Y() < other.Top() ? 0 : ( + other.Bottom() < Y() ? 2 : 1)); + int zone(xZone + 3*yZone); + + if (zone == 4) { + normal = (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()) { + normal = Vector(0, -1); + } else { + normal = Vector(0, 1); + } + + return true; + } else { + if (Right() < other.Left()) return false; + if (other.Right() < Left()) return false; + + if (Left() < other.Left()) { + normal = Vector(-1, 0); + } else { + normal = Vector(1, 0); + } + + return true; + } + } else { + Vector near( + yZone ? other.Right() : other.Left(), + xZone ? other.Bottom() : other.Top()); + Vector distance(position - near); + Sint32 distanceSquared(distance.LengthSquared()); + if (distanceSquared < (Radius() * Radius())) { + normal = distance.Unit(); + return true; + } else { + return false; + } + } +} + +bool Circle::Overlaps(const Circle &other, Vector &normal) const { + Vector delta(position - other.position); + Sint32 distanceSquared(delta.LengthSquared()), minDistance(Radius() + other.Radius()); + if (distanceSquared < (minDistance * minDistance)) { + normal = delta.Unify(); + return true; + } else { + return false; + } +} + +bool Circle::Overlaps(const FakeLens &other, Vector &normal) const { + if (other.Overlaps(*this, normal)) { + normal *= -1; + return true; + } else { + return false; + } +} + +std::ostream &Circle::Write(std::ostream &out) const { + return out << "Circle(" << Radius() << '+' << Top() << '+' << Left() << ')'; +} + +} diff --git a/src/geometry/Circle.h b/src/geometry/Circle.h new file mode 100644 index 0000000..8e3e0e1 --- /dev/null +++ b/src/geometry/Circle.h @@ -0,0 +1,86 @@ +/* + * Circle.h + * + * Created on: Apr 19, 2012 + * Author: holy + */ + +#ifndef GEOMETRY_CIRCLE_H_ +#define GEOMETRY_CIRCLE_H_ + +#include "Shape.h" + +#include "AABB.h" + +#include + + +namespace geometry { + +class Circle +: public Shape { + + public: + Circle(void) : position(), radius() { }; + explicit Circle(Scalar radius) : position(), radius(radius) { }; + explicit Circle(const Vector &position, Scalar radius = Scalar()) : position(position), radius(radius) { }; + virtual ~Circle(void) { }; + + public: + Scalar X(void) const { return position.X(); }; + Scalar Y(void) const { return position.Y(); }; + Scalar Radius(void) const { return radius; }; + Scalar Diameter(void) const { return 2 * Radius(); }; + + Scalar Width(void) const { return Diameter(); }; + Scalar Height(void) const { return Diameter(); }; + + Scalar Left(void) const { return X() - Radius(); }; + Scalar Top(void) const { return Y() - Radius(); }; + Scalar Right(void) const { return X() + Radius(); }; + Scalar Bottom(void) const { return Y() + Radius(); }; + + public: + virtual bool Overlaps(const Shape &other, Vector &normal) const; + virtual bool Overlaps(const AABB &other, Vector &normal) const; + virtual bool Overlaps(const Circle &other, Vector &normal) const; + virtual bool Overlaps(const FakeLens &, Vector &normal) const; + + bool VerticalOverlap(const AABB &other) const { + if (Bottom() < other.Top()) return false; + if (other.Bottom() < Top()) return false; + return true; + }; + bool HorizontalOverlap(const AABB &other) const { + if (Right() < other.Left()) return false; + if (other.Right() < Left()) return false; + return true; + }; + + public: + void Move(const Vector &delta) { + position += delta; + }; + + void SetPosition(const Vector &pos) { + position = pos; + }; + void SetRadius(Scalar r) { + radius = r; + }; + + virtual Vector Center(void) const { + return position; + }; + + virtual std::ostream &Write(std::ostream &out) const; + + private: + Vector position; + Scalar radius; + +}; + +} + +#endif /* GEOMETRY_CIRCLE_H_ */ diff --git a/src/geometry/FakeLens.cpp b/src/geometry/FakeLens.cpp new file mode 100644 index 0000000..4ba8269 --- /dev/null +++ b/src/geometry/FakeLens.cpp @@ -0,0 +1,67 @@ +/* + * FakeLens.cpp + * + * Created on: Apr 24, 2012 + * Author: holy + */ + +#include "FakeLens.h" + +#include "Circle.h" + + +#include +using namespace std; + + +namespace geometry { + +bool FakeLens::Overlaps(const Shape &other, Vector &normal) const { + if (other.Overlaps(*this, normal)) { + normal *= -1; + return true; + } else { + return false; + } +} + +bool FakeLens::Overlaps(const AABB &other, Vector &normal) const { + if (AABB::Overlaps(other, normal)) { + MessUpNormal(normal, other); + return true; + } else { + return false; + } +} + +bool FakeLens::Overlaps(const Circle &other, Vector &normal) const { + if (AABB::Overlaps(other, normal)) { + MessUpNormal(normal, other); + return true; + } else { + return false; + } +} + +bool FakeLens::Overlaps(const FakeLens &other, Vector &normal) const { + if (AABB::Overlaps(static_cast(other), normal)) { + MessUpNormal(normal, other); + return true; + } else { + return false; + } +} + + +std::ostream &FakeLens::Write(std::ostream &out) const { + return out << "FakeLens(" << Width() << 'x' << Height() << '+' << X() << '+' << Y() << ')'; +} + + +void FakeLens::MessUpNormal(Vector &normal, const Shape &other) const { + Vector direction((Center() - other.Center()).Unify()); + normal = ((1 - bendFactor) * normal) + (bendFactor* direction); + normal.Unify(); +} + +} diff --git a/src/geometry/FakeLens.h b/src/geometry/FakeLens.h new file mode 100644 index 0000000..3de4577 --- /dev/null +++ b/src/geometry/FakeLens.h @@ -0,0 +1,47 @@ +/* + * FakeLens.h + * + * Created on: Apr 24, 2012 + * Author: holy + */ + +#ifndef GEOMETRY_FAKELENS_H_ +#define GEOMETRY_FAKELENS_H_ + +#include "AABB.h" + + +namespace geometry { + +class FakeLens +: public AABB { + + public: + FakeLens(void) : AABB(), bendFactor(0.22f) { }; + explicit FakeLens(const Vector &size) : AABB(size), bendFactor(0.22f) { }; + FakeLens(const Vector &position, const Vector &size, float bendFactor = 0.22f) : AABB(position, size), bendFactor(bendFactor) { }; + + public: + void SetBendFactor(float b) { bendFactor = b; }; + + public: + virtual bool Overlaps(const Shape &, Vector &normal) const; + + virtual bool Overlaps(const AABB &, Vector &normal) const; + virtual bool Overlaps(const Circle &, Vector &normal) const; + virtual bool Overlaps(const FakeLens &, Vector &normal) const; + + public: + virtual std::ostream &Write(std::ostream &out) const; + + private: + void MessUpNormal(Vector &normal, const Shape &other) const; + + private: + float bendFactor; + +}; + +} + +#endif /* GEOMETRY_FAKELENS_H_ */ diff --git a/src/geometry/Shape.h b/src/geometry/Shape.h new file mode 100644 index 0000000..79c3485 --- /dev/null +++ b/src/geometry/Shape.h @@ -0,0 +1,60 @@ +/* + * Shape.h + * + * Created on: Apr 20, 2012 + * Author: holy + */ + +#ifndef GEOMETRY_SHAPE_H_ +#define GEOMETRY_SHAPE_H_ + +#include "Vector2D.h" + +#include +#include + +namespace geometry { + +class AABB; +class Circle; +class FakeLens; + +class Shape { + + public: + typedef float Scalar; + typedef Vector2D Vector; + typedef std::numeric_limits Limits; + + protected: + Shape(void) { }; + virtual ~Shape(void) { }; + + public: + virtual bool Overlaps(const Shape &, Vector &normal) const = 0; + + virtual bool Overlaps(const AABB &, Vector &normal) const = 0; + virtual bool Overlaps(const Circle &, Vector &normal) const = 0; + virtual bool Overlaps(const FakeLens &, Vector &normal) const = 0; + + public: + virtual std::ostream &Write(std::ostream &out) const = 0; + + public: + virtual void SetPosition(const Vector &) = 0; + virtual Vector Center(void) const = 0; + +}; + +} + + +namespace std { + +inline ostream &operator <<(ostream &out, const geometry::Shape &s) { + return s.Write(out); +}; + +} + +#endif /* GEOMETRY_SHAPE_H_ */ diff --git a/src/geometry/Vector2D.h b/src/geometry/Vector2D.h new file mode 100644 index 0000000..ad7a614 --- /dev/null +++ b/src/geometry/Vector2D.h @@ -0,0 +1,160 @@ +/* + * Vector.h + * + * Created on: Apr 23, 2012 + * Author: holy + */ + +#ifndef GEOMETRY_VECTOR2D_H_ +#define GEOMETRY_VECTOR2D_H_ + +#include +#include + + +namespace geometry { + +template +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 &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 &Unify(void) { + if (LengthSquared() == Scalar()) return *this; + *this /= Length(); + return *this; + }; + Vector2D Unit(void) const { + if (LengthSquared() == Scalar()) return *this; + return *this / Length(); + }; + Vector2D &Reflect(const Vector2D &normal); + + public: + Vector2D &operator +=(const Vector2D &o) { + x += o.X(); + y += o.Y(); + return *this; + }; + Vector2D &operator -=(const Vector2D &o) { + x -= o.X(); + y -= o.Y(); + return *this; + }; + template + Vector2D &operator +=(T s) { x += s; y += s; return *this; }; + template + Vector2D &operator -=(T s) { x -= s; y -= s; return *this; }; + template + Vector2D &operator *=(T s) { x *= s; y *= s; return *this; }; + template + Vector2D &operator /=(T s) { x /= s; y /= s; return *this; }; + + private: + Scalar x, y; + +}; + +template +inline Vector2D &Vector2D::Reflect(const Vector2D &normal) { + Scalar doubleDot(2 * Dot(normal)); + x -= doubleDot * normal.X(); + y -= doubleDot * normal.Y(); + return *this; +}; + + +template +inline Vector2D operator +(const Vector2D &v) { + return v; +}; +template +inline Vector2D operator -(const Vector2D &v) { + return Vector2D(-v.X(), -v.Y()); +}; + +template +inline Vector2D operator +(const Vector2D &lhs, const Vector2D &rhs) { + Vector2D temp(lhs); + temp += rhs; + return temp; +}; +template +inline Vector2D operator -(const Vector2D &lhs, const Vector2D &rhs) { + Vector2D temp(lhs); + temp -= rhs; + return temp; +}; + +template +inline Vector2D operator +(const Vector2D &v, SScalar s) { + Vector2D temp(v); + temp += s; + return temp; +}; +template +inline Vector2D operator -(const Vector2D &v, SScalar s) { + Vector2D temp(v); + temp -= s; + return temp; +}; + +template +inline Vector2D operator +(SScalar s, const Vector2D &v) { + Vector2D temp(v); + temp += s; + return temp; +}; +template +inline Vector2D operator -(SScalar s, const Vector2D &v) { + Vector2D temp(v); + temp -= s; + return temp; +}; + +template +inline Vector2D operator *(const Vector2D &v, SScalar s) { + Vector2D temp(v); + temp *= s; + return temp; +}; +template +inline Vector2D operator *(SScalar s, const Vector2D &v) { + Vector2D temp(v); + temp *= s; + return temp; +}; +template +inline Vector2D operator /(const Vector2D &v, SScalar s) { + Vector2D temp(v); + temp /= s; + return temp; +}; +template +inline Vector2D operator /(SScalar s, const Vector2D &v) { + Vector2D temp(v); + temp /= s; + return temp; +}; + + +template +std::ostream &operator <<(std::ostream &out, const Vector2D &v) { + return out << '<' << v.X() << '|' << v.Y() << '>'; +} + +} + +#endif /* GEOMETRY_VECTOR2D_H_ */ diff --git a/src/pong/Ball.cpp b/src/pong/Ball.cpp new file mode 100644 index 0000000..69ba33e --- /dev/null +++ b/src/pong/Ball.cpp @@ -0,0 +1,45 @@ +/* + * Ball.cpp + * + * Created on: Apr 9, 2012 + * Author: holy + */ + +#include "Ball.h" + +#include "Paddle.h" + +#include +#include + +using game::Entity; + + +namespace pong { + +Ball::Ball(Scalar radius) +: Entity(&shape) +, shape(radius) { + +} + +Ball::Ball(const Vector &position, Scalar radius) +: Entity(position, &shape) +, shape(position, radius) { + +} + + +void Ball::Collide(Entity &other, const Vector &normal) { + Entity::Collide(other, normal); + + if (dynamic_cast(&other)) { + Accelerate(1.015f); + } +} + +void Ball::Render(SDL_Surface *screen) { + circleRGBA(screen, shape.X(), shape.Y(), shape.Radius(), 0xFF, 0xFF, 0xFF, 0xFF); +} + +} diff --git a/src/pong/Ball.h b/src/pong/Ball.h new file mode 100644 index 0000000..0715cba --- /dev/null +++ b/src/pong/Ball.h @@ -0,0 +1,37 @@ +/* + * Ball.h + * + * Created on: Apr 9, 2012 + * Author: holy + */ + +#ifndef PONG_BALL_H_ +#define PONG_BALL_H_ + +#include "../game/Entity.h" +#include "../geometry/Circle.h" + +#include + + +namespace pong { + +class Ball +: public game::Entity { + + public: + explicit Ball(Scalar radius); + Ball(const Vector &position, Scalar radius); + + public: + virtual void Collide(Entity &, const Vector &normal); + virtual void Render(SDL_Surface *dest); + + private: + geometry::Circle shape; + +}; + +} + +#endif /* PONG_BALL_H_ */ diff --git a/src/pong/CountingWall.cpp b/src/pong/CountingWall.cpp new file mode 100644 index 0000000..76989a7 --- /dev/null +++ b/src/pong/CountingWall.cpp @@ -0,0 +1,35 @@ +/* + * CountingWall.cpp + * + * Created on: Apr 17, 2012 + * Author: holy + */ + +#include "CountingWall.h" + +using game::Entity; + + +namespace pong { + +CountingWall::CountingWall(const Vector &size) +: Entity(&shape) +, shape(size) +, count(0) { + +} + +CountingWall::~CountingWall(void) { + +} + + +void CountingWall::Collide(Entity &e, const Vector &normal) { + ++count; +} + +void CountingWall::Render(SDL_Surface *dest) { + +} + +} diff --git a/src/pong/CountingWall.h b/src/pong/CountingWall.h new file mode 100644 index 0000000..98ad0e7 --- /dev/null +++ b/src/pong/CountingWall.h @@ -0,0 +1,40 @@ +/* + * CountingWall.h + * + * Created on: Apr 17, 2012 + * Author: holy + */ + +#ifndef PONG_COUNTINGWALL_H_ +#define PONG_COUNTINGWALL_H_ + +#include "../game/Entity.h" +#include "../geometry/AABB.h" + +#include + +namespace pong { + +class CountingWall +: public game::Entity { + + public: + explicit CountingWall(const Vector &size); + virtual ~CountingWall(void); + + public: + int HitCount(void) { return count; }; + + public: + virtual void Collide(Entity &, const Vector &normal); + virtual void Render(SDL_Surface *dest); + + private: + geometry::AABB shape; + int count; + +}; + +} + +#endif /* PONG_COUNTINGWALL_H_ */ diff --git a/src/pong/Match.cpp b/src/pong/Match.cpp new file mode 100644 index 0000000..683defe --- /dev/null +++ b/src/pong/Match.cpp @@ -0,0 +1,228 @@ +/* + * Match.cpp + * + * Created on: Apr 9, 2012 + * Author: holy + */ + +#include "Match.h" + +#include "../app/Control.h" + +#include +#include +#include +#include + +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::const_iterator i(entities.begin()), end(entities.end()); i != end; ++i) { + (*i)->Update(deltaT); + } +} + +void Match::CheckCollisions(float deltaT) { + Entity::Vector normal; + for (vector::const_iterator i(entities.begin()), end(entities.end()); i != end; ++i) { + for (vector::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::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::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); +} + +} diff --git a/src/pong/Match.h b/src/pong/Match.h new file mode 100644 index 0000000..ce7c0e1 --- /dev/null +++ b/src/pong/Match.h @@ -0,0 +1,66 @@ +/* + * 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 +#include +#include + + +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(float deltaT); + virtual void Render(SDL_Surface *); + + private: + void UpdateEntities(float deltaT); + void CheckCollisions(float deltaT); + void CheckWorldCollisions(float deltaT); + void HandleCollisions(float deltaT); + 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; + Paddle leftPaddle, rightPaddle; + CountingWall topWall, bottomWall, leftWall, rightWall; + std::vector entities; + std::vector collisions; + bool updateScore; + +}; + +} + +#endif /* PONG_MATCH_H_ */ diff --git a/src/pong/Paddle.cpp b/src/pong/Paddle.cpp new file mode 100644 index 0000000..0169689 --- /dev/null +++ b/src/pong/Paddle.cpp @@ -0,0 +1,58 @@ +/* + * Paddle.cpp + * + * Created on: Apr 10, 2012 + * Author: holy + */ + +#include "Paddle.h" + +#include "Ball.h" + + +namespace pong { + +Paddle::Paddle(const Vector &size) +: Entity(&shape) +, shape(size) { + +} + + +void Paddle::Collide(game::Entity &other, const Vector &normal) { + +} + +void Paddle::Render(SDL_Surface *screen) { + SDL_Rect destRect; + shape.WriteRect(destRect); + SDL_FillRect(screen, &destRect, SDL_MapRGB(screen->format, 0xFF, 0xFF, 0xFF)); +} + + +void Paddle::SetMovementSpeed(Vector s) { + movementSpeed = s; + + Vector v; + v = Velocity(); + SetVelocity(v.Unify() * s.Length()); +} + + +void Paddle::StartMovingUp(void) { + SetVelocity(Velocity() - movementSpeed); +} + +void Paddle::StopMovingUp(void) { + SetVelocity(Velocity() + movementSpeed); +} + +void Paddle::StartMovingDown(void) { + SetVelocity(Velocity() + movementSpeed); +} + +void Paddle::StopMovingDown(void) { + SetVelocity(Velocity() - movementSpeed); +} + +} diff --git a/src/pong/Paddle.h b/src/pong/Paddle.h new file mode 100644 index 0000000..a0f90b8 --- /dev/null +++ b/src/pong/Paddle.h @@ -0,0 +1,44 @@ +/* + * Paddle.h + * + * Created on: Apr 10, 2012 + * Author: holy + */ + +#ifndef PONG_PADDLE_H_ +#define PONG_PADDLE_H_ + +#include "../game/Entity.h" +#include "../geometry/FakeLens.h" + +#include + +namespace pong { + +class Paddle +: public game::Entity { + + public: + explicit Paddle(const Vector &size); + + public: + virtual void Collide(game::Entity &, const Vector &normal); + virtual void Render(SDL_Surface *dest); + + public: + void SetMovementSpeed(Vector); + + void StartMovingUp(void); + void StopMovingUp(void); + void StartMovingDown(void); + void StopMovingDown(void); + + private: + geometry::FakeLens shape; + Vector movementSpeed; + +}; + +} + +#endif /* PONG_PADDLE_H_ */ diff --git a/src/sdl-test7.cpp b/src/sdl-test7.cpp new file mode 100644 index 0000000..1f52297 --- /dev/null +++ b/src/sdl-test7.cpp @@ -0,0 +1,26 @@ +//============================================================================ +// Name : sdl-test7.cpp +// Author : HolySmoke +// Version : +// Copyright : +// Description : Hello World in C++, Ansi-style +//============================================================================ + +#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; +} diff --git a/src/sdl/InitSDL.cpp b/src/sdl/InitSDL.cpp new file mode 100644 index 0000000..0f2eacd --- /dev/null +++ b/src/sdl/InitSDL.cpp @@ -0,0 +1,27 @@ +/* + * InitSDL.cpp + * + * Created on: Apr 22, 2012 + * Author: holy + */ + +#include "InitSDL.h" + +#include + +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(); +} + +} diff --git a/src/sdl/InitSDL.h b/src/sdl/InitSDL.h new file mode 100644 index 0000000..016c0b4 --- /dev/null +++ b/src/sdl/InitSDL.h @@ -0,0 +1,29 @@ +/* + * InitSDL.h + * + * Created on: Apr 22, 2012 + * Author: holy + */ + +#ifndef SDL_INITSDL_H_ +#define SDL_INITSDL_H_ + +#include + + +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_ */ diff --git a/src/sdl/InitScreen.cpp b/src/sdl/InitScreen.cpp new file mode 100644 index 0000000..c9b275f --- /dev/null +++ b/src/sdl/InitScreen.cpp @@ -0,0 +1,28 @@ +/* + * InitScreen.cpp + * + * Created on: Apr 22, 2012 + * Author: holy + */ + +#include "InitScreen.h" + +#include + +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) { + +} + +} diff --git a/src/sdl/InitScreen.h b/src/sdl/InitScreen.h new file mode 100644 index 0000000..ba731da --- /dev/null +++ b/src/sdl/InitScreen.h @@ -0,0 +1,37 @@ +/* + * InitScreen.h + * + * Created on: Apr 22, 2012 + * Author: holy + */ + +#ifndef SDL_INITSCREEN_H_ +#define SDL_INITSCREEN_H_ + +#include + +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_ */ diff --git a/src/sdl/InitTTF.cpp b/src/sdl/InitTTF.cpp new file mode 100644 index 0000000..5818a73 --- /dev/null +++ b/src/sdl/InitTTF.cpp @@ -0,0 +1,28 @@ +/* + * InitTTF.cpp + * + * Created on: Apr 22, 2012 + * Author: holy + */ + +#include "InitTTF.h" + +#include +#include + +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(); +} + +} diff --git a/src/sdl/InitTTF.h b/src/sdl/InitTTF.h new file mode 100644 index 0000000..6f0306c --- /dev/null +++ b/src/sdl/InitTTF.h @@ -0,0 +1,26 @@ +/* + * 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_ */