Initial commit after git corruption, old repo deleted.

Working:
Rendering
Resources
Physics
Player movement with mouse
Shooting with mouse
Tiles
This commit is contained in:
Felix Ableitner 2012-09-09 22:50:15 +02:00
commit 45f0b31d57
31 changed files with 1813 additions and 0 deletions

219
source/Game.cpp Normal file
View file

@ -0,0 +1,219 @@
/*
* Game.cpp
*
* Created on: 05.07.2012
* Author: Felix
*/
#include "Game.h"
#include "abstract/Actor.h"
#include "sprite/Cover.h"
#include "util/Loader.h"
#include "util/ResourceManager.h"
#include "util/String.h"
#include "util/Log.h"
/// Goal amount of frames per second.
const int Game::FPS_GOAL = 60;
/// Milliseconds per tick at FPS_GOAL.
const float Game::TICKS_GOAL = 1000 / Game::FPS_GOAL;
/**
* Initializes game, including window and objects (sprites).
*/
Game::Game(const Vector2i& resolution) :
mWorld(b2Vec2(0, 0)),
mWindow(sf::VideoMode(resolution.x, resolution.y, 32), "Roguelike Shooter",
sf::Style::Close | sf::Style::Titlebar),
mView(Vector2f(0, 0), Vector2f(resolution)),
//mFps("test"),
mTileManager(mWorld),
mPlayer(mWorld, mCollection),
mElapsed(0),
mQuit(false),
mPaused(false) {
mWindow.setFramerateLimit(FPS_GOAL);
mWindow.setKeyRepeatEnabled(true);
for (int i = 0; i < 500; i += 50) {
mCollection.insert(std::shared_ptr<Sprite>(new Cover(Vector2f(i, i), Vector2i(20, 20),
mWorld)), Collection::LEVEL_STATIC);
}
mTileManager.generate();
mWorld.SetContactListener(this);
}
/**
* Closes window.
*/
Game::~Game() {
mWindow.close();
}
/**
* Runs the game loop.
*/
void
Game::loop() {
sf::Uint32 left = 0;
while (!mQuit) {
input();
for (; !mPaused && (left >= TICKS_GOAL); left -= TICKS_GOAL) {
Actor::think(TICKS_GOAL);
mWorld.Step(1.0f / FPS_GOAL, 8, 3);
mCollection.checkDelete();
}
//mFps.setString(getFps());
tick();
left += mElapsed;
render();
}
}
/**
* Saves ticks since last call.
*/
void
Game::tick() {
mElapsed = mClock.restart().asMilliseconds();
if (mPaused) {
mElapsed = 0;
}
}
/**
* Handles general game input.
*/
void
Game::input() {
sf::Event event;
while (mWindow.pollEvent(event)) {
switch (event.type) {
case sf::Event::Closed:
mQuit = true;
break;
case sf::Event::KeyPressed:
keyDown(event);
break;
case sf::Event::KeyReleased:
keyUp(event);
break;
case sf::Event::MouseButtonReleased:
mouseUp(event);
break;
case sf::Event::MouseMoved:
mPlayer.setCrosshairPosition(convertCoordinates(event.mouseMove.x, event.mouseMove.y));
break;
default:
break;
}
}
}
/**
* Handles key up event. This is used for events that only fire once per keypress.
*/
void
Game::keyUp(const sf::Event& event) {
switch (event.key.code) {
case sf::Keyboard::Escape:
mQuit = true;
break;
case sf::Keyboard::Space:
mPaused = !mPaused;
break;
default:
break;
}
}
/**
* Handles key down event. This is used for any events that refire automatically.
*/
void
Game::keyDown(const sf::Event& event) {
switch (event.key.code) {
default:
break;
}
}
/**
* Converts a screen coordinate to a world coordinate.
*/
sf::Vector2<float>
Game::convertCoordinates(int x, int y) {
return mWindow.convertCoords(Vector2i(x, y), mView);
}
/**
* Handles mouse key up events.
*/
void
Game::mouseUp(const sf::Event& event) {
switch (event.mouseButton.button) {
case sf::Mouse::Left:
mPlayer.fire();
break;
case sf::Mouse::Right:
mPlayer.move(convertCoordinates(event.mouseButton.x, event.mouseButton.y));
break;
default:
break;
}
}
/**
* Renders world and GUI.
*/
void
Game::render() {
mWindow.clear();
mView.setCenter(mPlayer.getPosition());
// Render world and dynamic stuff.
mWindow.setView(mView);
mWindow.draw(mTileManager);
mWindow.draw(mCollection);
mWindow.draw(mPlayer);
// Render GUI and static stuff.
mWindow.setView(mWindow.getDefaultView());
//mWindow.draw(mFps);
mWindow.display();
}
/**
* Returns current FPS as string.
*/
sf::String
Game::getFps() {
return str((mElapsed != 0) ? 1000.0f / mElapsed : 0.0f, 2);
}
/**
* Begin of collision, call callback function on both objects.
*/
void
Game::BeginContact(b2Contact* contact) {
Physical& first = *static_cast<Physical*>(contact->GetFixtureA()->GetBody()->GetUserData());
Physical& second = *static_cast<Physical*>(contact->GetFixtureB()->GetBody()->GetUserData());
if (!first.doesCollide(second) || !second.doesCollide(first)) {
contact->SetEnabled(false);
return;
}
first.onCollide(second, second.getCategory());
second.onCollide(first, first.getCategory());
}

71
source/Game.h Normal file
View file

@ -0,0 +1,71 @@
/*
* Game.h
*
* Created on: 05.07.2012
* Author: Felix
*/
#ifndef DG_GAME_H_
#define DG_GAME_H_
#include <SFML/System.hpp>
#include <SFML/Graphics.hpp>
#include <Thor/Resources.hpp>
#include <Box2D/Box2D.h>
#include "TileManager.h"
#include "sprite/Player.h"
#include "util/Collection.h"
/*
* Use vertex for tiles.
*/
class Game : private sf::NonCopyable, public b2ContactListener {
// Public functions.
public:
Game(const Vector2i& resolution);
~Game();
void loop();
void BeginContact(b2Contact* contact);
// Private functions.
private:
void input();
void render();
void tick();
void keyDown(const sf::Event& event);
void keyUp(const sf::Event& event);
void mouseUp(const sf::Event& event);
sf::String getFps();
sf::Vector2<float> convertCoordinates(int x, int y);
// Private variables.
private:
static const int FPS_GOAL;
static const float TICKS_GOAL;
b2World mWorld;
sf::RenderWindow mWindow;
sf::Clock mClock;
sf::View mView;
//sf::Text mFps;
Collection mCollection;
TileManager mTileManager;
Player mPlayer;
/// Milliseconds since the last tick.
sf::Uint32 mElapsed;
bool mQuit;
bool mPaused;
};
#endif /* DG_GAME_H_ */

116
source/TileManager.cpp Executable file
View file

@ -0,0 +1,116 @@
/*
* TileManager.cpp
*
* Created on: 08.08.2012
* Author: Felix
*/
#include "TileManager.h"
#include <Thor/Resources.hpp>
#include "util/Loader.h"
#include "util/ResourceManager.h"
#include "abstract/Sprite.h"
const Vector2i TileManager::TILE_SIZE = Vector2i(100, 100);
/**
* Loads tile resources.
*
* @param world Box2D world to create (physical) tiles in.
*/
TileManager::TileManager(b2World& world) :
mWorld(world) {
}
/**
* Constructs a tile.
*
* @param pType Type of the tile to create.
* @param pPosition Position of the tile in tile coordinates.
* @param world Box2D world object.
*/
TileManager::Tile::Tile(Type type, const TilePosition& position, b2World& world) :
Sprite(getTexture(type), PhysicalData(Vector2f(position.x * TILE_SIZE.x, position.y * TILE_SIZE.y),
TILE_SIZE, world, CATEGORY_WORLD, (type == TYPE_FLOOR) ? MASK_NONE : MASK_ALL, false)),
mType(type) {
}
/**
* Returns a texture key for a certain tile type.
*
* @param type The type of tile to load a resource key for.
* @return Resource key to the correct texture.
*/
std::shared_ptr<sf::Texture>
TileManager::Tile::getTexture(Type type) {
sf::String filename;
switch (type) {
case TYPE_FLOOR:
filename = "floor.png";
break;
case TYPE_WALL:
filename = "wall.png";
break;
default:
throw new aurora::Exception("Invalid tile type.");
}
return ResourceManager::i().acquire(Loader::i().fromFile<sf::Texture>(filename));
}
/**
* Returns the Type of this tile.
*/
TileManager::Type
TileManager::Tile::getType() const {
return mType;
}
/**
* Returns the position of the tile with tile width/height as a unit.
*/
TileManager::TilePosition
TileManager::Tile::getTilePosition() const {
return TilePosition(getPosition().x / TILE_SIZE.x, getPosition().y / TILE_SIZE.y);
}
/**
* Fills the world with predefined tiles.
*/
void
TileManager::generate() {
for (int x = 0; x < 10; x++)
for (int y = 0; y < 10; y++)
setTile(TilePosition(x, y), TYPE_WALL);
for (int x = 1; x < 9; x++)
for (int y = 1; y < 9; y++)
setTile(TilePosition(x, y), TYPE_FLOOR);
}
/**
* Insert a tile at the position. Deletes an existing tile first if one is at the position.
*
* @param position Grid coordinate of the tile (not pixel coordinate).
* @param type Type of tile to be inserted.
*/
void
TileManager::setTile(const TilePosition& position, Type type) {
for (auto it = mTiles.begin(); it != mTiles.end(); it++) {
if ((*it)->getTilePosition() == position) {
mTiles.erase(it);
}
}
mTiles.push_back(std::unique_ptr<Tile>(new Tile(type, position, mWorld)));
}
/**
* \copydoc sf::Drawable::draw
*/
void
TileManager::draw(sf::RenderTarget& target, sf::RenderStates states) const {
for (auto it = mTiles.begin(); it != mTiles.end(); it++) {
target.draw((**it), states);
}
}

79
source/TileManager.h Executable file
View file

@ -0,0 +1,79 @@
/*
* TileManager.h
*
* Created on: 08.08.2012
* Author: Felix
*/
#ifndef DG_TILEMANAGER_H_
#define DG_TILEMANAGER_H_
#include <map>
#include <memory>
#include <vector>
#include <SFML/Graphics.hpp>
#include <Box2D/Box2D.h>
#include "util/Vector.h"
#include "abstract/Sprite.h"
class TileManager : public sf::Drawable {
// Public constants.
public:
/// The size of a single tile (pixels).
static const Vector2i TILE_SIZE;
// Public functions.
public:
TileManager(b2World& world);
void generate();
// Private types.
private:
enum Type {
TYPE_FLOOR,
TYPE_WALL
};
/**
* Uses the length/width of a tile as a unit.
*/
typedef Vector2i TilePosition;
class Tile;
// Private functions.
private:
void draw(sf::RenderTarget& target, sf::RenderStates states) const;
void setTile(const TilePosition& position, Type type);
// Private variables.
private:
b2World& mWorld;
std::vector<std::unique_ptr<Tile> > mTiles;
};
/**
* Holds information about a single tile.
*/
class TileManager::Tile : public Sprite {
// Public functions.
public:
Tile(Type type, const TilePosition& position, b2World& world);
Type getType() const;
TilePosition getTilePosition() const;
static std::shared_ptr<sf::Texture> getTexture(Type type);
// Private variables.
private:
Type mType;
};
#endif /* DG_TILEMANAGER_H_ */

41
source/abstract/Actor.cpp Executable file
View file

@ -0,0 +1,41 @@
/*
* Actor.cpp
*
* Created on: 02.09.2012
* Author: Felix
*/
#include "Actor.h"
#include <algorithm>
#include <assert.h>
std::vector<Actor*> Actor::mInstances = std::vector<Actor*>();
/**
* Saves pointer to this instance in static var for think().
*/
Actor::Actor() {
mInstances.push_back(this);
}
/**
* Deletes pointer from think() static var.
*/
Actor::~Actor() {
auto it = std::find(mInstances.begin(), mInstances.end(), this);
assert(it != mInstances.end());
mInstances.erase(it);
}
/**
* Calls onThink on all Actor instances.
*
* @param elapsedTime Amount of time to simulate.
*/
void
Actor::think(float elapsedTime) {
for (auto i : mInstances) {
i->onThink(elapsedTime);
}
}

38
source/abstract/Actor.h Executable file
View file

@ -0,0 +1,38 @@
/*
* Actor.h
*
* Created on: 02.09.2012
* Author: Felix
*/
#ifndef DG_ACTOR_H_
#define DG_ACTOR_H_
#include <vector>
/**
* Provides think function for AI.
*/
class Actor {
// Public functions.
public:
Actor();
virtual ~Actor() = 0;
static void think(float elapsedTime);
// Protected functions.
protected:
/**
* Implement this function for any (regular) AI computations.
*
* @param elapsedTime Amount of time to simulate.
*/
virtual void onThink(float elapsedTime) = 0;
// Private variables.
private:
static std::vector<Actor*> mInstances;
};
#endif /* DG_ACTOR_H_ */

166
source/abstract/Physical.cpp Executable file
View file

@ -0,0 +1,166 @@
/*
* Physical.cpp
*
* Created on: 11.08.2012
* Author: Felix
*/
#include "Physical.h"
#include <math.h>
#include <Thor/Vectors.hpp>
/**
* Initializes Box2D body.
*
* @param data Data needed for construction.
*/
Physical::Physical(const PhysicalData& data) :
mDelete(false) {
assert(data.size != Vector2i());
assert(data.category);
b2BodyDef bodyDef;
// not moving -> static body
// moving -> dynamic body
// bullet -> kinematic body
bodyDef.type = (data.moving) ?
(data.bullet)
? b2_dynamicBody
: b2_dynamicBody
: b2_staticBody;
bodyDef.position = vector(data.position);
bodyDef.allowSleep = true;
bodyDef.fixedRotation = true;
bodyDef.bullet = data.bullet;
bodyDef.userData = this;
mBody = data.world.CreateBody(&bodyDef);
b2PolygonShape boxShape;
boxShape.SetAsBox(pixelToMeter(data.size.x) / 2, pixelToMeter(data.size.y) / 2);
b2FixtureDef fixtureDef;
fixtureDef.shape = &boxShape;
fixtureDef.density = 1.0f;
fixtureDef.filter.categoryBits = data.category;
fixtureDef.filter.maskBits = ~data.maskExclude;
fixtureDef.restitution = 0;
mBody->CreateFixture(&fixtureDef);
}
/**
* Removes body from world.
*/
Physical::~Physical() {
mBody->GetWorld()->DestroyBody(mBody);
}
/**
* Initializes container.
*
* @link Physical::PhysicalData
*/
Physical::PhysicalData::PhysicalData( const Vector2f& position, const Vector2i& size,
b2World& world, uint16 category, uint16 maskExclude, bool moving, bool bullet) :
position(position),
size(size),
world(world),
category(category),
maskExclude(maskExclude),
moving(moving),
bullet(bullet) {
}
/**
* Returns the position of the sprite (center).
*/
Vector2f
Physical::getPosition() const {
return vector(mBody->GetPosition());
}
/**
* Returns the movement speed of the body.
*/
Vector2f
Physical::getSpeed() const {
return vector(mBody->GetLinearVelocity());
}
/**
* Returns the rotation of the body (converted to an SFML angle).
*/
float
Physical::getAngle() const {
return - thor::toDegree(mBody->GetAngle());
}
/**
* Returns true if this object should be deleted.
*/
bool
Physical::getDelete() const {
return mDelete;
}
uint16
Physical::getCategory() const {
return mBody->GetFixtureList()->GetFilterData().categoryBits;
}
/**
* This method filters collisions with other physicals. Implement it if you want to
* limit collisions to/with certain objects. Default implementation always returns true.
*
* @param other The Physical this object is about to collide with.
* @return True if the objects should collide.
*/
bool
Physical::doesCollide(Physical& other) {
return true;
}
/**
* Called when a collision with another body occured. Override this method
* to manage collision events.
*
* @param other Reference to the other Physical in the collision.
* @param category The Category of the other object (as passed in constructor).
*/
void
Physical::onCollide(Physical& other, uint16 type) {
}
/**
* Set to true to mark this object for deletion from the world.
*/
void
Physical::setDelete(bool value) {
mDelete = value;
}
/**
* Sets movement speed and direction of the body. Set either value to zero to stop movement.
*
* @param direction The direction the body moves in, does not have to be normalized.
* @param speed The value of the movement speed to be used.
*/
void
Physical::setSpeed(Vector2f direction, float speed) {
if (direction != Vector2f()) {
direction = thor::unitVector<float>(direction);
}
direction *= speed;
mBody->SetLinearVelocity(vector(direction));
}
/**
* Sets the angle of the body based on the direction of a vector.
*/
void
Physical::setAngle(float angle) {
mBody->SetTransform(mBody->GetPosition(), - thor::toRadian(angle));
}

90
source/abstract/Physical.h Executable file
View file

@ -0,0 +1,90 @@
/*
* Physical.h
*
* Created on: 11.08.2012
* Author: Felix
*/
#ifndef DG_PHYSICAL_H_
#define DG_PHYSICAL_H_
#include <Box2D/Box2D.h>
#include "../util/Vector.h"
/**
* An object with physical properties.
*
* @warning May only handle bodies with one fixture.
*/
class Physical {
// Public types.
public:
/**
* POD container that carries all data required to construct this class.
*/
class PhysicalData {
public:
PhysicalData() = default;
PhysicalData(const Vector2f& position, const Vector2i& size, b2World& world,
uint16 category, uint16 maskExclude, bool moving, bool bullet = false);
const Vector2f& position; //< World position of the body in pixel coordinates.
const Vector2i& size; //< Pixel size of the body.
b2World& world; //< Box2D world object.
uint16 category; //< The category for collision filtering. Only one may be set. @link Physical::Category
uint16 maskExclude; //< All categories set here will have collisions disabled with this object.
bool moving; //< True if the body may move on its own (player, monster).
bool bullet; //< True if the object is a bullet.
};
/**
* Categories of physical objects, for Box2D collision filtering.
*
* @warning An object may only have one category.
*/
enum Category {
CATEGORY_NONSOLID = 0,
CATEGORY_WORLD = 1 << 1,
CATEGORY_ACTOR = 1 << 2,
CATEGORY_PARTICLE = 1 << 3
};
/**
* Common Box2D collision masking values.
*/
enum Mask {
MASK_NONE = 0xffff, //< Disables any collisions.
MASK_ALL = 0 //< Enables all collisions.
};
// Public functions.
public:
Physical(const PhysicalData& data);
virtual ~Physical() = 0;
Vector2f getPosition() const;
Vector2f getSpeed() const;
float getAngle() const;
bool getDelete() const;
uint16 getCategory() const;
virtual bool doesCollide(Physical& other);
virtual void onCollide(Physical& other, uint16 category);
// Protected functions.
protected:
void setDelete(bool value);
void setSpeed(Vector2f direction, float speed);
void setAngle(float angle);
// Protected variables.
protected:
// Currently protected to allow for (debug only) direct player input.
b2Body* mBody;
// Private variables.
private:
bool mDelete;
};
#endif /* DG_PHYSICAL_H_ */

View file

@ -0,0 +1,58 @@
/*
* Sprite.cpp
*
* Created on: 22.07.2012
* Author: Felix
*/
#include "Sprite.h"
#include "../util/Loader.h"
#include "../util/Log.h"
#include "../util/String.h"
#include "../util/ResourceManager.h"
/**
* Loads sprite from ResourceManager, sets world position.
*
* @param texturePath Relative path to the texture file in the resource folder.
*/
Sprite::Sprite(const sf::String& texturePath, const PhysicalData& data) :
Physical(data),
mTexture(ResourceManager::i().acquire(Loader::i().fromFile<sf::Texture>(texturePath))),
mSize(data.size) {
}
/**
* Loads sprite from ResourceManager, sets world position. Use this if the texture has already been loaded.
*
* @param texture Pointer to the texture to be used (must already be loaded).
*/
Sprite::Sprite(const std::shared_ptr<sf::Texture>& texture, const PhysicalData& data) :
Physical(data),
mTexture(texture),
mSize(data.size) {
}
/**
* Does nothing.
*/
Sprite::~Sprite() {
}
/**
* \copydoc sf::Drawable::draw
*/
void
Sprite::draw(sf::RenderTarget& target, sf::RenderStates states) const {
// Create a temporary shape to apply box2d body transformations to.
sf::RectangleShape shape = sf::RectangleShape(Vector2f(mSize));
shape.setTexture(&*mTexture, true);
shape.setOrigin(Vector2f(mSize.x / 2, mSize.y / 2));
shape.setTextureRect(sf::IntRect(Vector2i(0, 0), mSize));
shape.setPosition(getPosition());
shape.setRotation(getAngle());
target.draw(shape, states);
}

36
source/abstract/Sprite.h Normal file
View file

@ -0,0 +1,36 @@
/*
* Sprite.h
*
* Created on: 22.07.2012
* Author: Felix
*/
#ifndef DG_SPRITE_H_
#define DG_SPRITE_H_
#include <SFML/Graphics.hpp>
#include <Thor/Resources.hpp>
#include "Physical.h"
#include "../util/Vector.h"
/**
* Represents a drawable object.
*
* Handles drawing to world.
*/
class Sprite : public sf::Drawable, public Physical {
public:
Sprite(const sf::String& texturePath, const PhysicalData& data);
Sprite(const std::shared_ptr<sf::Texture>& texture, const PhysicalData& data);
virtual ~Sprite() = 0;
private:
virtual void draw(sf::RenderTarget& target, sf::RenderStates states) const;
std::shared_ptr<sf::Texture> mTexture;
Vector2i mSize;
};
#endif /* DG_SPRITE_H_ */

45
source/effects/Bullet.cpp Executable file
View file

@ -0,0 +1,45 @@
/*
* Bullet.cpp
*
* Created on: 12.08.2012
* Author: Felix
*/
#include "Bullet.h"
#include "../util/Log.h"
const float Bullet::SPEED = 500.0f;
/**
* Places a bullet in the world.
*
* @param position World position of the bullet.
* @param world Box2d world.
* @param texture Texture to display for bullet.
*/
Bullet::Bullet(const Vector2f& position, b2World& world,
const std::shared_ptr<sf::Texture>& texture, Physical& shooter, float direction) :
Particle(texture, PhysicalData(position, Vector2i(20, 20), world, CATEGORY_PARTICLE,
CATEGORY_PARTICLE, true, true)),
mShooter(shooter) {
setSpeed(angle(direction), SPEED);
setAngle(direction);
}
/**
* @copydoc Physical::onCollide
*/
void
Bullet::onCollide(Physical& other, uint16 type) {
// Make sure we do not damage twice.
if (!getDelete()) {
// Call onShot on other, with damage as param.
setDelete(true);
}
}
bool
Bullet::doesCollide(Physical& other) {
return &other != &mShooter;
}

31
source/effects/Bullet.h Executable file
View file

@ -0,0 +1,31 @@
/*
* Bullet.h
*
* Created on: 12.08.2012
* Author: Felix
*/
#ifndef DG_BULLET_H_
#define DG_BULLET_H_
#include "../particle/Particle.h"
/**
* Bullet particle fired by a weapon, may damage actors.
*/
class Bullet : public Particle {
// Public functions.
public:
Bullet(const Vector2f& position, b2World& world, const std::shared_ptr<sf::Texture>& texture,
Physical& shooter, float direction);
void onCollide(Physical& other, uint16 category);
bool doesCollide(Physical& other);
// Private variables.
private:
static const float SPEED;
Physical& mShooter;
};
#endif /* DG_BULLET_H_ */

38
source/items/Weapon.cpp Executable file
View file

@ -0,0 +1,38 @@
/*
* Weapon.cpp
*
* Created on: 12.08.2012
* Author: Felix
*/
#include "Weapon.h"
#include "../util/Collection.h"
#include "../effects/Bullet.h"
#include "../util/Loader.h"
#include "../util/ResourceManager.h"
Weapon::Weapon(Physical& holder, Collection& collection, b2World& world) :
Emitter(collection),
mHolder(holder),
mBulletTexture(ResourceManager::i().acquire(Loader::i().fromFile<sf::Texture>("bullet.png"))),
mWorld(world) {
}
Weapon::~Weapon() {
}
/**
* Call on any button press/refire.
*/
void
Weapon::fire() {
// Only call if has ammo, consider firing rate etc.
emit();
}
std::shared_ptr<Particle>
Weapon::createParticle() {
return std::shared_ptr<Particle>(new Bullet(mHolder.getPosition(), mWorld, mBulletTexture,
mHolder, mHolder.getAngle()));
}

37
source/items/Weapon.h Executable file
View file

@ -0,0 +1,37 @@
/*
* Weapon.h
*
* Created on: 12.08.2012
* Author: Felix
*/
#ifndef DG_WEAPON_H_
#define DG_WEAPON_H_
#include <Thor/Particles.hpp>
#include "../abstract/Physical.h"
#include "../particle/Emitter.h"
/**
* Loading mechanism:
* - pass enum value and load mapped xml
* - pass xml filename
*/
class Weapon : public Emitter {
public:
Weapon(Physical& holder, Collection& collection, b2World& world);
~Weapon();
void fire();
protected:
std::shared_ptr<Particle> createParticle();
private:
Physical& mHolder;
std::shared_ptr<sf::Texture> mBulletTexture;
b2World& mWorld;
};
#endif /* DG_WEAPON_H_ */

23
source/main.cpp Normal file
View file

@ -0,0 +1,23 @@
/*
* main.cpp
*
* Created on: 19.07.2012
* Author: Felix
*/
#include "Game.h"
#include "util/Loader.h"
/**
* Creates Game object.
*/
int main(int argc, char* argv[]) {
Loader::i().setFolder("resources/");
Loader::i().setSubFolder<sf::Texture>("textures/");
Game game(Vector2i(800, 600));
game.loop();
return 0;
}

23
source/particle/Emitter.cpp Executable file
View file

@ -0,0 +1,23 @@
/*
* Emitter.cpp
*
* Created on: 15.08.2012
* Author: Felix
*/
#include "Emitter.h"
Emitter::Emitter(Collection& collection) :
mCollection(collection) {
}
Emitter::~Emitter() {
}
/**
* Inserts a new particle into the system, using createParticle().
*/
void
Emitter::emit() {
mCollection.insert(createParticle(), Collection::LEVEL_PARTICLE);
}

32
source/particle/Emitter.h Executable file
View file

@ -0,0 +1,32 @@
/*
* Emitter.h
*
* Created on: 15.08.2012
* Author: Felix
*/
#ifndef DG_EMITTER_H_
#define DG_EMITTER_H_
#include "../abstract/Physical.h"
#include "../util/Collection.h"
#include "Particle.h"
class Emitter {
// Public functions.
public:
Emitter(Collection& collection);
virtual ~Emitter();
// Protected functions.
protected:
void emit();
/// Creates a particle. Allows to use a user-defined particle class and custom settings.
virtual std::shared_ptr<Particle> createParticle() = 0;
// Private variables.
private:
Collection& mCollection;
};
#endif /* DG_EMITTER_H_ */

16
source/particle/Particle.cpp Executable file
View file

@ -0,0 +1,16 @@
/*
* Particle.cpp
*
* Created on: 15.08.2012
* Author: Felix
*/
#include "Particle.h"
Particle::Particle(const std::shared_ptr<sf::Texture>& texture, const PhysicalData& data) :
Sprite(texture, data) {
}
Particle::~Particle() {
}

22
source/particle/Particle.h Executable file
View file

@ -0,0 +1,22 @@
/*
* Particle.h
*
* Created on: 15.08.2012
* Author: Felix
*/
#ifndef DG_PARTICLE_H_
#define DG_PARTICLE_H_
#include "../abstract/Sprite.h"
/**
* Prototype for a particle.
*/
class Particle : public Sprite {
public:
Particle(const std::shared_ptr<sf::Texture>& texture, const PhysicalData& data);
virtual ~Particle();
};
#endif /* DG_PARTICLE_H_ */

13
source/sprite/Cover.cpp Executable file
View file

@ -0,0 +1,13 @@
/*
* Cover.cpp
*
* Created on: 12.08.2012
* Author: Felix
*/
#include "Cover.h"
Cover::Cover(const Vector2f& position, const Vector2i& size, b2World& world) :
Sprite("cover.png", PhysicalData(position, size, world, CATEGORY_WORLD, MASK_ALL, false)) {
}

21
source/sprite/Cover.h Executable file
View file

@ -0,0 +1,21 @@
/*
* Cover.h
*
* Created on: 12.08.2012
* Author: Felix
*/
#ifndef DG_COVER_H_
#define DG_COVER_H_
#include "../abstract/Sprite.h"
/**
* A wall that can be placed anywhere (not limited by tiles) and have any (rectangular) size.
*/
class Cover : public Sprite {
public:
Cover(const Vector2f& position, const Vector2i& size, b2World& world);
};
#endif /* DG_COVER_H_ */

74
source/sprite/Player.cpp Normal file
View file

@ -0,0 +1,74 @@
/*
* Player.cpp
*
* Created on: 21.07.2012
* Author: Felix
*/
#include "Player.h"
#include <Thor/Vectors.hpp>
#include "../util/Vector.h"
#include "../items/Weapon.h"
const float Player::SPEED = 100.0f;
/**
* Initializes Sprite.
*/
Player::Player(b2World& world, Collection& collection) :
Sprite("player.png", PhysicalData(Vector2f(200.0f, 100.0f), Vector2i(50, 50), world,
CATEGORY_ACTOR, MASK_ALL, true)),
mWeapon(*this, collection, world),
mDestination(Vector2i(50, 50)) {
}
/**
* Sets the point where to look and shoot at.
*
* @param Absolute world coordinates of the crosshair.
*/
void
Player::setCrosshairPosition(const Vector2f& position) {
mCrosshairPosition = position - getPosition();
}
/**
* Fire the attacked Weapon, emitting a Bullet object.
*/
void
Player::fire() {
mWeapon.fire();
}
/**
* Moves the player to a destination point.
*
* @param destination Absolute world coordinate of the destination point.
*/
void
Player::move(const Vector2f& destination) {
mDestination = destination;
// Convert to relative destination.
setSpeed(mDestination - getPosition(), SPEED);
}
void
Player::onThink(float elapsedTime) {
// Stop if we are close enough.
if (thor::length(mDestination - getPosition()) < 1.0f) {
setSpeed(Vector2f(), 0);
}
// Look towards crosshair.
setAngle(angle(mCrosshairPosition));
}
/**
* Stop movement if we collide with anything except bullets.
*/
void
Player::onCollide(Physical& other, uint16 category) {
if (category != CATEGORY_PARTICLE) {
mDestination = getPosition();
}
}

46
source/sprite/Player.h Normal file
View file

@ -0,0 +1,46 @@
/*
* Player.h
*
* Created on: 21.07.2012
* Author: Felix
*/
#ifndef DG_PLAYER_H_
#define DG_PLAYER_H_
#include <SFML/System.hpp>
#include <SFML/Graphics.hpp>
#include "../abstract/Actor.h"
#include "../abstract/Sprite.h"
#include "../items/Weapon.h"
#include "../util/Vector.h"
class Sprite;
/**
* Player object.
*/
class Player : public Sprite, public Actor {
// Public functions.
public:
Player(b2World& world, Collection& collection);
void setCrosshairPosition(const Vector2f& position);
void fire();
void move(const Vector2f& destination);
// Protected functions.
protected:
void onCollide(Physical& other, uint16 category);
void onThink(float elapsedTime);
// Private variables.
private:
static const float SPEED;
Weapon mWeapon; //< Weapon object used for Player::fire().
Vector2f mDestination; //< Absolute position of the movement destination.
Vector2f mCrosshairPosition; //< Relative position of the point to fire at (mouse cursor).
};
#endif /* DG_PLAYER_H_ */

65
source/util/Collection.cpp Executable file
View file

@ -0,0 +1,65 @@
/*
* Collection.cpp
*
* Created on: 29.08.2012
* Author: Felix
*/
#include "Collection.h"
#include <algorithm>
/**
* Insert a drawable into the group. Drawables should only be handled with shared_ptr.
* An object can't be inserted more than once at the same level.
*/
void
Collection::insert(std::shared_ptr<Sprite> drawable, Level level) {
auto item = std::find(mDrawables[level].begin(), mDrawables[level].end(), drawable);
if (item == mDrawables[level].end()) {
mDrawables[level].push_back(drawable);
}
}
/**
* Removes a drawable from the group.
*/
void
Collection::remove(std::shared_ptr<Sprite> drawable) {
for (auto v = mDrawables.begin(); v != mDrawables.end(); v++) {
auto item = std::find(v->second.begin(), v->second.end(), drawable);
if (item != v->second.end()) {
v->second.erase(item);
}
}
}
/**
* Deletes any sprites which return true for getDelete().
*/
void
Collection::checkDelete() {
for (auto v = mDrawables.begin(); v != mDrawables.end(); v++) {
for (auto item = v->second.begin(); item != v->second.end(); ) {
if ((*item)->getDelete()) {
item = v->second.erase(item);
}
else {
item++;
}
}
}
}
/**
* Draws all elements in the group.
*/
void
Collection::draw(sf::RenderTarget& target, sf::RenderStates states) const {
for (auto v = mDrawables.begin(); v != mDrawables.end(); v++) {
for (auto item : v->second) {
target.draw(static_cast<sf::Drawable&>(*item), states);
}
}
}

48
source/util/Collection.h Executable file
View file

@ -0,0 +1,48 @@
/*
* Collection.h
*
* Created on: 29.08.2012
* Author: Felix
*/
#ifndef DG_COLLECTION_H_
#define DG_COLLECTION_H_
#include <map>
#include <vector>
#include <SFML/Graphics.hpp>
#include "../abstract/Sprite.h"
/**
* A collection of sprites, which can be put into different layers.
*/
class Collection : public sf::Drawable {
// Public types.
public:
/**
* Determines in what order sprites are rendered, dynamics and actors should be on top.
*/
enum Level {
LEVEL_STATIC,
LEVEL_PARTICLE,
LEVEL_ACTOR
};
// Public functions.
public:
void insert(std::shared_ptr<Sprite> drawable, Level level);
void remove(std::shared_ptr<Sprite> drawable);
void checkDelete();
// Private functions.
private:
void draw(sf::RenderTarget& target, sf::RenderStates states) const;
// Private variables.
private:
std::map<Level, std::vector<std::shared_ptr<Sprite> > > mDrawables;
};
#endif /* DG_COLLECTION_H_ */

137
source/util/Loader.h Executable file
View file

@ -0,0 +1,137 @@
/*
* Loader.h
*
* Created on: 13.08.2012
* Author: Felix
*/
#ifndef DG_LOADER_H_
#define DG_LOADER_H_
#include <string>
#include <map>
#include <memory>
#include <SFML/System.hpp>
#include <Thor/Resources.hpp>
#include "Singleton.h"
/**
* This class allows to set default resource folders and subfolders, which means that these
* folders only have to be set once, and not be included in the creation of every single
* resource key.
*
* If the general resource folder or a specific resource folder is not set, the current
* directory is searched.
*
* R is any resource that can be loaded with Thor's resource loader.
*
* Any folder/file parameter can be a full path and is relative to the current directory,
* or the directory set by the higher variables.
*
* @code
* Loader l;
* l.setFolder("resources/");
* l.setSubFolder<sf::Texture>("textures/");
* thor::ResourceKey<sf::Texture> t = l.fromFile<sf::Texture>("myimage.png");
*
* ResourceManager r;
* r.acquire(t); // This loads from "resources/textures/myimage.png".
* // folder subfolder file
* @endcode
*/
class Loader : public Singleton<Loader> {
// Public functions.
public:
/**
* Sets the general resource folder path.
*/
inline void setFolder(const std::string& folder) {mFolder = folder;};
/**
* Sets the resource subfolder for the specific type.
*/
template <typename R> void
setSubFolder(std::string path) {
getLoader<R>()->setSubFolder(path);
}
/**
* Loads a resource from a file, looking in the specific resource folder for this type.
*/
template <typename T> thor::ResourceKey<T>
fromFile(const std::string& file) {
return static_cast<SpecificLoader<T>* >(getLoader<T>().get())->fromFile(mFolder, file);
}
// Private types.
private:
/**
* We need this to save templates of different types in the same container.
*/
class LoaderBase {
public:
virtual void setSubFolder(const std::string& path) = 0;
};
/**
* This class forwards the loading of each individual type to Thor.
*/
template <typename T>
class SpecificLoader : public LoaderBase {
public:
/**
* Sets the subfolder for the current type.
*/
void
setSubFolder(const std::string& path) {
mSubfolder = path;
}
/**
* Loads a resource from file via Thor.
*
* @param folder The general resource folder
* @param file Path/name of the file within the resource subfolder.
*/
thor::ResourceKey<T>
fromFile(const std::string& folder, const std::string& file) {
return thor::Resources::fromFile<T>(folder + mSubfolder + file);
}
private:
std::string mSubfolder;
};
// Private functions.
private:
/**
* For Singleton behaviour.
*/
Loader() = default;
friend class Singleton<Loader>;
/**
* Gets the correct loader for each template type, creates it if it does not exist.
*/
template <typename T> std::unique_ptr<LoaderBase>&
getLoader() {
auto loader = mLoaders.find(typeid(T));
if (loader != mLoaders.end()) {
return static_cast<std::unique_ptr<LoaderBase>&>(loader->second);
}
else {
return (*mLoaders.insert(std::pair<std::type_index, std::unique_ptr<LoaderBase> >
(typeid(T), std::unique_ptr<LoaderBase>(new SpecificLoader<T>))).first).second;
}
};
// Private variables.
private:
std::string mFolder;
std::map<std::type_index, std::unique_ptr<LoaderBase> > mLoaders;
};
#endif /* DG_LOADER_H_ */

37
source/util/Log.h Normal file
View file

@ -0,0 +1,37 @@
/*
* Log.h
*
* Created on: 25.07.2012
* Author: Felix
*/
#ifndef DG_LOG_H_
#define DG_LOG_H_
#include <iostream>
/**
* \def LOG_E(str)
* Log an error to the error stream.
*/
#define LOG_E(str) std::cerr << "Error: " << __FILE__ << ":" << __LINE__ << " \"" << str << "\"" << std::endl
/**
* \def LOG_E(str)
* Log a warning to the output stream.
*/
#define LOG_W(str) std::cout << "Warning: " << __FILE__ << ":" << __LINE__ << " \"" << str << "\"" << std::endl
/**
* \def LOG_E(str)
* Log a debug message to the output stream.
*/
#define LOG_D(str) std::cout << "Debug: " << __FILE__ << ":" << __LINE__ << " \"" << str << "\"" << std::endl
/**
* \def LOG_E(str)
* Log an info to the output stream.
*/
#define LOG_I(str) std::cout << "Info: " << __FILE__ << ":" << __LINE__ << " \"" << str << "\"" << std::endl
#endif /* DG_LOG_H_ */

View file

@ -0,0 +1,26 @@
/*
* ResourceManager.h
*
* Created on: 22.07.2012
* Author: Felix
*/
#ifndef DG_RESOURCEMANAGER_H_
#define DG_RESOURCEMANAGER_H_
#include <SFML/Graphics.hpp>
#include <Thor/Resources.hpp>
#include "Singleton.h"
/**
* Loads and manages all resources by providing Singleton access to Thor ResourceManager.
*/
class ResourceManager : public thor::MultiResourceCache, public Singleton<ResourceManager> {
private:
friend class Singleton<ResourceManager>;
ResourceManager() = default;
};
#endif /* DG_RESOURCEMANAGER_H_ */

31
source/util/Singleton.h Normal file
View file

@ -0,0 +1,31 @@
/*
* Singleton.h
*
* Created on: 04.07.2012
* Author: Felix
*/
#ifndef DG_SINGLETON_H_
#define DG_SINGLETON_H_
#include <SFML/System.hpp>
/**
* Template class for inheriting singleton behaviour.
*
* To use, just make a subclass with only a private default constructor and Singleton<T>
* as friend class.
*/
template <class T>
class Singleton : public sf::NonCopyable {
public:
/**
* Get the instance of this class.
*/
static T& i() {
static T s;
return s;
};
};
#endif /* DG_SINGLETON_H_ */

50
source/util/String.h Normal file
View file

@ -0,0 +1,50 @@
/*
* String.h
*
* Created on: 19.07.2012
* Author: Felix
*/
/**
* Use this as a replacement for std::to_string as MingW does not support it.
*/
#ifndef DG_STRING_H_
#define DG_STRING_H_
#include <math.h>
#include <sstream>
#include <SFML/System.hpp>
/**
* Converts any value to a string.
*
* @param val Any variable.
* @return val converted to string.
*/
template <typename T>
sf::String
str(T val) {
std::stringstream out;
out << val;
return out.str();
}
/**
* Converts floating point variable to string,
*
* @param val Any floating point variable.
* @param digits Number of decimal places to round to.
* @return val converted to string.
*/
template <typename T>
sf::String
str(T val, int digits) {
std::stringstream out;
out.precision(digits);
out << val;
return out.str();
}
#endif /* DG_STRING_H_ */

84
source/util/Vector.h Executable file
View file

@ -0,0 +1,84 @@
/*
* Vector.h
*
* Created on: 03.08.2012
* Author: Felix
*/
#ifndef VECTOR_H_
#define VECTOR_H_
#include <math.h>
#include <SFML/System.hpp>
#include <Box2D/Box2D.h>
#include <Thor/Vectors.hpp>
/**
* 2D floating point vector with x/y members.
*/
typedef sf::Vector2f Vector2f;
/**
* 2D integer vector with x/y members.
*/
typedef sf::Vector2i Vector2i;
/**
* Constant for conversion between Box2D vectors and SFML vectors.
*/
static const int PIXELS_PER_METER = 25;
/**
* Converts a distance from pixels to meters.
*/
inline float
pixelToMeter(float in) {
return in / PIXELS_PER_METER;
}
/**
* Converts a distance from meters to pixels.
*/
inline float
meterToPixel(float in) {
return in * PIXELS_PER_METER;
}
/**
* Converts Box2D metric vector to SFML pixel vector.
*/
inline Vector2f
vector(const b2Vec2& in) {
return Vector2f(meterToPixel(in.x), meterToPixel(in.y));
}
/**
* Converts SFML pixel vector to Box2D metric vector.
*/
inline b2Vec2
vector(const Vector2f& in) {
return b2Vec2(pixelToMeter(in.x), pixelToMeter(in.y));
}
/**
* Converts a vector to an SFML angle with the same direction.
*/
inline float
angle(Vector2f in) {
return 180 - thor::toDegree(atan2(in.x, in.y));
}
/**
* Converts an SFML angle to a unit vector with the same direction.
*/
inline Vector2f
angle(float in) {
in = thor::toRadian(180 - in);
return Vector2f(sin(in), cos(in));
}
#endif /* VECTOR_H_ */