Added Vector2 class to replace sf::Vector2, featuring comparison operator.
This commit is contained in:
parent
602cc605e8
commit
e469211e95
36 changed files with 271 additions and 230 deletions
|
@ -23,14 +23,14 @@ const int Game::FPS_GOAL = 60;
|
|||
*/
|
||||
Game::Game(tgui::Window& window) :
|
||||
mWindow(window),
|
||||
mWorldView(sf::Vector2f(0, 0), mWindow.getView().getSize()),
|
||||
mWorldView(Vector2f(0, 0), mWindow.getView().getSize()),
|
||||
mGenerator(mWorld, mPathfinder),
|
||||
mQuit(false),
|
||||
mPaused(false) {
|
||||
mWindow.setFramerateLimit(FPS_GOAL);
|
||||
mWindow.setKeyRepeatEnabled(false);
|
||||
|
||||
mGenerator.generateCurrentAreaIfNeeded(sf::Vector2f());
|
||||
mGenerator.generateCurrentAreaIfNeeded(Vector2f());
|
||||
mPlayer = std::shared_ptr<Player>(new Player(mWorld, mPathfinder,
|
||||
mGenerator.getPlayerSpawn()));
|
||||
mPlayer->setLeftGadget(std::shared_ptr<Gadget>(new Heal()));
|
||||
|
@ -221,9 +221,9 @@ Game::keyDown(const sf::Event& event) {
|
|||
/**
|
||||
* Converts a screen coordinate to a world coordinate.
|
||||
*/
|
||||
sf::Vector2<float>
|
||||
Vector2<float>
|
||||
Game::convertCoordinates(int x, int y) {
|
||||
return mWindow.mapPixelToCoords(sf::Vector2i(x, y), mWorldView);
|
||||
return mWindow.mapPixelToCoords(Vector2i(x, y), mWorldView);
|
||||
}
|
||||
|
||||
void
|
||||
|
|
|
@ -36,7 +36,7 @@ private:
|
|||
void mouseDown(const sf::Event& event);
|
||||
void mouseUp(const sf::Event& event);
|
||||
|
||||
sf::Vector2<float> convertCoordinates(int x, int y);
|
||||
Vector2<float> convertCoordinates(int x, int y);
|
||||
void updateGui();
|
||||
|
||||
private:
|
||||
|
|
|
@ -32,7 +32,7 @@ Pathfinder::astarArea(Area* start, Area* end) const {
|
|||
assert(start);
|
||||
assert(end);
|
||||
auto heuristic_cost_estimate = [](Area* start, Area* end) {
|
||||
return thor::length(sf::Vector2f(end->center - start->center));
|
||||
return thor::length(Vector2f(end->center - start->center));
|
||||
};
|
||||
|
||||
std::set<Area*> closed;
|
||||
|
@ -91,37 +91,37 @@ Pathfinder::astarArea(Area* start, Area* end) const {
|
|||
* @param radius Radius of the moving object.
|
||||
* @return Path from end to start (path from start to end in reverse order).
|
||||
*/
|
||||
std::vector<sf::Vector2f>
|
||||
Pathfinder::getPath(const sf::Vector2f& start, const sf::Vector2f& end,
|
||||
std::vector<Vector2f>
|
||||
Pathfinder::getPath(const Vector2f& start, const Vector2f& end,
|
||||
float radius) const {
|
||||
if (!getArea(end))
|
||||
return std::vector<sf::Vector2f>();
|
||||
return std::vector<Vector2f>();
|
||||
std::vector<Portal*> portals = astarArea(getArea(start), getArea(end));
|
||||
if (portals.empty())
|
||||
return std::vector<sf::Vector2f>();
|
||||
std::vector<sf::Vector2f> path;
|
||||
return std::vector<Vector2f>();
|
||||
std::vector<Vector2f> path;
|
||||
|
||||
path.push_back(end);
|
||||
for (auto p : portals) {
|
||||
// Find the point on the line of the portal closest to the previous point.
|
||||
sf::Vector2f startToEnd = sf::Vector2f(p->end - p->start);
|
||||
float percentage = thor::dotProduct(startToEnd, path.back() - sf::Vector2f(p->start)) /
|
||||
Vector2f startToEnd = Vector2f(p->end - p->start);
|
||||
float percentage = thor::dotProduct(startToEnd, path.back() - Vector2f(p->start)) /
|
||||
thor::squaredLength(startToEnd);
|
||||
sf::Vector2f point;
|
||||
Vector2f point;
|
||||
|
||||
if (percentage < 0 || percentage > 1.0f) {
|
||||
if (thor::squaredLength(sf::Vector2f(p->start) - path.back()) <
|
||||
thor::squaredLength(sf::Vector2f(p->end) - path.back())) {
|
||||
if (thor::squaredLength(Vector2f(p->start) - path.back()) <
|
||||
thor::squaredLength(Vector2f(p->end) - path.back())) {
|
||||
thor::setLength(startToEnd, WALL_DISTANCE_MULTIPLIER * radius);
|
||||
point = sf::Vector2f(p->start) + startToEnd;
|
||||
point = Vector2f(p->start) + startToEnd;
|
||||
}
|
||||
else {
|
||||
thor::setLength(startToEnd, WALL_DISTANCE_MULTIPLIER * radius);
|
||||
point = sf::Vector2f(p->end) - startToEnd;
|
||||
point = Vector2f(p->end) - startToEnd;
|
||||
}
|
||||
}
|
||||
else
|
||||
point = sf::Vector2f(p->start) + startToEnd * percentage;
|
||||
point = Vector2f(p->start) + startToEnd * percentage;
|
||||
|
||||
// Take two points on a line orthogonal to the portal.
|
||||
thor::setLength(startToEnd, radius);
|
||||
|
@ -148,7 +148,7 @@ Pathfinder::insertArea(const sf::FloatRect& rect) {
|
|||
rect.top * Tile::TILE_SIZE.y - Tile::TILE_SIZE.y / 2.0f,
|
||||
rect.width * Tile::TILE_SIZE.x,
|
||||
rect.height * Tile::TILE_SIZE.y);
|
||||
a.center = sf::Vector2f(a.area.left + a.area.width / 2,
|
||||
a.center = Vector2f(a.area.left + a.area.width / 2,
|
||||
a.area.top + a.area.height / 2);
|
||||
mAreas.push_back(a);
|
||||
}
|
||||
|
@ -174,8 +174,8 @@ Pathfinder::generatePortals() {
|
|||
.getOverlap(Interval::IntervalFromPoints(other.area.top,
|
||||
other.area.top + other.area.height));
|
||||
if (overlap.getLength() > 0) {
|
||||
portal.start = sf::Vector2f(other.area.left, overlap.start);
|
||||
portal.end = sf::Vector2f(other.area.left, overlap.end);
|
||||
portal.start = Vector2f(other.area.left, overlap.start);
|
||||
portal.end = Vector2f(other.area.left, overlap.end);
|
||||
it.portals.push_back(portal);
|
||||
}
|
||||
}
|
||||
|
@ -185,8 +185,8 @@ Pathfinder::generatePortals() {
|
|||
.getOverlap(Interval::IntervalFromPoints(other.area.top,
|
||||
other.area.top + other.area.height));
|
||||
if (overlap.getLength() > 0) {
|
||||
portal.start = sf::Vector2f(it.area.left, overlap.start);
|
||||
portal.end = sf::Vector2f(it.area.left, overlap.end);
|
||||
portal.start = Vector2f(it.area.left, overlap.start);
|
||||
portal.end = Vector2f(it.area.left, overlap.end);
|
||||
it.portals.push_back(portal);
|
||||
}
|
||||
}
|
||||
|
@ -196,8 +196,8 @@ Pathfinder::generatePortals() {
|
|||
.getOverlap(Interval::IntervalFromPoints(other.area.left,
|
||||
other.area.left + other.area.width));
|
||||
if (overlap.getLength() > 0) {
|
||||
portal.start = sf::Vector2f(overlap.start, other.area.top);
|
||||
portal.end = sf::Vector2f(overlap.end, other.area.top);
|
||||
portal.start = Vector2f(overlap.start, other.area.top);
|
||||
portal.end = Vector2f(overlap.end, other.area.top);
|
||||
it.portals.push_back(portal);
|
||||
}
|
||||
}
|
||||
|
@ -207,8 +207,8 @@ Pathfinder::generatePortals() {
|
|||
.getOverlap(Interval::IntervalFromPoints(other.area.left,
|
||||
other.area.left + other.area.width));
|
||||
if (overlap.getLength() > 0) {
|
||||
portal.start = sf::Vector2f(overlap.start, it.area.top);
|
||||
portal.end = sf::Vector2f(overlap.end, it.area.top);
|
||||
portal.start = Vector2f(overlap.start, it.area.top);
|
||||
portal.end = Vector2f(overlap.end, it.area.top);
|
||||
it.portals.push_back(portal);
|
||||
}
|
||||
}
|
||||
|
@ -220,7 +220,7 @@ Pathfinder::generatePortals() {
|
|||
* Returns the area where point is in.
|
||||
*/
|
||||
Pathfinder::Area*
|
||||
Pathfinder::getArea(const sf::Vector2f& point) const {
|
||||
Pathfinder::getArea(const Vector2f& point) const {
|
||||
for (auto& area : mAreas) {
|
||||
if (area.area.contains(point))
|
||||
// Make the return value non-const for convenience.
|
||||
|
@ -236,8 +236,8 @@ Pathfinder::getArea(const sf::Vector2f& point) const {
|
|||
void
|
||||
Pathfinder::draw(sf::RenderTarget& target, sf::RenderStates states) const {
|
||||
for (auto& area : mAreas) {
|
||||
sf::RectangleShape rect(sf::Vector2f(area.area.width, area.area.height));
|
||||
rect.setPosition(sf::Vector2f(area.area.left, area.area.top));
|
||||
sf::RectangleShape rect(Vector2f(area.area.width, area.area.height));
|
||||
rect.setPosition(Vector2f(area.area.left, area.area.top));
|
||||
rect.setFillColor(sf::Color(area.area.width * 30, 127, 0, 96));
|
||||
target.draw(rect);
|
||||
}
|
||||
|
|
|
@ -11,6 +11,8 @@
|
|||
#include <SFML/System.hpp>
|
||||
#include <SFML/Graphics.hpp>
|
||||
|
||||
#include "util/Vector.h"
|
||||
|
||||
/**
|
||||
* Used to find paths between points in the world.
|
||||
*
|
||||
|
@ -25,11 +27,11 @@ private:
|
|||
public:
|
||||
void insertArea(const sf::FloatRect& rect);
|
||||
void generatePortals();
|
||||
std::vector<sf::Vector2f> getPath(const sf::Vector2f& start,
|
||||
const sf::Vector2f& end, float radius) const;
|
||||
std::vector<Vector2f> getPath(const Vector2f& start,
|
||||
const Vector2f& end, float radius) const;
|
||||
|
||||
private:
|
||||
Area* getArea(const sf::Vector2f& point) const;
|
||||
Area* getArea(const Vector2f& point) const;
|
||||
std::vector<Portal*> astarArea(Area* start, Area* end) const;
|
||||
void draw(sf::RenderTarget& target, sf::RenderStates states) const;
|
||||
|
||||
|
@ -44,8 +46,8 @@ private:
|
|||
* Redundant data as portals are saved twice.
|
||||
*/
|
||||
struct Pathfinder::Portal {
|
||||
sf::Vector2f start;
|
||||
sf::Vector2f end;
|
||||
Vector2f start;
|
||||
Vector2f end;
|
||||
Area* area;
|
||||
};
|
||||
|
||||
|
@ -54,7 +56,7 @@ struct Pathfinder::Portal {
|
|||
*/
|
||||
struct Pathfinder::Area {
|
||||
sf::FloatRect area;
|
||||
sf::Vector2f center;
|
||||
Vector2f center;
|
||||
std::vector<Portal> portals;
|
||||
};
|
||||
|
||||
|
|
|
@ -52,7 +52,7 @@ World::remove(std::shared_ptr<Sprite> drawable) {
|
|||
* Returns all characters that are within maxDistance from position.
|
||||
*/
|
||||
std::vector<std::shared_ptr<Character> >
|
||||
World::getCharacters(const sf::Vector2f& position, float maxDistance) const {
|
||||
World::getCharacters(const Vector2f& position, float maxDistance) const {
|
||||
std::vector<std::shared_ptr<Character> > visible;
|
||||
for (const auto& it : mCharacters) {
|
||||
if (position == it->getPosition())
|
||||
|
@ -81,7 +81,7 @@ World::step(int elapsed) {
|
|||
it--;
|
||||
}
|
||||
// Don't run collision tests if sprite is not moving.
|
||||
else if ((*it)->getSpeed() != sf::Vector2f())
|
||||
else if ((*it)->getSpeed() != Vector2f())
|
||||
applyMovement(*it, elapsed);
|
||||
}
|
||||
}
|
||||
|
@ -93,7 +93,7 @@ World::step(int elapsed) {
|
|||
*/
|
||||
void
|
||||
World::applyMovement(std::shared_ptr<Sprite> sprite, int elapsed) {
|
||||
sf::Vector2f offset = sprite->getSpeed() * (elapsed / 1000.0f);
|
||||
Vector2f offset = sprite->getSpeed() * (elapsed / 1000.0f);
|
||||
for (auto w = mDrawables.begin(); w != mDrawables.end(); w++) {
|
||||
for (const auto& other : w->second) {
|
||||
if (sprite == other)
|
||||
|
@ -158,19 +158,19 @@ World::draw(sf::RenderTarget& target, sf::RenderStates states) const {
|
|||
* @return True if the ray was not blocked.
|
||||
*/
|
||||
bool
|
||||
World::raycast(const sf::Vector2f& lineStart,
|
||||
const sf::Vector2f& lineEnd) const {
|
||||
World::raycast(const Vector2f& lineStart,
|
||||
const Vector2f& lineEnd) const {
|
||||
assert(lineStart != lineEnd);
|
||||
sf::Vector2f lineCenter = lineStart + 0.5f * (lineEnd - lineStart);
|
||||
Vector2f lineCenter = lineStart + 0.5f * (lineEnd - lineStart);
|
||||
for (const auto& it : mDrawables.at(Sprite::Category::CATEGORY_WORLD)) {
|
||||
if (!it->collisionEnabled(Sprite::CATEGORY_ACTOR))
|
||||
continue;
|
||||
sf::Vector2f axis = it->getPosition() - lineCenter;
|
||||
if (axis == sf::Vector2f())
|
||||
Vector2f axis = it->getPosition() - lineCenter;
|
||||
if (axis == Vector2f())
|
||||
return false;
|
||||
|
||||
axis = thor::unitVector(axis);
|
||||
sf::Vector2f halfsize = it->getSize() / 2.0f;
|
||||
Vector2f halfsize = it->getSize() / 2.0f;
|
||||
float rectPosProjected = thor::dotProduct(axis, it->getPosition());
|
||||
float lineStartProjected = thor::dotProduct(axis, lineStart);
|
||||
float lineEndProjected = thor::dotProduct(axis, lineEnd);
|
||||
|
@ -180,7 +180,7 @@ World::raycast(const sf::Vector2f& lineStart,
|
|||
float rectHalfWidthProjected = std::max(
|
||||
abs(thor::dotProduct(axis, halfsize)),
|
||||
abs(thor::dotProduct(axis,
|
||||
sf::Vector2f(halfsize.x, -halfsize.y))));
|
||||
Vector2f(halfsize.x, -halfsize.y))));
|
||||
Interval line = Interval::IntervalFromPoints(lineStartProjected,
|
||||
lineEndProjected);
|
||||
Interval rect = Interval::IntervalFromRadius(rectPosProjected,
|
||||
|
@ -196,7 +196,7 @@ World::raycast(const sf::Vector2f& lineStart,
|
|||
* Returns the item closest to position after linear search.
|
||||
*/
|
||||
std::shared_ptr<Item>
|
||||
World::getNearestItem(const sf::Vector2f& position) const {
|
||||
World::getNearestItem(const Vector2f& position) const {
|
||||
std::shared_ptr<Item> closest;
|
||||
float distance = std::numeric_limits<float>::max();
|
||||
for (const auto& v : mDrawables) {
|
||||
|
|
|
@ -28,10 +28,10 @@ public:
|
|||
void step(int elapsed);
|
||||
void think(int elapsed);
|
||||
std::vector<std::shared_ptr<Character> >
|
||||
getCharacters(const sf::Vector2f& position, float maxDistance) const;
|
||||
bool raycast(const sf::Vector2f& lineStart,
|
||||
const sf::Vector2f& lineEnd) const;
|
||||
std::shared_ptr<Item> getNearestItem(const sf::Vector2f& position) const;
|
||||
getCharacters(const Vector2f& position, float maxDistance) const;
|
||||
bool raycast(const Vector2f& lineStart,
|
||||
const Vector2f& lineEnd) const;
|
||||
std::shared_ptr<Item> getNearestItem(const Vector2f& position) const;
|
||||
|
||||
private:
|
||||
|
||||
|
|
|
@ -23,7 +23,7 @@ const float Character::ITEM_PICKUP_MAX_DISTANCE_SQUARED = 2500.0f;
|
|||
/**
|
||||
* Saves pointer to this instance in static var for think().
|
||||
*/
|
||||
Character::Character(const sf::Vector2f& position, Category category,
|
||||
Character::Character(const Vector2f& position, Category category,
|
||||
unsigned short mask, const Yaml& config, World& world,
|
||||
Pathfinder& pathfinder) :
|
||||
Circle(position, category, mask, config),
|
||||
|
@ -133,7 +133,7 @@ Character::releaseTrigger() {
|
|||
* @return True if a path was found.
|
||||
*/
|
||||
bool
|
||||
Character::setDestination(const sf::Vector2f& destination) {
|
||||
Character::setDestination(const Vector2f& destination) {
|
||||
mPath = mPathfinder.getPath(getPosition(), destination, getRadius());
|
||||
return !mPath.empty();
|
||||
}
|
||||
|
@ -152,7 +152,7 @@ Character::move() {
|
|||
if (thor::length(mPath.back() - getPosition()) < POINT_REACHED_DISTANCE) {
|
||||
mPath.pop_back();
|
||||
if (mPath.empty())
|
||||
setSpeed(sf::Vector2f(), 0);
|
||||
setSpeed(Vector2f(), 0);
|
||||
}
|
||||
}
|
||||
|
||||
|
@ -168,7 +168,7 @@ Character::isMoving() const {
|
|||
* Tests if a target is visible from the current position.
|
||||
*/
|
||||
bool
|
||||
Character::isVisible(const sf::Vector2f& target) const {
|
||||
Character::isVisible(const Vector2f& target) const {
|
||||
return mWorld.raycast(getPosition(), target);
|
||||
}
|
||||
|
||||
|
@ -284,7 +284,6 @@ Character::pickUpItem() {
|
|||
mRightGadget = mLeftGadget;
|
||||
mLeftGadget = gadget;
|
||||
}
|
||||
// TODO: implement (or just make invisible?)
|
||||
mWorld.remove(item);
|
||||
}
|
||||
else {
|
||||
|
|
|
@ -31,7 +31,7 @@ public:
|
|||
static const float VISION_DISTANCE;
|
||||
|
||||
public:
|
||||
explicit Character(const sf::Vector2f& position, Category category,
|
||||
explicit Character(const Vector2f& position, Category category,
|
||||
unsigned short mask, const Yaml& config, World& world,
|
||||
Pathfinder& pathfinder);
|
||||
virtual ~Character() = 0;
|
||||
|
@ -45,9 +45,9 @@ protected:
|
|||
float getMovementSpeed() const;
|
||||
void pullTrigger();
|
||||
void releaseTrigger();
|
||||
bool setDestination(const sf::Vector2f& destination);
|
||||
bool setDestination(const Vector2f& destination);
|
||||
bool isMoving() const;
|
||||
bool isVisible(const sf::Vector2f& target) const;
|
||||
bool isVisible(const Vector2f& target) const;
|
||||
std::vector<std::shared_ptr<Character> > getCharacters() const;
|
||||
int getMagazineAmmo() const;
|
||||
int getTotalAmmo() const;
|
||||
|
@ -90,8 +90,8 @@ private:
|
|||
std::shared_ptr<Weapon> mActiveWeapon;
|
||||
std::shared_ptr<Gadget> mLeftGadget;
|
||||
std::shared_ptr<Gadget> mRightGadget;
|
||||
std::vector<sf::Vector2f> mPath; //< Contains nodes to reach a set destination.
|
||||
sf::Vector2f mLastPosition;
|
||||
std::vector<Vector2f> mPath; //< Contains nodes to reach a set destination.
|
||||
Vector2f mLastPosition;
|
||||
Faction mFaction;
|
||||
};
|
||||
|
||||
|
|
|
@ -10,10 +10,10 @@
|
|||
#include "Rectangle.h"
|
||||
#include "../util/Yaml.h"
|
||||
|
||||
Circle::Circle(const sf::Vector2f& position, Category category,
|
||||
Circle::Circle(const Vector2f& position, Category category,
|
||||
unsigned short mask, const Yaml& config,
|
||||
const sf::Vector2f& direction) :
|
||||
Sprite(position, category, mask, config.get("size", sf::Vector2f()),
|
||||
const Vector2f& direction) :
|
||||
Sprite(position, category, mask, config.get("size", Vector2f()),
|
||||
config.get("texture", std::string()), direction) {
|
||||
}
|
||||
|
||||
|
@ -23,7 +23,7 @@ Circle::Circle(const sf::Vector2f& position, Category category,
|
|||
*/
|
||||
bool
|
||||
Circle::testCollision(std::shared_ptr<Sprite> other,
|
||||
sf::Vector2f& offsetFirst, const sf::Vector2f& offsetSecond) {
|
||||
Vector2f& offsetFirst, const Vector2f& offsetSecond) {
|
||||
Rectangle* rect = dynamic_cast<Rectangle*>(other.get());
|
||||
Circle* circle = dynamic_cast<Circle*>(other.get());
|
||||
if (circle != nullptr)
|
||||
|
|
|
@ -18,13 +18,13 @@ class Yaml;
|
|||
*/
|
||||
class Circle : public CollisionModel, public Sprite {
|
||||
public:
|
||||
explicit Circle(const sf::Vector2f& position, Category category,
|
||||
explicit Circle(const Vector2f& position, Category category,
|
||||
unsigned short mask, const Yaml& config,
|
||||
const sf::Vector2f& direction = sf::Vector2f(0, 0));
|
||||
const Vector2f& direction = Vector2f(0, 0));
|
||||
virtual ~Circle() = default;
|
||||
|
||||
bool testCollision(std::shared_ptr<Sprite> other,
|
||||
sf::Vector2f& offsetFirst, const sf::Vector2f& offsetSecond);
|
||||
Vector2f& offsetFirst, const Vector2f& offsetSecond);
|
||||
float getRadius() const;
|
||||
};
|
||||
|
||||
|
|
|
@ -29,10 +29,10 @@ CollisionModel::~CollisionModel() {
|
|||
*/
|
||||
bool
|
||||
CollisionModel::testCollision(const Circle& circle, const Rectangle& rect,
|
||||
sf::Vector2f& offsetFirst, const sf::Vector2f& offsetSecond) {
|
||||
sf::Vector2f halfSize = rect.getSize() / 2.0f;
|
||||
sf::Vector2f rectNewPos = rect.getPosition() + offsetSecond;
|
||||
sf::Vector2f circleRotatedPos = circle.getPosition() + offsetFirst - rectNewPos;
|
||||
Vector2f& offsetFirst, const Vector2f& offsetSecond) {
|
||||
Vector2f halfSize = rect.getSize() / 2.0f;
|
||||
Vector2f rectNewPos = rect.getPosition() + offsetSecond;
|
||||
Vector2f circleRotatedPos = circle.getPosition() + offsetFirst - rectNewPos;
|
||||
circleRotatedPos = thor::rotatedVector(circleRotatedPos, -rect.mShape.getRotation());
|
||||
circleRotatedPos += rectNewPos;
|
||||
|
||||
|
@ -44,7 +44,7 @@ CollisionModel::testCollision(const Circle& circle, const Rectangle& rect,
|
|||
.getOverlap(Interval::IntervalFromRadius(rectNewPos.y, halfSize.y))
|
||||
.getLength();
|
||||
offsetFirst += ((circleRotatedPos.y > rectNewPos.y) ? 1.0f : - 1.0f) *
|
||||
thor::rotatedVector(sf::Vector2f(0, overlapY), rect.mShape.getRotation());
|
||||
thor::rotatedVector(Vector2f(0, overlapY), rect.mShape.getRotation());
|
||||
return overlapY > 0;
|
||||
}
|
||||
// Same here (just switched x/y).
|
||||
|
@ -55,14 +55,14 @@ CollisionModel::testCollision(const Circle& circle, const Rectangle& rect,
|
|||
.getOverlap(Interval::IntervalFromRadius(rectNewPos.x, halfSize.x))
|
||||
.getLength();
|
||||
offsetFirst += ((circleRotatedPos.x > rectNewPos.x) ? 1.0f : - 1.0f) *
|
||||
thor::rotatedVector(sf::Vector2f(overlapX, 0), rect.mShape.getRotation());
|
||||
thor::rotatedVector(Vector2f(overlapX, 0), rect.mShape.getRotation());
|
||||
return overlapX > 0;
|
||||
}
|
||||
// Test if the circle is colliding with a corner of the rectangle, using
|
||||
// the same method as circle-circle collision (distance to corner instead
|
||||
// of radius.
|
||||
else {
|
||||
sf::Vector2f axis(thor::unitVector(rectNewPos - circleRotatedPos));
|
||||
Vector2f axis(thor::unitVector(rectNewPos - circleRotatedPos));
|
||||
|
||||
// Use correct vector for corner projections (positive/negative
|
||||
// direction does not matter).
|
||||
|
@ -72,7 +72,7 @@ CollisionModel::testCollision(const Circle& circle, const Rectangle& rect,
|
|||
rectHalfSizeProjected = thor::dotProduct(axis, halfSize);
|
||||
else
|
||||
rectHalfSizeProjected = thor::dotProduct(axis,
|
||||
sf::Vector2f(halfSize.x, -halfSize.y));
|
||||
Vector2f(halfSize.x, -halfSize.y));
|
||||
|
||||
Interval projectedCircle = Interval::IntervalFromRadius(
|
||||
thor::dotProduct(axis, circleRotatedPos),
|
||||
|
@ -100,8 +100,8 @@ CollisionModel::testCollision(const Circle& circle, const Rectangle& rect,
|
|||
*/
|
||||
bool
|
||||
CollisionModel::testCollision(const Circle& first, const Circle& second,
|
||||
sf::Vector2f& offsetFirst, const sf::Vector2f& offsetSecond) {
|
||||
sf::Vector2f axis(thor::unitVector(second.getPosition() + offsetFirst -
|
||||
Vector2f& offsetFirst, const Vector2f& offsetSecond) {
|
||||
Vector2f axis(thor::unitVector(second.getPosition() + offsetFirst -
|
||||
(first.getPosition() + offsetSecond)));
|
||||
Interval projectedFirst = Interval::IntervalFromRadius(
|
||||
thor::dotProduct(axis, first.getPosition() + offsetFirst),
|
||||
|
@ -125,6 +125,6 @@ CollisionModel::testCollision(const Circle& first, const Circle& second,
|
|||
*/
|
||||
bool
|
||||
CollisionModel::testCollision(const Rectangle& first, const Rectangle& second,
|
||||
sf::Vector2f& offsetFirst, const sf::Vector2f& offsetSecond) {
|
||||
Vector2f& offsetFirst, const Vector2f& offsetSecond) {
|
||||
return false;
|
||||
}
|
||||
|
|
|
@ -11,7 +11,7 @@
|
|||
class Circle;
|
||||
class Rectangle;
|
||||
|
||||
#include <SFML/System.hpp>
|
||||
#include "../util/Vector.h"
|
||||
|
||||
/**
|
||||
* Abstract class providing helper functions to test for collisions between shapes.
|
||||
|
@ -24,11 +24,11 @@ public:
|
|||
|
||||
protected:
|
||||
static bool testCollision(const Circle& circle, const Rectangle& rect,
|
||||
sf::Vector2f& offsetFirst, const sf::Vector2f& offsetSecond);
|
||||
Vector2f& offsetFirst, const Vector2f& offsetSecond);
|
||||
static bool testCollision(const Circle& first, const Circle& second,
|
||||
sf::Vector2f& offsetFirst, const sf::Vector2f& offsetSecond);
|
||||
Vector2f& offsetFirst, const Vector2f& offsetSecond);
|
||||
static bool testCollision(const Rectangle& first, const Rectangle& second,
|
||||
sf::Vector2f& offsetFirst, const sf::Vector2f& offsetSecond);
|
||||
Vector2f& offsetFirst, const Vector2f& offsetSecond);
|
||||
};
|
||||
|
||||
#endif /* DG_COLLISIONMODEL_H_ */
|
||||
|
|
|
@ -10,10 +10,10 @@
|
|||
#include "Circle.h"
|
||||
#include "../util/Yaml.h"
|
||||
|
||||
Rectangle::Rectangle(const sf::Vector2f& position, Category category,
|
||||
Rectangle::Rectangle(const Vector2f& position, Category category,
|
||||
unsigned short mask, const Yaml& config,
|
||||
const sf::Vector2f& direction) :
|
||||
Sprite(position, category, mask, config.get("size", sf::Vector2f()),
|
||||
const Vector2f& direction) :
|
||||
Sprite(position, category, mask, config.get("size", Vector2f()),
|
||||
config.get("texture", std::string()), direction) {
|
||||
}
|
||||
|
||||
|
@ -23,7 +23,7 @@ Rectangle::Rectangle(const sf::Vector2f& position, Category category,
|
|||
*/
|
||||
bool
|
||||
Rectangle::testCollision(std::shared_ptr<Sprite> other,
|
||||
sf::Vector2f& offsetFirst, const sf::Vector2f& offsetSecond) {
|
||||
Vector2f& offsetFirst, const Vector2f& offsetSecond) {
|
||||
Rectangle* rect = dynamic_cast<Rectangle*>(other.get());
|
||||
Circle* circle = dynamic_cast<Circle*>(other.get());
|
||||
if (circle != nullptr)
|
||||
|
|
|
@ -18,13 +18,13 @@ class Yaml;
|
|||
*/
|
||||
class Rectangle : public CollisionModel, public Sprite {
|
||||
public:
|
||||
explicit Rectangle(const sf::Vector2f& position, Category category,
|
||||
explicit Rectangle(const Vector2f& position, Category category,
|
||||
unsigned short mask, const Yaml& config,
|
||||
const sf::Vector2f& direction = sf::Vector2f(0, 0));
|
||||
const Vector2f& direction = sf::Vector2f(0, 0));
|
||||
virtual ~Rectangle() = default;
|
||||
|
||||
bool testCollision(std::shared_ptr<Sprite> other,
|
||||
sf::Vector2f& offsetFirst, const sf::Vector2f& offsetSecond);
|
||||
Vector2f& offsetFirst, const Vector2f& offsetSecond);
|
||||
};
|
||||
|
||||
#endif /* DG_RECTANGLE_H_ */
|
||||
|
|
|
@ -13,14 +13,14 @@
|
|||
#include "../util/Log.h"
|
||||
#include "../util/ResourceManager.h"
|
||||
|
||||
Sprite::Sprite(const sf::Vector2f& position, Category category,
|
||||
unsigned short mask, const sf::Vector2f& size,
|
||||
const std::string& texture, const sf::Vector2f& direction) :
|
||||
Sprite::Sprite(const Vector2f& position, Category category,
|
||||
unsigned short mask, const Vector2f& size,
|
||||
const std::string& texture, const Vector2f& direction) :
|
||||
mCategory(category),
|
||||
mMask(mask) {
|
||||
mShape.setSize(size);
|
||||
mShape.setOrigin(size / 2.0f);
|
||||
mShape.setTextureRect(sf::IntRect(sf::Vector2i(), sf::Vector2i(size)));
|
||||
mShape.setTextureRect(sf::IntRect(Vector2i(), Vector2i(size)));
|
||||
setPosition(position);
|
||||
setDirection(direction);
|
||||
try {
|
||||
|
@ -37,7 +37,7 @@ Sprite::Sprite(const sf::Vector2f& position, Category category,
|
|||
/**
|
||||
* Returns the position of the sprite (center).
|
||||
*/
|
||||
sf::Vector2f
|
||||
Vector2f
|
||||
Sprite::getPosition() const {
|
||||
return mShape.getPosition();
|
||||
}
|
||||
|
@ -45,7 +45,7 @@ Sprite::getPosition() const {
|
|||
/**
|
||||
* Returns the movement speed of the sprite.
|
||||
*/
|
||||
sf::Vector2f
|
||||
Vector2f
|
||||
Sprite::getSpeed() const {
|
||||
return mSpeed;
|
||||
}
|
||||
|
@ -53,9 +53,9 @@ Sprite::getSpeed() const {
|
|||
/**
|
||||
* Returns the angle of the sprite.
|
||||
*/
|
||||
sf::Vector2f
|
||||
Vector2f
|
||||
Sprite::getDirection() const {
|
||||
return thor::rotatedVector(sf::Vector2f(0, - 1), mShape.getRotation());
|
||||
return thor::rotatedVector(Vector2f(0, - 1), mShape.getRotation());
|
||||
}
|
||||
|
||||
/**
|
||||
|
@ -78,10 +78,10 @@ Sprite::getCategory() const {
|
|||
* Returns the size of the sprite as a vector (bottom left to top right),
|
||||
* does not consider rotation.
|
||||
*/
|
||||
sf::Vector2f
|
||||
Vector2f
|
||||
Sprite::getSize() const {
|
||||
sf::FloatRect bounds = mShape.getLocalBounds();
|
||||
return sf::Vector2f(bounds.width, bounds.height);
|
||||
return Vector2f(bounds.width, bounds.height);
|
||||
}
|
||||
|
||||
void
|
||||
|
@ -127,8 +127,8 @@ Sprite::setDelete(bool value) {
|
|||
* @param speed Movement speed in pixels per second.
|
||||
*/
|
||||
void
|
||||
Sprite::setSpeed(sf::Vector2f direction, float speed) {
|
||||
if (direction != sf::Vector2f())
|
||||
Sprite::setSpeed(Vector2f direction, float speed) {
|
||||
if (direction != Vector2f())
|
||||
thor::setLength(direction, speed);
|
||||
mSpeed = direction;
|
||||
}
|
||||
|
@ -138,8 +138,8 @@ Sprite::setSpeed(sf::Vector2f direction, float speed) {
|
|||
* but is otherwise meaningless.
|
||||
*/
|
||||
void
|
||||
Sprite::setDirection(const sf::Vector2f& direction) {
|
||||
if (direction != sf::Vector2f())
|
||||
Sprite::setDirection(const Vector2f& direction) {
|
||||
if (direction != Vector2f())
|
||||
mShape.setRotation(thor::polarAngle(direction) + 90);
|
||||
}
|
||||
|
||||
|
@ -147,6 +147,6 @@ Sprite::setDirection(const sf::Vector2f& direction) {
|
|||
* Sets the position of thr Sprite.
|
||||
*/
|
||||
void
|
||||
Sprite::setPosition(const sf::Vector2f& position) {
|
||||
Sprite::setPosition(const Vector2f& position) {
|
||||
mShape.setPosition(position);
|
||||
}
|
||||
|
|
|
@ -12,6 +12,8 @@
|
|||
|
||||
#include <SFML/Graphics.hpp>
|
||||
|
||||
#include "../util/Vector.h"
|
||||
|
||||
/**
|
||||
* An sprite that is rendered in the world.
|
||||
*/
|
||||
|
@ -38,30 +40,30 @@ public:
|
|||
|
||||
// Public functions.
|
||||
public:
|
||||
explicit Sprite(const sf::Vector2f& position, Category category,
|
||||
unsigned short mask, const sf::Vector2f& size,
|
||||
const std::string& texture, const sf::Vector2f& direction);
|
||||
explicit Sprite(const Vector2f& position, Category category,
|
||||
unsigned short mask, const Vector2f& size,
|
||||
const std::string& texture, const Vector2f& direction);
|
||||
virtual ~Sprite() = default;
|
||||
|
||||
sf::Vector2f getPosition() const;
|
||||
sf::Vector2f getSpeed() const;
|
||||
sf::Vector2f getDirection() const;
|
||||
Vector2f getPosition() const;
|
||||
Vector2f getSpeed() const;
|
||||
Vector2f getDirection() const;
|
||||
bool getDelete() const;
|
||||
Category getCategory() const;
|
||||
sf::Vector2f getSize() const;
|
||||
Vector2f getSize() const;
|
||||
virtual void draw(sf::RenderTarget& target, sf::RenderStates states) const;
|
||||
bool collisionEnabled(Category category) const;
|
||||
bool isInside(const sf::FloatRect& rect) const;
|
||||
|
||||
virtual bool testCollision(std::shared_ptr<Sprite> other,
|
||||
sf::Vector2f& offsetFirst, const sf::Vector2f& offsetSecond) = 0;
|
||||
Vector2f& offsetFirst, const Vector2f& offsetSecond) = 0;
|
||||
virtual void onCollide(std::shared_ptr<Sprite> other);
|
||||
|
||||
protected:
|
||||
void setDelete(bool value);
|
||||
void setSpeed(sf::Vector2f direction, float speed);
|
||||
void setDirection(const sf::Vector2f& direction);
|
||||
void setPosition(const sf::Vector2f& position);
|
||||
void setSpeed(Vector2f direction, float speed);
|
||||
void setDirection(const Vector2f& direction);
|
||||
void setPosition(const Vector2f& position);
|
||||
|
||||
private:
|
||||
friend class CollisionModel;
|
||||
|
@ -69,7 +71,7 @@ private:
|
|||
|
||||
sf::RectangleShape mShape;
|
||||
std::shared_ptr<sf::Texture> mTexture;
|
||||
sf::Vector2f mSpeed;
|
||||
Vector2f mSpeed;
|
||||
Category mCategory;
|
||||
unsigned short mMask;
|
||||
bool mDelete = false;
|
||||
|
|
|
@ -20,8 +20,8 @@
|
|||
* @param world Box2d world.
|
||||
* @param texture Texture to display for bullet.
|
||||
*/
|
||||
Bullet::Bullet(const sf::Vector2f& position, Character& shooter,
|
||||
sf::Vector2f direction, const Yaml& config, float speed,
|
||||
Bullet::Bullet(const Vector2f& position, Character& shooter,
|
||||
Vector2f direction, const Yaml& config, float speed,
|
||||
float damage, float maxRange) :
|
||||
Circle(position, CATEGORY_PARTICLE, ~CATEGORY_PARTICLE,
|
||||
config, thor::rotatedVector(direction, -90.0f)),
|
||||
|
|
|
@ -18,8 +18,8 @@ class Yaml;
|
|||
*/
|
||||
class Bullet : public Circle {
|
||||
public:
|
||||
explicit Bullet(const sf::Vector2f& position, Character& shooter,
|
||||
sf::Vector2f direction, const Yaml& config, float speed,
|
||||
explicit Bullet(const Vector2f& position, Character& shooter,
|
||||
Vector2f direction, const Yaml& config, float speed,
|
||||
float damage, float maxRange);
|
||||
|
||||
void onCollide(std::shared_ptr<Sprite> other);
|
||||
|
@ -29,7 +29,7 @@ private:
|
|||
const int mDamage;
|
||||
const float mSpeed;
|
||||
const float mMaxRangeSquared;
|
||||
sf::Vector2f mStartPoint;
|
||||
Vector2f mStartPoint;
|
||||
};
|
||||
|
||||
#endif /* DG_BULLET_H_ */
|
||||
|
|
|
@ -37,27 +37,24 @@ Generator::Generator(World& world, Pathfinder& pathfinder) :
|
|||
* GENERATE_AREA_SIZE and GENERATE_AREA_RANGE).
|
||||
*/
|
||||
void
|
||||
Generator::generateCurrentAreaIfNeeded(const sf::Vector2f& playerPosition) {
|
||||
auto compare = [](const sf::Vector2i& a, const sf::Vector2i& b) {
|
||||
return a.x < b.x || (a.x == b.x && a.y < b.y);
|
||||
};
|
||||
std::map<sf::Vector2i, float, decltype(compare)> open(compare);
|
||||
std::set<sf::Vector2i, decltype(compare)> closed(compare);
|
||||
Generator::generateCurrentAreaIfNeeded(const Vector2f& playerPosition) {
|
||||
std::map<Vector2i, float> open;
|
||||
std::set<Vector2i> closed;
|
||||
|
||||
sf::Vector2i start((int) floor(playerPosition.x / Tile::TILE_SIZE.x),
|
||||
Vector2i start((int) floor(playerPosition.x / Tile::TILE_SIZE.x),
|
||||
(int) floor(playerPosition.y / Tile::TILE_SIZE.y));
|
||||
start /= GENERATE_AREA_SIZE;
|
||||
auto makePair = [&start](const sf::Vector2i& point) {
|
||||
return std::make_pair(point, thor::length(sf::Vector2f(point - start)));
|
||||
auto makePair = [&start](const Vector2i& point) {
|
||||
return std::make_pair(point, thor::length(Vector2f(point - start)));
|
||||
};
|
||||
|
||||
open.insert(makePair(start));
|
||||
while (!open.empty()) {
|
||||
auto intComp = [](const std::pair<sf::Vector2i, float>& left,
|
||||
const std::pair<sf::Vector2i, float>& right) {
|
||||
auto intComp = [](const std::pair<Vector2i, float>& left,
|
||||
const std::pair<Vector2i, float>& right) {
|
||||
return left.second < right.second;
|
||||
};
|
||||
sf::Vector2i current =
|
||||
Vector2i current =
|
||||
std::min_element(open.begin(), open.end(), intComp)->first;
|
||||
float distance = open[current];
|
||||
open.erase(current);
|
||||
|
@ -65,8 +62,8 @@ Generator::generateCurrentAreaIfNeeded(const sf::Vector2f& playerPosition) {
|
|||
if (!mGenerated[current.x][current.y] && distance <= GENERATE_AREA_RANGE) {
|
||||
mGenerated[current.x][current.y] = true;
|
||||
sf::IntRect area(current * GENERATE_AREA_SIZE -
|
||||
sf::Vector2i(GENERATE_AREA_SIZE, GENERATE_AREA_SIZE) / 2,
|
||||
sf::Vector2i(GENERATE_AREA_SIZE, GENERATE_AREA_SIZE));
|
||||
Vector2i(GENERATE_AREA_SIZE, GENERATE_AREA_SIZE) / 2,
|
||||
Vector2i(GENERATE_AREA_SIZE, GENERATE_AREA_SIZE));
|
||||
generateTiles(area);
|
||||
for (const auto& enemyPosition : getEnemySpawns(area)) {
|
||||
float distance = thor::length(enemyPosition - playerPosition);
|
||||
|
@ -76,14 +73,14 @@ Generator::generateCurrentAreaIfNeeded(const sf::Vector2f& playerPosition) {
|
|||
}
|
||||
}
|
||||
if (mGenerated[current.x][current.y] && distance <= GENERATE_AREA_RANGE) {
|
||||
if (closed.find(sf::Vector2i(current.x + 1, current.y)) == closed.end())
|
||||
open.insert(makePair(sf::Vector2i(current.x + 1, current.y)));
|
||||
if (closed.find(sf::Vector2i(current.x, current.y + 1)) == closed.end())
|
||||
open.insert(makePair(sf::Vector2i(current.x, current.y + 1)));
|
||||
if (closed.find(sf::Vector2i(current.x - 1, current.y)) == closed.end())
|
||||
open.insert(makePair(sf::Vector2i(current.x - 1, current.y)));
|
||||
if (closed.find(sf::Vector2i(current.x, current.y - 1)) == closed.end())
|
||||
open.insert(makePair(sf::Vector2i(current.x, current.y - 1)));
|
||||
if (closed.find(Vector2i(current.x + 1, current.y)) == closed.end())
|
||||
open.insert(makePair(Vector2i(current.x + 1, current.y)));
|
||||
if (closed.find(Vector2i(current.x, current.y + 1)) == closed.end())
|
||||
open.insert(makePair(Vector2i(current.x, current.y + 1)));
|
||||
if (closed.find(Vector2i(current.x - 1, current.y)) == closed.end())
|
||||
open.insert(makePair(Vector2i(current.x - 1, current.y)));
|
||||
if (closed.find(Vector2i(current.x, current.y - 1)) == closed.end())
|
||||
open.insert(makePair(Vector2i(current.x, current.y - 1)));
|
||||
}
|
||||
}
|
||||
}
|
||||
|
@ -94,16 +91,16 @@ Generator::generateCurrentAreaIfNeeded(const sf::Vector2f& playerPosition) {
|
|||
*
|
||||
* FIXME: Some nodes are selected more than once.
|
||||
*/
|
||||
std::vector<sf::Vector2i>
|
||||
Generator::createMinimalSpanningTree(const sf::Vector2i& start,
|
||||
std::vector<Vector2i>
|
||||
Generator::createMinimalSpanningTree(const Vector2i& start,
|
||||
const float limit) {
|
||||
std::vector<sf::Vector2i> open;
|
||||
std::vector<sf::Vector2i> selected;
|
||||
std::vector<Vector2i> open;
|
||||
std::vector<Vector2i> selected;
|
||||
open.push_back(start);
|
||||
float totalWeight = 0.0f;
|
||||
|
||||
while (totalWeight < limit) {
|
||||
sf::Vector2i current;
|
||||
Vector2i current;
|
||||
float minValue = std::numeric_limits<float>::max();
|
||||
for (auto& o : open) {
|
||||
if (mTileNoise.getNoise(o.x, o.y) + 1.0f < minValue) {
|
||||
|
@ -115,15 +112,15 @@ Generator::createMinimalSpanningTree(const sf::Vector2i& start,
|
|||
selected.push_back(current);
|
||||
totalWeight += minValue;
|
||||
|
||||
auto insertOnlyNew = [&open, &selected](const sf::Vector2i& v) {
|
||||
auto insertOnlyNew = [&open, &selected](const Vector2i& v) {
|
||||
if (std::find(open.begin(), open.end(), v) == open.end()
|
||||
&& std::find(selected.begin(), selected.end(), v) == selected.end())
|
||||
open.push_back(v);
|
||||
};
|
||||
insertOnlyNew(sf::Vector2i(current.x + 1, current.y));
|
||||
insertOnlyNew(sf::Vector2i(current.x, current.y + 1));
|
||||
insertOnlyNew(sf::Vector2i(current.x - 1, current.y));
|
||||
insertOnlyNew(sf::Vector2i(current.x, current.y - 1));
|
||||
insertOnlyNew(Vector2i(current.x + 1, current.y));
|
||||
insertOnlyNew(Vector2i(current.x, current.y + 1));
|
||||
insertOnlyNew(Vector2i(current.x - 1, current.y));
|
||||
insertOnlyNew(Vector2i(current.x, current.y - 1));
|
||||
}
|
||||
return selected;
|
||||
}
|
||||
|
@ -144,19 +141,19 @@ Generator::generateTiles(const sf::IntRect& area) {
|
|||
assert(area.width && !(area.width & (area.width - 1)));
|
||||
assert(area.height && !(area.height & (area.height - 1)));
|
||||
|
||||
sf::Vector2i start;
|
||||
Vector2i start;
|
||||
float minValue = std::numeric_limits<float>::max();
|
||||
|
||||
// Find lowest value for tree start.
|
||||
for (int x = area.left; x < area.left + area.width; x++)
|
||||
for (int y = area.top; y < area.top + area.height; y++) {
|
||||
if (mTileNoise.getNoise(x, y) + 1.0f < minValue) {
|
||||
start = sf::Vector2i(x, y);
|
||||
start = Vector2i(x, y);
|
||||
minValue = mTileNoise.getNoise(x, y) + 1.0f;
|
||||
}
|
||||
}
|
||||
|
||||
std::vector<sf::Vector2i> selected = createMinimalSpanningTree(start, 12.0f);
|
||||
std::vector<Vector2i> selected = createMinimalSpanningTree(start, 12.0f);
|
||||
|
||||
// For rooms, take minimum bounding box of spanning tree.
|
||||
|
||||
|
@ -191,22 +188,22 @@ Generator::generateTiles(const sf::IntRect& area) {
|
|||
*
|
||||
* @param area Area for which enemy spawns should be returned.
|
||||
*/
|
||||
std::vector<sf::Vector2f>
|
||||
std::vector<Vector2f>
|
||||
Generator::getEnemySpawns(const sf::IntRect& area) {
|
||||
auto compare = [](const sf::Vector2f& a, const sf::Vector2f& b) {
|
||||
auto compare = [](const Vector2f& a, const Vector2f& b) {
|
||||
return a.x < b.x || (a.x == b.x && a.y < b.y);
|
||||
};
|
||||
std::set<sf::Vector2f, decltype(compare)> ret(compare);
|
||||
std::set<Vector2f, decltype(compare)> ret(compare);
|
||||
for (int x = area.left; x < area.left + area.width; x++) {
|
||||
for (int y = area.top; y < area.top + area.height; y++) {
|
||||
if (mCharacterNoise.getNoise(x, y) < -0.85f) {
|
||||
sf::Vector2i tilePosition = findClosestFloor(sf::Vector2i(x, y));
|
||||
ret.insert(sf::Vector2f(tilePosition.x * Tile::TILE_SIZE.x,
|
||||
Vector2i tilePosition = findClosestFloor(Vector2i(x, y));
|
||||
ret.insert(Vector2f(tilePosition.x * Tile::TILE_SIZE.x,
|
||||
tilePosition.y * Tile::TILE_SIZE.y));
|
||||
}
|
||||
}
|
||||
}
|
||||
return std::vector<sf::Vector2f>(ret.begin(), ret.end());
|
||||
return std::vector<Vector2f>(ret.begin(), ret.end());
|
||||
}
|
||||
|
||||
/**
|
||||
|
@ -245,10 +242,10 @@ Generator::generateAreas(const sf::IntRect& area) {
|
|||
/**
|
||||
* Returns a valid position (floor) for the player to spawn at.
|
||||
*/
|
||||
sf::Vector2f
|
||||
Vector2f
|
||||
Generator::getPlayerSpawn() const {
|
||||
sf::Vector2i spawn = findClosestFloor(sf::Vector2i(0, 0));
|
||||
return sf::Vector2f(spawn.x * Tile::TILE_SIZE.x,
|
||||
Vector2i spawn = findClosestFloor(Vector2i(0, 0));
|
||||
return Vector2f(spawn.x * Tile::TILE_SIZE.x,
|
||||
spawn.y * Tile::TILE_SIZE.y);
|
||||
}
|
||||
|
||||
|
@ -258,25 +255,22 @@ Generator::getPlayerSpawn() const {
|
|||
* @warn Will fail if no floor tile has been generated yet.
|
||||
* @position Point to start search for a floor tile from.
|
||||
*/
|
||||
sf::Vector2i
|
||||
Generator::findClosestFloor(const sf::Vector2i& position) const {
|
||||
auto compare = [](const sf::Vector2i& a, const sf::Vector2i& b) {
|
||||
return a.x < b.x || (a.x == b.x && a.y < b.y);
|
||||
};
|
||||
std::map<sf::Vector2i, float, decltype(compare)> open(compare);
|
||||
std::set<sf::Vector2i, decltype(compare)> closed(compare);
|
||||
sf::Vector2i start = position;
|
||||
auto makePair = [&start](const sf::Vector2i& point) {
|
||||
return std::make_pair(point, thor::length(sf::Vector2f(point - start)));
|
||||
Vector2i
|
||||
Generator::findClosestFloor(const Vector2i& position) const {
|
||||
std::map<Vector2i, float> open;
|
||||
std::set<Vector2i> closed;
|
||||
Vector2i start = position;
|
||||
auto makePair = [&start](const Vector2i& point) {
|
||||
return std::make_pair(point, thor::length(Vector2f(point - start)));
|
||||
};
|
||||
|
||||
open.insert(makePair(start));
|
||||
while (!open.empty()) {
|
||||
auto intComp = [](const std::pair<sf::Vector2i, float>& left,
|
||||
const std::pair<sf::Vector2i, float>& right) {
|
||||
auto intComp = [](const std::pair<Vector2i, float>& left,
|
||||
const std::pair<Vector2i, float>& right) {
|
||||
return left.second < right.second;
|
||||
};
|
||||
sf::Vector2i current = std::min_element(open.begin(), open.end(), intComp)->first;
|
||||
Vector2i current = std::min_element(open.begin(), open.end(), intComp)->first;
|
||||
open.erase(current);
|
||||
closed.insert(current);
|
||||
if (mTiles.count(current.x) != 0 &&
|
||||
|
@ -285,17 +279,17 @@ Generator::findClosestFloor(const sf::Vector2i& position) const {
|
|||
return current;
|
||||
}
|
||||
else {
|
||||
if (closed.find(sf::Vector2i(current.x + 1, current.y)) == closed.end())
|
||||
open.insert(makePair(sf::Vector2i(current.x + 1, current.y)));
|
||||
if (closed.find(sf::Vector2i(current.x, current.y + 1)) == closed.end())
|
||||
open.insert(makePair(sf::Vector2i(current.x, current.y + 1)));
|
||||
if (closed.find(sf::Vector2i(current.x - 1, current.y)) == closed.end())
|
||||
open.insert(makePair(sf::Vector2i(current.x - 1, current.y)));
|
||||
if (closed.find(sf::Vector2i(current.x, current.y - 1)) == closed.end())
|
||||
open.insert(makePair(sf::Vector2i(current.x, current.y - 1)));
|
||||
if (closed.find(Vector2i(current.x + 1, current.y)) == closed.end())
|
||||
open.insert(makePair(Vector2i(current.x + 1, current.y)));
|
||||
if (closed.find(Vector2i(current.x, current.y + 1)) == closed.end())
|
||||
open.insert(makePair(Vector2i(current.x, current.y + 1)));
|
||||
if (closed.find(Vector2i(current.x - 1, current.y)) == closed.end())
|
||||
open.insert(makePair(Vector2i(current.x - 1, current.y)));
|
||||
if (closed.find(Vector2i(current.x, current.y - 1)) == closed.end())
|
||||
open.insert(makePair(Vector2i(current.x, current.y - 1)));
|
||||
}
|
||||
}
|
||||
// No floor tile found in the entire world.
|
||||
assert(false);
|
||||
return sf::Vector2i();
|
||||
return Vector2i();
|
||||
}
|
||||
|
|
|
@ -12,6 +12,7 @@
|
|||
|
||||
#include "../sprites/Tile.h"
|
||||
#include "SimplexNoise.h"
|
||||
#include "../util/Vector.h"
|
||||
|
||||
class World;
|
||||
class Pathfinder;
|
||||
|
@ -22,9 +23,9 @@ class Pathfinder;
|
|||
class Generator {
|
||||
public:
|
||||
explicit Generator(World& world, Pathfinder& pathfinder);
|
||||
void generateCurrentAreaIfNeeded(const sf::Vector2f& position);
|
||||
sf::Vector2f getPlayerSpawn() const;
|
||||
std::vector<sf::Vector2f> getEnemySpawns(const sf::IntRect& area);
|
||||
void generateCurrentAreaIfNeeded(const Vector2f& position);
|
||||
Vector2f getPlayerSpawn() const;
|
||||
std::vector<Vector2f> getEnemySpawns(const sf::IntRect& area);
|
||||
|
||||
private:
|
||||
typedef std::map<int, std::map<int, Tile::Type> > array;
|
||||
|
@ -32,9 +33,9 @@ private:
|
|||
private:
|
||||
void generateAreas(const sf::IntRect& area);
|
||||
void generateTiles(const sf::IntRect& area);
|
||||
sf::Vector2i findClosestFloor(const sf::Vector2i& position) const;
|
||||
std::vector<sf::Vector2i> createMinimalSpanningTree(
|
||||
const sf::Vector2i& start, const float limit);
|
||||
Vector2i findClosestFloor(const Vector2i& position) const;
|
||||
std::vector<Vector2i> createMinimalSpanningTree(
|
||||
const Vector2i& start, const float limit);
|
||||
|
||||
private:
|
||||
static const int GENERATE_AREA_SIZE;
|
||||
|
|
|
@ -9,18 +9,18 @@
|
|||
|
||||
#include "../World.h"
|
||||
|
||||
Item::Item(const sf::Vector2f& size, const std::string& texture) :
|
||||
Sprite(sf::Vector2f(), CATEGORY_NONSOLID, MASK_NONE, size, texture,
|
||||
sf::Vector2f()) {
|
||||
Item::Item(const Vector2f& size, const std::string& texture) :
|
||||
Sprite(Vector2f(), CATEGORY_NONSOLID, MASK_NONE, size, texture,
|
||||
Vector2f()) {
|
||||
}
|
||||
|
||||
void
|
||||
Item::drop(const sf::Vector2f& position) {
|
||||
Item::drop(const Vector2f& position) {
|
||||
setPosition(position);
|
||||
}
|
||||
|
||||
bool
|
||||
Item::testCollision(std::shared_ptr<Sprite> other,
|
||||
sf::Vector2f& offsetFirst, const sf::Vector2f& offsetSecond) {
|
||||
Vector2f& offsetFirst, const Vector2f& offsetSecond) {
|
||||
return false;
|
||||
}
|
||||
|
|
|
@ -14,12 +14,12 @@ class World;
|
|||
|
||||
class Item : public Sprite {
|
||||
public:
|
||||
Item(const sf::Vector2f& size, const std::string& texture);
|
||||
Item(const Vector2f& size, const std::string& texture);
|
||||
virtual ~Item() {};
|
||||
|
||||
void drop(const sf::Vector2f& position);
|
||||
void drop(const Vector2f& position);
|
||||
bool testCollision(std::shared_ptr<Sprite> other,
|
||||
sf::Vector2f& offsetFirst, const sf::Vector2f& offsetSecond);
|
||||
Vector2f& offsetFirst, const Vector2f& offsetSecond);
|
||||
};
|
||||
|
||||
#endif /* DG_ITEM_H_ */
|
||||
|
|
|
@ -20,7 +20,7 @@ Shield::onUse(Character& character) {
|
|||
mCharacter = &character;
|
||||
if (mRotatingShield)
|
||||
mRotatingShield->setDelete(true);
|
||||
sf::Vector2f offset = mCharacter->getDirection() * mCharacter->getRadius();
|
||||
Vector2f offset = mCharacter->getDirection() * mCharacter->getRadius();
|
||||
mRotatingShield = std::shared_ptr<RotatingShield>(
|
||||
new RotatingShield(mCharacter->getPosition() + offset));
|
||||
mCharacter->mWorld.insert(mRotatingShield);
|
||||
|
|
|
@ -14,7 +14,7 @@
|
|||
#include "../util/Yaml.h"
|
||||
|
||||
Weapon::Weapon(World& world, Character& holder, const Yaml& config) :
|
||||
Item(sf::Vector2f(80, 30), "weapon.png"),
|
||||
Item(Vector2f(80, 30), "weapon.png"),
|
||||
mWorld(world),
|
||||
mHolder(&holder),
|
||||
mName(config.get("name", std::string())),
|
||||
|
@ -154,15 +154,15 @@ Weapon::setHolder(Character& holder) {
|
|||
*/
|
||||
void
|
||||
Weapon::insertProjectile(float angle) {
|
||||
sf::Vector2f offset(mHolder->getDirection() * mHolder->getRadius());
|
||||
Vector2f offset(mHolder->getDirection() * mHolder->getRadius());
|
||||
|
||||
float spread = (mHolder->getSpeed() == sf::Vector2f())
|
||||
float spread = (mHolder->getSpeed() == Vector2f())
|
||||
? mSpread
|
||||
: mSpreadMoving;
|
||||
std::uniform_real_distribution<float> distribution(- spread, spread);
|
||||
angle += distribution(mGenerator) + 90.0f;
|
||||
|
||||
sf::Vector2f direction(thor::rotatedVector(mHolder->getDirection(), angle));
|
||||
Vector2f direction(thor::rotatedVector(mHolder->getDirection(), angle));
|
||||
|
||||
std::shared_ptr<Sprite> projectile(new Bullet(mHolder->getPosition() + offset,
|
||||
*mHolder, direction, mProjectile, mProjectileSpeed,
|
||||
|
|
|
@ -9,7 +9,7 @@
|
|||
|
||||
#include "../util/Yaml.h"
|
||||
|
||||
Corpse::Corpse(const sf::Vector2f& position) :
|
||||
Corpse::Corpse(const Vector2f& position) :
|
||||
Circle(position, CATEGORY_NONSOLID, MASK_NONE, Yaml("corpse.yaml")) {
|
||||
}
|
||||
|
||||
|
|
|
@ -12,7 +12,7 @@
|
|||
|
||||
class Corpse : public Circle {
|
||||
public:
|
||||
explicit Corpse(const sf::Vector2f& position);
|
||||
explicit Corpse(const Vector2f& position);
|
||||
};
|
||||
|
||||
#endif /* DG_CORPSE_H_ */
|
||||
|
|
|
@ -12,7 +12,7 @@
|
|||
#include "../util/Yaml.h"
|
||||
|
||||
Enemy::Enemy(World& world, Pathfinder& pathfinder,
|
||||
const sf::Vector2f& position) :
|
||||
const Vector2f& position) :
|
||||
Character(position, CATEGORY_ACTOR, MASK_ALL, Yaml("enemy.yaml"), world,
|
||||
pathfinder) {
|
||||
}
|
||||
|
@ -41,6 +41,6 @@ Enemy::onThink(int elapsed) {
|
|||
}
|
||||
else {
|
||||
releaseTrigger();
|
||||
setSpeed(sf::Vector2f(), 0);
|
||||
setSpeed(Vector2f(), 0);
|
||||
}
|
||||
}
|
||||
|
|
|
@ -15,7 +15,7 @@ class World;
|
|||
class Enemy : public Character {
|
||||
public:
|
||||
explicit Enemy(World& world, Pathfinder& pathfinder,
|
||||
const sf::Vector2f& position);
|
||||
const Vector2f& position);
|
||||
|
||||
private:
|
||||
virtual void onThink(int elapsed) override;
|
||||
|
|
|
@ -15,7 +15,7 @@
|
|||
* Initializes Sprite.
|
||||
*/
|
||||
Player::Player(World& world, Pathfinder& pathfinder,
|
||||
const sf::Vector2f& position) :
|
||||
const Vector2f& position) :
|
||||
Character(position, CATEGORY_ACTOR, MASK_ALL, Yaml("player.yaml"), world,
|
||||
pathfinder),
|
||||
mDirection(0) {
|
||||
|
@ -27,7 +27,7 @@ Player::Player(World& world, Pathfinder& pathfinder,
|
|||
* @param Absolute world coordinates of the crosshair.
|
||||
*/
|
||||
void
|
||||
Player::setCrosshairPosition(const sf::Vector2f& position) {
|
||||
Player::setCrosshairPosition(const Vector2f& position) {
|
||||
mCrosshairPosition = position - getPosition();
|
||||
}
|
||||
|
||||
|
@ -46,7 +46,7 @@ Player::setDirection(Direction direction, bool unset) {
|
|||
mDirection = mDirection | direction;
|
||||
|
||||
// Convert directions into a vector.
|
||||
sf::Vector2f dirVec(0, 0);
|
||||
Vector2f dirVec(0, 0);
|
||||
if (mDirection & Direction::RIGHT)
|
||||
dirVec.x += 1.0f;
|
||||
if (mDirection & Direction::LEFT)
|
||||
|
@ -59,7 +59,7 @@ Player::setDirection(Direction direction, bool unset) {
|
|||
}
|
||||
|
||||
void
|
||||
Player::setDestination(const sf::Vector2f& destination) {
|
||||
Player::setDestination(const Vector2f& destination) {
|
||||
mDirection = 0;
|
||||
Character::setDestination(destination);
|
||||
}
|
||||
|
|
|
@ -29,13 +29,13 @@ public:
|
|||
|
||||
public:
|
||||
explicit Player(World& world, Pathfinder& pathfinder,
|
||||
const sf::Vector2f& position);
|
||||
const Vector2f& position);
|
||||
|
||||
void setCrosshairPosition(const sf::Vector2f& position);
|
||||
void setCrosshairPosition(const Vector2f& position);
|
||||
using Character::pullTrigger;
|
||||
using Character::releaseTrigger;
|
||||
void setDirection(Direction direction, bool unset);
|
||||
void setDestination(const sf::Vector2f& destination);
|
||||
void setDestination(const Vector2f& destination);
|
||||
using Character::getMagazineAmmo;
|
||||
using Character::getTotalAmmo;
|
||||
using Character::getWeaponName;
|
||||
|
@ -56,7 +56,7 @@ private:
|
|||
void onThink(int elapsed) override;
|
||||
|
||||
private:
|
||||
sf::Vector2f mCrosshairPosition; //< Relative position of the point to fire at (mouse cursor).
|
||||
Vector2f mCrosshairPosition; //< Relative position of the point to fire at (mouse cursor).
|
||||
unsigned char mDirection; //< Current movement direction for direct control.
|
||||
};
|
||||
|
||||
|
|
|
@ -9,7 +9,7 @@
|
|||
|
||||
#include "../util/Yaml.h"
|
||||
|
||||
RotatingShield::RotatingShield(const sf::Vector2f& position) :
|
||||
RotatingShield::RotatingShield(const Vector2f& position) :
|
||||
Rectangle(position, CATEGORY_WORLD, MASK_ALL,
|
||||
Yaml("rotating_shield.yaml")) {
|
||||
}
|
||||
|
|
|
@ -12,7 +12,7 @@
|
|||
|
||||
class RotatingShield : public Rectangle {
|
||||
public:
|
||||
explicit RotatingShield(const sf::Vector2f& position);
|
||||
explicit RotatingShield(const Vector2f& position);
|
||||
|
||||
private:
|
||||
using Sprite::setDelete;
|
||||
|
|
|
@ -14,7 +14,7 @@
|
|||
#include "../util/Yaml.h"
|
||||
#include "../World.h"
|
||||
|
||||
const sf::Vector2i Tile::TILE_SIZE = sf::Vector2i(75, 75);
|
||||
const Vector2i Tile::TILE_SIZE = sf::Vector2i(75, 75);
|
||||
|
||||
/**
|
||||
* Constructs a tile.
|
||||
|
@ -24,7 +24,7 @@ const sf::Vector2i Tile::TILE_SIZE = sf::Vector2i(75, 75);
|
|||
* @param world Box2D world object.
|
||||
*/
|
||||
Tile::Tile(Type type, int x, int y) :
|
||||
Rectangle(sf::Vector2f(x * TILE_SIZE.x, y * TILE_SIZE.y),
|
||||
Rectangle(Vector2f(x * TILE_SIZE.x, y * TILE_SIZE.y),
|
||||
CATEGORY_WORLD, (isSolid(type)) ? 0xffff : 0,
|
||||
Yaml(getConfig(type))),
|
||||
mType(type) {
|
||||
|
|
|
@ -26,7 +26,7 @@ public:
|
|||
Type getType() const;
|
||||
|
||||
public:
|
||||
static const sf::Vector2i TILE_SIZE; //< Tile size in pixels.
|
||||
static const Vector2i TILE_SIZE; //< Tile size in pixels.
|
||||
|
||||
public:
|
||||
static std::string getConfig(Type type);
|
||||
|
|
44
source/util/Vector.h
Normal file
44
source/util/Vector.h
Normal file
|
@ -0,0 +1,44 @@
|
|||
/*
|
||||
* Vector.h
|
||||
*
|
||||
* Created on: 07.08.2013
|
||||
* Author: Felix
|
||||
*/
|
||||
|
||||
#ifndef DG_VECTOR_H_
|
||||
#define DG_VECTOR_H_
|
||||
|
||||
#include <SFML/System.hpp>
|
||||
|
||||
/**
|
||||
* Vector class with comparison operator. All other operators are inherited
|
||||
* from sf::Vector2.
|
||||
*/
|
||||
template <typename T>
|
||||
class Vector2 : public sf::Vector2<T> {
|
||||
public:
|
||||
Vector2() : sf::Vector2<T>() {};
|
||||
Vector2(T x, T y) : sf::Vector2<T>(x, y) {};
|
||||
/**
|
||||
* Implicitly catches and converts any vectors that have been converted to
|
||||
* sf::Vector2 (as done by arithmethic operations defined by sf::Vector2).
|
||||
*/
|
||||
template <typename U>
|
||||
Vector2(const sf::Vector2<U>& vector) : sf::Vector2<T>(vector) {};
|
||||
|
||||
};
|
||||
|
||||
/**
|
||||
* Comparison operator meant for containers like std::set.
|
||||
*
|
||||
* Provides a clearly defined, but otherwise meaningless sorting of vectors.
|
||||
*/
|
||||
template <typename T>
|
||||
bool operator <(const Vector2<T>& left, const Vector2<T>& right) {
|
||||
return left.x < right.x || (left.x == right.x && left.y < right.y);
|
||||
}
|
||||
|
||||
typedef Vector2<int> Vector2i;
|
||||
typedef Vector2<float> Vector2f;
|
||||
|
||||
#endif /* DG_VECTOR_H_ */
|
|
@ -13,9 +13,8 @@
|
|||
|
||||
#include <yaml-cpp/yaml.h>
|
||||
|
||||
#include <SFML/System.hpp>
|
||||
|
||||
#include "Log.h"
|
||||
#include "Vector.h"
|
||||
|
||||
/**
|
||||
* Interface to a YAML file.
|
||||
|
@ -45,12 +44,12 @@ private:
|
|||
* Error handling is done in Yaml::get.
|
||||
*/
|
||||
namespace {
|
||||
void operator>>(const YAML::Node& node, sf::Vector2i& vector) {
|
||||
void operator>>(const YAML::Node& node, Vector2i& vector) {
|
||||
node[0] >> vector.x;
|
||||
node[1] >> vector.y;
|
||||
}
|
||||
|
||||
void operator>>(const YAML::Node& node, sf::Vector2f& vector) {
|
||||
void operator>>(const YAML::Node& node, Vector2f& vector) {
|
||||
node[0] >> vector.x;
|
||||
node[1] >> vector.y;
|
||||
}
|
||||
|
|
Reference in a new issue