Merged Sprite and Body.

This commit is contained in:
Felix Ableitner 2012-12-23 15:50:49 +01:00
parent 88270ad28c
commit f384165e24
19 changed files with 255 additions and 323 deletions

View file

@ -17,7 +17,7 @@
*/
void
World::insert(std::shared_ptr<Sprite> drawable) {
Body::Category cat = drawable->getCategory();
Sprite::Category cat = drawable->getCategory();
auto item = std::find(mDrawables[cat].begin(), mDrawables[cat].end(), drawable);
if (item == mDrawables[cat].end()) {
mDrawables[cat].push_back(drawable);

View file

@ -13,10 +13,9 @@
#include <SFML/Graphics.hpp>
#include "abstract/Body.h"
#include "abstract/Sprite.h"
class Body;
class Sprite;
class Sprite;
/**
@ -39,7 +38,7 @@ private:
// Private variables.
private:
std::map<Body::Category, std::vector<std::shared_ptr<Sprite> > > mDrawables;
std::map<Sprite::Category, std::vector<std::shared_ptr<Sprite> > > mDrawables;
};
#endif /* DG_WORLD_H_ */

View file

@ -1,154 +0,0 @@
/*
* Body.cpp
*
* Created on: 11.08.2012
* Author: Felix
*/
#include "Body.h"
#include <math.h>
#include <Thor/Vectors.hpp>
const std::string Body::KEY_SIZE = "size";
const sf::Vector2i Body::DEFAULT_SIZE = sf::Vector2i(50, 50);
/**
* Initializes Box2D body.
*
* @param data Data needed for construction.
*/
Body::Body(const Data& data, const Yaml& config, const sf::Vector2i& pSize) :
mPosition(data.position),
mSize(config.get(KEY_SIZE, DEFAULT_SIZE)),
mAngle(0),
mCategory(data.category),
mMask(data.mask),
mDelete(false) {
}
/**
* Used to make this class pure virtual without any pure virtual function.
*/
Body::~Body() {
}
/**
* Initializes container.
*/
Body::Data::Data(const sf::Vector2f& position, float angle,
Category category, unsigned short maskExclude) :
position(position),
angle(angle),
category(category),
mask(maskExclude) {
}
/**
* Returns the position of the sprite (center).
*/
sf::Vector2f
Body::getPosition() const {
return mPosition;
}
/**
* Returns the movement speed of the body.
*/
sf::Vector2f
Body::getSpeed() const {
return mSpeed;
}
/**
* Returns the rotation of the body (converted to an SFML angle).
*/
float
Body::getAngle() const {
return mAngle;
}
/**
* Returns true if this object should be deleted.
*/
bool
Body::getDelete() const {
return mDelete;
}
/**
* Returns the Physical::Category of this object.
*/
Body::Category
Body::getCategory() const {
return mCategory;
}
/**
* Returns the size of the body as a vector.
*/
sf::Vector2i
Body::getSize() const {
return mSize;
}
/**
* 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
Body::doesCollide(Body& 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.
*/
void
Body::onCollide(Body& other) {
}
/**
* Set to true to mark this object for deletion from the world.
*/
void
Body::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 Movement speed in pixels per second.
*/
void
Body::setSpeed(sf::Vector2f direction, float speed) {
if (direction != sf::Vector2f()) {
thor::setLength(direction, speed);
}
mSpeed = direction;
}
/**
* Sets the angle of the body.
*/
void
Body::setAngle(float angle) {
mAngle = angle;
}
/**
* Sets the position of thr body.
*/
void
Body::setPosition(const sf::Vector2f& position) {
mPosition = position;
}

View file

@ -1,98 +0,0 @@
/*
* Body.h
*
* Created on: 11.08.2012
* Author: Felix
*/
#ifndef DG_BODY_H_
#define DG_BODY_H_
#include "../util/Yaml.h"
class Yaml;
/**
* An object with physical properties.
*
* @warning May only handle bodies with one fixture.
*/
class Body {
// Public types.
public:
/**
* Categories of physical objects, for Box2D collision filtering.
* The order of categories is also used for render order in Collection::draw()
* (higher number on top).
*
* @warning An object may only have one category.
*/
enum Category {
CATEGORY_WORLD = 1 << 1,
CATEGORY_NONSOLID = 1 << 2,
CATEGORY_PARTICLE = 1 << 3,
CATEGORY_ACTOR = 1 << 4
};
/**
* POD container that carries all data required to construct an object of this class.
*/
class Data {
public:
Data() = default;
Data(const sf::Vector2f& position, float angle, Category category, unsigned short maskExclude);
const sf::Vector2f& position;
float angle;
Category category;
unsigned short mask;
};
/**
* Common collision masking values.
*/
enum Mask : unsigned short {
MASK_NONE = 0xffff, //< Disables any collisions.
MASK_ALL = 0 //< Enables all collisions.
};
// Public functions.
public:
Body(const Data& data, const Yaml& config, const sf::Vector2i& pSize = sf::Vector2i());
virtual ~Body() = 0;
sf::Vector2f getPosition() const;
sf::Vector2f getSpeed() const;
float getAngle() const;
bool getDelete() const;
Category getCategory() const;
sf::Vector2i getSize() const;
virtual bool doesCollide(Body& other);
virtual void onCollide(Body& other);
// Public variables.
public:
static const std::string KEY_SIZE;
static const sf::Vector2i DEFAULT_SIZE;
// Protected functions.
protected:
friend class World;
void setDelete(bool value);
void setSpeed(sf::Vector2f direction, float speed);
void setAngle(float angle);
void setPosition(const sf::Vector2f& position);
// Private variables.
private:
sf::Vector2f mPosition;
sf::Vector2i mSize;
sf::Vector2f mSpeed;
float mAngle;
Category mCategory;
unsigned short mMask;
bool mDelete;
};
#endif /* DG_BODY_H_ */

View file

@ -27,7 +27,7 @@ std::vector<Character*> Character::mCharacterInstances = std::vector<Character*>
*/
Character::Character(World& world, Pathfinder& pathfinder,
const Data& data, const Yaml& config) :
Sprite(config, data),
Sprite(data, config),
mWorld(world),
mPathfinder(pathfinder),
mMaxHealth(config.get(KEY_HEALTH, DEFAULT_HEALTH)),

181
source/abstract/Sprite.cpp Normal file → Executable file
View file

@ -1,33 +1,59 @@
/*
* Sprite.cpp
*
* Created on: 22.07.2012
* Created on: 11.08.2012
* Author: Felix
*/
#include "Sprite.h"
#include "../util/Loader.h"
#include "../util/ResourceManager.h"
#include "../util/Log.h"
#include <math.h>
#include <Thor/Vectors.hpp>
#include "../util/Loader.h"
#include "../util/Log.h"
#include "../util/ResourceManager.h"
const std::string Sprite::KEY_SIZE = "size";
const std::string Sprite::KEY_RADIUS = "radius";
const std::string Sprite::KEY_TEXTURE = "texture";
const std::string Sprite::DEFAULT_TEXTURE = "";
/**
* Loads sprite from ResourceManager, sets world position.
* Initializes sprite data.
*
* @param texturePath Relative path to the texture file in the resource folder.
* @param data Container holding construction parameters.
* @param config Additional construction parameters
*/
Sprite::Sprite(const Yaml& config, const Data& data, const sf::Vector2i& size) :
Body(data, config, size),
mSize(sf::Vector2i(getSize())) {
std::string texture = config.get(KEY_TEXTURE, DEFAULT_TEXTURE);
Sprite::Sprite(const Data& data, const Yaml& config) :
mCategory(data.category),
mMask(data.mask),
mDelete(false) {
std::string texture = config.get<std::string>(KEY_TEXTURE, "");
if (texture == "") {
LOG_E("Failed to read texture from YAML file " << config.getFilename());
}
mTexture = ResourceManager::i().acquire(Loader::i()
.fromFile<sf::Texture>(texture));
.fromFile<sf::Texture>(texture));
float radius = config.get(KEY_RADIUS, 0.0f);
sf::Vector2f size = config.get(KEY_SIZE, sf::Vector2f());
if (radius != 0.0f) {
mShape = std::unique_ptr<sf::Shape>(new sf::CircleShape(radius));
}
else if (size != sf::Vector2f()) {
mShape = std::unique_ptr<sf::Shape>(new sf::RectangleShape(size));
}
else {
LOG_E("Could not read size or radius from " << config.getFilename());
}
mShape->setOrigin(sf::Vector2f(getSize().x / 2, getSize().y / 2));
mShape->setTextureRect(sf::IntRect(sf::Vector2i(0, 0), sf::Vector2i(getSize())));
mShape->setTexture(&*mTexture, false);
setPosition(data.position);
setAngle(data.angle);
}
/**
@ -37,18 +63,127 @@ Sprite::~Sprite() {
}
/**
* \copydoc sf::Drawable::draw
* Initializes container.
*/
Sprite::Data::Data(const sf::Vector2f& position, float angle,
Category category, unsigned short maskExclude) :
position(position),
angle(angle),
category(category),
mask(maskExclude) {
}
/**
* Returns the position of the sprite (center).
*/
sf::Vector2f
Sprite::getPosition() const {
return mShape->getPosition();
}
/**
* Returns the movement speed of the sprite.
*/
sf::Vector2f
Sprite::getSpeed() const {
return mSpeed;
}
/**
* Returns the angle of the sprite.
*/
float
Sprite::getAngle() const {
return mShape->getRotation();
}
/**
* Returns true if this object should be deleted.
*/
bool
Sprite::getDelete() const {
return mDelete;
}
/**
* Returns the Category of this object.
*/
Sprite::Category
Sprite::getCategory() const {
return mCategory;
}
/**
* Returns the size of the sprite as a vector (bottom left to top right),
* does not consider rotation.
*/
sf::Vector2f
Sprite::getSize() const {
sf::FloatRect bounds = mShape->getLocalBounds();
return sf::Vector2f(bounds.width, bounds.height);
}
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(sf::Vector2f(mSize));
shape.setTexture(&*mTexture, true);
shape.setOrigin(sf::Vector2f(mSize.x / 2, mSize.y / 2));
shape.setTextureRect(sf::IntRect(sf::Vector2i(0, 0), mSize));
shape.setPosition(getPosition());
shape.setRotation(getAngle());
target.draw(shape, states);
target.draw(*mShape, states);
}
/**
* This method filters collisions with other sprites. Implement it if you want to
* limit collisions to/with certain objects. Default implementation always returns true.
*
* @param other The Sprite this object is about to collide with.
* @return True if the objects should collide.
*/
bool
Sprite::doesCollide(Sprite& other) {
return true;
}
/**
* Called when a collision with another Sprite occured. Override this method
* to manage collision events.
*
* @param other The other Sprite in the collision.
*/
void
Sprite::onCollide(Sprite& other) {
}
/**
* Set to true to mark this object for deletion from the world.
*/
void
Sprite::setDelete(bool value) {
mDelete = value;
}
/**
* Sets movement speed and direction of the Sprite. Set either value to zero to stop movement.
*
* @param direction The direction the Sprite moves in, does not have to be normalized.
* @param speed Movement speed in pixels per second.
*/
void
Sprite::setSpeed(sf::Vector2f direction, float speed) {
if (direction != sf::Vector2f()) {
thor::setLength(direction, speed);
}
mSpeed = direction;
}
/**
* Sets the angle of the Sprite.
*/
void
Sprite::setAngle(float angle) {
mShape->setRotation(angle);
}
/**
* Sets the position of thr Sprite.
*/
void
Sprite::setPosition(const sf::Vector2f& position) {
mShape->setPosition(position);
}

82
source/abstract/Sprite.h Normal file → Executable file
View file

@ -1,46 +1,96 @@
/*
* Sprite.h
*
* Created on: 22.07.2012
* Created on: 11.08.2012
* Author: Felix
*/
#ifndef DG_SPRITE_H_
#define DG_SPRITE_H_
#include <SFML/System.hpp>
#include <SFML/Graphics.hpp>
#include <Thor/Resources.hpp>
#include "Body.h"
#include <string>
#include "../util/Yaml.h"
class Body;
class Yaml;
/**
* Represents a drawable object.
*
* Handles drawing to world.
* An sprite that is rendered in the world.
*/
class Sprite : public sf::Drawable, public Body {
class Sprite : public sf::Drawable {
// Public types.
public:
/**
* Categories of objects for filtering.
* The order of categories is also used for render order (higher number on top).
*/
enum Category {
CATEGORY_WORLD = 1 << 1,
CATEGORY_NONSOLID = 1 << 2,
CATEGORY_PARTICLE = 1 << 3,
CATEGORY_ACTOR = 1 << 4
};
/**
* Container that carries all data required to construct an object of this class.
*/
class Data {
public:
Data(const sf::Vector2f& position, float angle, Category category, unsigned short maskExclude);
const sf::Vector2f& position;
float angle;
Category category;
unsigned short mask;
};
/**
* Common collision masking values.
*/
enum Mask : unsigned short {
MASK_NONE = 0xffff, //< Disables any collisions.
MASK_ALL = 0 //< Enables all collisions.
};
// Public functions.
public:
Sprite(const Yaml& config, const Data& data, const sf::Vector2i& size = sf::Vector2i());
Sprite(const Data& data, const Yaml& config);
virtual ~Sprite() = 0;
sf::Vector2f getPosition() const;
sf::Vector2f getSpeed() const;
float getAngle() const;
bool getDelete() const;
Category getCategory() const;
sf::Vector2f getSize() const;
virtual void draw(sf::RenderTarget& target, sf::RenderStates states) const;
virtual bool doesCollide(Sprite& other);
virtual void onCollide(Sprite& other);
// Public variables.
public:
static const std::string KEY_SIZE;
static const std::string KEY_RADIUS;
static const std::string KEY_TEXTURE;
// Protected functions.
protected:
virtual void draw(sf::RenderTarget& target, sf::RenderStates states) const;
friend class World;
void setDelete(bool value);
void setSpeed(sf::Vector2f direction, float speed);
void setAngle(float angle);
void setPosition(const sf::Vector2f& position);
// Private variables.
private:
static const std::string KEY_TEXTURE;
static const std::string DEFAULT_TEXTURE;
std::unique_ptr<sf::Shape> mShape;
std::shared_ptr<sf::Texture> mTexture;
sf::Vector2i mSize;
sf::Vector2f mSpeed;
Category mCategory;
unsigned short mMask;
bool mDelete;
};
#endif /* DG_SPRITE_H_ */

View file

@ -25,7 +25,7 @@ const float Bullet::DEFAULT_SPEED = 500;
* @param world Box2d world.
* @param texture Texture to display for bullet.
*/
Bullet::Bullet(const sf::Vector2f& position, Body& shooter, float direction,
Bullet::Bullet(const sf::Vector2f& position, Sprite& shooter, float direction,
const Yaml& config) :
Particle(config, Data(position, 0, CATEGORY_PARTICLE, CATEGORY_PARTICLE)),
mShooter(shooter),
@ -41,7 +41,7 @@ Bullet::Bullet(const sf::Vector2f& position, Body& shooter, float direction,
* @copydoc Physical::onCollide
*/
void
Bullet::onCollide(Body& other) {
Bullet::onCollide(Sprite& other) {
// Make sure we do not damage twice.
if (!getDelete()) {
// Call onShot on other, with damage as param.
@ -54,6 +54,6 @@ Bullet::onCollide(Body& other) {
}
bool
Bullet::doesCollide(Body& other) {
Bullet::doesCollide(Sprite& other) {
return &other != &mShooter;
}

View file

@ -22,11 +22,11 @@ class Yaml;
class Bullet : public Particle {
// Public functions.
public:
Bullet(const sf::Vector2f& position, Body& shooter, float direction,
Bullet(const sf::Vector2f& position, Sprite& shooter, float direction,
const Yaml& config);
void onCollide(Body& other);
bool doesCollide(Body& other);
void onCollide(Sprite& other);
void doesCollide(Sprite& other);
// Private variables.
private:
@ -35,7 +35,7 @@ private:
static const std::string KEY_SPEED;
static const float DEFAULT_SPEED;
Body& mShooter;
Sprite& mShooter;
const int mDamage;
const float mSpeed;
};

View file

@ -19,15 +19,15 @@ const std::string Weapon::DEFAULT_BULLET = "bullet.yaml";
const std::string Weapon::KEY_INTERVAL = "interval";
const int Weapon::DEFAULT_INTERVAL = 250;
Weapon::Weapon(World& world, Body& holder, const Yaml& config) :
Weapon::Weapon(World& world, Sprite& holder, const Yaml& config) :
Emitter(world),
mWorld(world),
mHolder(holder),
mBullet(config.get(KEY_BULLET, DEFAULT_BULLET)),
mTimer(sf::milliseconds(config.get(KEY_INTERVAL, DEFAULT_INTERVAL))) {
sf::Vector2i holderSize = mHolder.getSize();
sf::Vector2f holderSize = mHolder.getSize();
Yaml bullet(mBullet);
sf::Vector2i bulletSize = bullet.get(Body::KEY_SIZE, sf::Vector2i());
sf::Vector2f bulletSize = bullet.get(Sprite::KEY_SIZE, sf::Vector2f());
mOffset = sf::Vector2f(0,
std::max(holderSize.x, holderSize.y) / 2 +
std::max(bulletSize.x, bulletSize.y) / 2);

View file

@ -10,14 +10,14 @@
#include <Thor/Particles.hpp>
#include "../abstract/Body.h"
#include "../abstract/Sprite.h"
#include "../particle/Emitter.h"
#include "../util/Timer.h"
#include "../util/Yaml.h"
class Emitter;
class Instances;
class Body;
class Sprite;
class Timer;
class Yaml;
@ -29,7 +29,7 @@ class Yaml;
class Weapon : public Emitter {
// Public functions.
public:
Weapon(World& world, Body& holder, const Yaml& config);
Weapon(World& world, Sprite& holder, const Yaml& config);
void fire();
@ -45,7 +45,7 @@ private:
static const int DEFAULT_INTERVAL;
World& mWorld;
Body& mHolder;
Sprite& mHolder;
sf::Vector2f mOffset; //< Offset to the point where bullets are inserted (from holder center).
const std::string mBullet;

View file

@ -8,11 +8,11 @@
#ifndef DG_EMITTER_H_
#define DG_EMITTER_H_
#include "../abstract/Body.h"
#include "../abstract/Sprite.h"
#include "../World.h"
#include "Particle.h"
class Body;
class Sprite;
class World;
class Particle;

View file

@ -8,7 +8,7 @@
#include "Particle.h"
Particle::Particle(const Yaml& config, const Data& data) :
Sprite(config, data) {
Sprite(data, config) {
}
Particle::~Particle() {

View file

@ -8,6 +8,6 @@
#include "Corpse.h"
Corpse::Corpse(const sf::Vector2f& position, const Yaml& config) :
Sprite(config, Data(position, 0, CATEGORY_NONSOLID, MASK_NONE)) {
Sprite(Data(position, 0, CATEGORY_NONSOLID, MASK_NONE), config) {
}

View file

@ -103,7 +103,7 @@ Player::onThink(float elapsedTime) {
* Stop movement if we collide with anything except bullets.
*/
void
Player::onCollide(Body& other) {
Player::onCollide(Sprite& other) {
if (other.getCategory() != CATEGORY_PARTICLE) {
setDestination(getPosition());
}

View file

@ -50,7 +50,7 @@ public:
// Private functions.
private:
void onCollide(Body& other);
void onCollide(Sprite& other);
void onThink(float elapsedTime);
// Private variables.

View file

@ -34,9 +34,9 @@ TileManager::TileManager(World& world) :
* @param world Box2D world object.
*/
TileManager::Tile::Tile(Type type, const TilePosition& position) :
Sprite(Yaml(getConfig(type)), Data(
sf::Vector2f(position.x * TILE_SIZE.x, position.y * TILE_SIZE.y), 0,
CATEGORY_WORLD, (type == Type::FLOOR) ? MASK_NONE : MASK_ALL)),
Sprite(Data(sf::Vector2f(position.x * TILE_SIZE.x, position.y * TILE_SIZE.y),
0, CATEGORY_WORLD, (type == Type::FLOOR) ? MASK_NONE : MASK_ALL),
Yaml(getConfig(type))),
mType(type) {
}

View file

@ -12,6 +12,6 @@ Pathfinder::Pathfinder() {
}
std::vector<sf::Vector2f>
Pathfinder::getPath(Body& physical, const sf::Vector2f& destination) {
Pathfinder::getPath(Sprite& physical, const sf::Vector2f& destination) {
return std::vector<sf::Vector2f>();
}

View file

@ -10,16 +10,16 @@
#include <SFML/System.hpp>
#include "../abstract/Body.h"
#include "../abstract/Sprite.h"
class Body;
class Sprite;
class Pathfinder {
// Public functions.
public:
Pathfinder();
std::vector<sf::Vector2f> getPath(Body& physical, const sf::Vector2f& destination);
std::vector<sf::Vector2f> getPath(Sprite& physical, const sf::Vector2f& destination);
};
#endif /* PATHFINDER_H_ */