diff --git a/source/Game.cpp b/source/Game.cpp index 5e9663e..d2fd462 100644 --- a/source/Game.cpp +++ b/source/Game.cpp @@ -27,9 +27,9 @@ Game::Game(sf::RenderWindow& window) : mWindow.setKeyRepeatEnabled(true); Generator generator; - generator.generateTiles(mTileManager, mWorld, + generator.generateTiles(mTileManager, mPathfinder, sf::IntRect(-32, -32, 64, 64)); - mPlayer = std::shared_ptr(new Player(mWorld, mTileManager, + mPlayer = std::shared_ptr(new Player(mWorld, mTileManager, mPathfinder, sf::Vector2f(0.0f, 0.0f), Yaml("player.yaml"))); mWorld.insertCharacter(mPlayer); } diff --git a/source/Game.h b/source/Game.h index 1f4a520..9995c2d 100644 --- a/source/Game.h +++ b/source/Game.h @@ -9,9 +9,11 @@ #define DG_GAME_H_ #include "sprites/TileManager.h" +#include "Pathfinder.h" #include "World.h" class TileManager; +class Pathfinder; class Player; class World; @@ -46,6 +48,7 @@ private: World mWorld; TileManager mTileManager; + Pathfinder mPathfinder; std::shared_ptr mPlayer; bool mQuit; diff --git a/source/Pathfinder.cpp b/source/Pathfinder.cpp new file mode 100644 index 0000000..639eec9 --- /dev/null +++ b/source/Pathfinder.cpp @@ -0,0 +1,242 @@ +/* + * Pathfinder.cpp + * + * Created on: 28.04.2013 + * Author: Felix + */ + +#include "Pathfinder.h" + +#include +#include +#include + +#include + +#include "util/Interval.h" +#include "sprites/TileManager.h" + +const float Pathfinder::WALL_DISTANCE_MULTIPLIER = 1.5f; + +/** + * Runs the A* path finding algorithm with areas as nodes and portals as edges. + * + * @warning Areas and portals must not be changed while this is running. + * + * @param start The area to start the path finding from. Must not be null. + * @param end The goal to reach. Must not be null. + * @return Path in reverse order (start being the last item and end the first). + */ +std::vector +Pathfinder::astarArea(Area* start, Area* end) const { + assert(start); + assert(end); + + std::unordered_set closed; + std::unordered_map openAreasEstimatedCost; + // Navigated areas with previous area/portal. + std::unordered_map> previousAreaAndPortal; + std::unordered_map bestPathCost; + + openAreasEstimatedCost[start] = heuristic_cost_estimate(start, end); + bestPathCost[start] = 0; + + while (!openAreasEstimatedCost.empty()) { + Area* current = std::min_element(openAreasEstimatedCost.begin(), + openAreasEstimatedCost.end())->first; + if (current == end) { + std::vector path; + auto previous = current; + while (previous != start) { + path.push_back(previousAreaAndPortal[previous].second); + previous = previousAreaAndPortal[previous].first; + } + return path; + } + + openAreasEstimatedCost.erase(current); + closed.insert(current); + for (Portal& portal : current->portals) { + Area* neighbor = portal.area; + float tentative_g_score = bestPathCost[current] + + heuristic_cost_estimate(current,neighbor); + if (closed.find(neighbor) != closed.end()) { + if (tentative_g_score >= bestPathCost[neighbor]) + continue; + } + + if ((openAreasEstimatedCost.find(neighbor) == + openAreasEstimatedCost.end()) || + (tentative_g_score < bestPathCost[neighbor])) { + previousAreaAndPortal[neighbor] = std::make_pair(current, + &portal); + bestPathCost[neighbor] = tentative_g_score; + openAreasEstimatedCost[neighbor] = bestPathCost[neighbor] + + heuristic_cost_estimate(neighbor, end); + } + } + } + return std::vector(); +} + +/** + * Returns path in reverse order. + * + * @warning Areas and portals must not be changed while this running. + * + * @param start Position to start the path from. + * @param end Position to move to. + * @param radius Radius of the moving object. + * @return Path from end to start (path from start to end in reverse order). + */ +std::vector +Pathfinder::getPath(const sf::Vector2f& start, const sf::Vector2f& end, + float radius) const { + if (!getArea(end)) + return std::vector(); + std::vector portals = astarArea(getArea(start), getArea(end)); + if (portals.empty()) + return std::vector(); + std::vector 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)) / + thor::squaredLength(startToEnd); + sf::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())) { + thor::setLength(startToEnd, WALL_DISTANCE_MULTIPLIER * radius); + point = sf::Vector2f(p->start) + startToEnd; + } + else { + thor::setLength(startToEnd, WALL_DISTANCE_MULTIPLIER * radius); + point = sf::Vector2f(p->end) - startToEnd; + } + } + else + point = sf::Vector2f(p->start) + startToEnd * percentage; + + // Take two points on a line orthogonal to the portal. + thor::setLength(startToEnd, radius); + startToEnd = thor::perpendicularVector(startToEnd); + path.push_back(point + startToEnd); + path.push_back(point - startToEnd); + // Make sure the points are in the right order. + if (thor::squaredLength(*(path.end() - 1) - *(path.end() - 3) ) < + thor::squaredLength(*(path.end() - 2) - *(path.end() - 3) )) + std::swap(*(path.end() - 1), *(path.end() - 2)); + } + return path; +} + +/** + * Returns the linear distance between two areas (using their center). + */ +float +Pathfinder::heuristic_cost_estimate(Area* start, Area* end) const { + return thor::length(sf::Vector2f(end->center - start->center)); +} + +bool Pathfinder::Portal::operator==(const Portal& p) { + return start == p.start && end == p.end && area == p.area; +} + +/** + * Inserts an area used for path finding. + * + * @parm rect Rectangle the area covers. + */ +void +Pathfinder::insertArea(const sf::IntRect& rect) { + Area a; + // Not sure why the offset of -50 is required, but with it, areas align + // with tiles perfectly. + a.area = sf::IntRect(rect.left * TileManager::TILE_SIZE.x - 50, + rect.top * TileManager::TILE_SIZE.y - 50, + rect.width * TileManager::TILE_SIZE.x, + rect.height * TileManager::TILE_SIZE.y); + a.center = sf::Vector2i(a.area.left + a.area.width / 2, + a.area.top + a.area.height / 2); + mAreas.push_back(a); +} + +/** + * Generates portals that connect areas. Needs to be run after insertArea for + * path finding to work. + */ +void +Pathfinder::generatePortals() { + for (Area& it : mAreas) { + // We currently recreate portals for all existing areas, so we have + // to clear in case this was already generated. + it.portals.clear(); + for (Area& other : mAreas) { + if (&it == &other) + continue; + Portal portal; + portal.area = &other; + if (it.area.left + it.area.width == other.area.left) { + Interval overlap = Interval::IntervalFromPoints(it.area.top, + it.area.top + it.area.height) + .getOverlap(Interval::IntervalFromPoints(other.area.top, + other.area.top + other.area.height)); + if (overlap.getLength() > 0) { + portal.start = sf::Vector2i(other.area.left, overlap.start); + portal.end = sf::Vector2i(other.area.left, overlap.end); + it.portals.push_back(portal); + } + } + if (other.area.left + other.area.width == it.area.left) { + Interval overlap = Interval::IntervalFromPoints(it.area.top, + it.area.top + it.area.height) + .getOverlap(Interval::IntervalFromPoints(other.area.top, + other.area.top + other.area.height)); + if (overlap.getLength() > 0) { + portal.start = sf::Vector2i(it.area.left, overlap.start); + portal.end = sf::Vector2i(it.area.left, overlap.end); + it.portals.push_back(portal); + } + } + else if (it.area.top + it.area.height == other.area.top) { + Interval overlap = Interval::IntervalFromPoints(it.area.left, + it.area.left + it.area.width) + .getOverlap(Interval::IntervalFromPoints(other.area.left, + other.area.left + other.area.width)); + if (overlap.getLength() > 0) { + portal.start = sf::Vector2i(overlap.start, other.area.top); + portal.end = sf::Vector2i(overlap.end, other.area.top); + it.portals.push_back(portal); + } + } + else if (other.area.top + other.area.height == it.area.top) { + Interval overlap = Interval::IntervalFromPoints(it.area.left, + it.area.left + it.area.width) + .getOverlap(Interval::IntervalFromPoints(other.area.left, + other.area.left + other.area.width)); + if (overlap.getLength() > 0) { + portal.start = sf::Vector2i(overlap.start, it.area.top); + portal.end = sf::Vector2i(overlap.end, it.area.top); + it.portals.push_back(portal); + } + } + } + } +} + +/** + * Returns the area where point is in. + */ +Pathfinder::Area* +Pathfinder::getArea(const sf::Vector2f& point) const { + for (auto& area : mAreas) { + if (sf::FloatRect(area.area).contains(point)) + // Make the return value non-const for convenience. + return &const_cast(area); + } + return nullptr; +} diff --git a/source/Pathfinder.h b/source/Pathfinder.h new file mode 100644 index 0000000..4138ba0 --- /dev/null +++ b/source/Pathfinder.h @@ -0,0 +1,57 @@ +/* + * Pathfinder.h + * + * Created on: 28.04.2013 + * Author: Felix + */ + +#ifndef DG_PATHFINDER_H_ +#define DG_PATHFINDER_H_ + +#include +#include + +class Pathfinder { +private: + struct Area; + struct Portal; + +public: + void insertArea(const sf::IntRect& rect); + void generatePortals(); + std::vector getPath(const sf::Vector2f& start, + const sf::Vector2f& end, float radius) const; + +private: + Area* getArea(const sf::Vector2f& point) const; + float heuristic_cost_estimate(Area* start, Area* end) const; + std::vector astarArea(Area* start, Area* end) const; + +private: + static const float WALL_DISTANCE_MULTIPLIER; + std::vector mAreas; //< This has to be a vector as objects are compared by address. +}; + +/** + * Edges + * + * Redundant data as portals are saved twice. + */ +struct Pathfinder::Portal { + Portal() = default; + bool operator==(const Portal& p); + sf::Vector2i start; + sf::Vector2i end; + Area* area; +}; + +/** + * Nodes + */ +struct Pathfinder::Area { + sf::IntRect area; + sf::Vector2i center; + std::vector portals; +}; + +#endif /* DG_PATHFINDER_H_ */ diff --git a/source/World.cpp b/source/World.cpp index 851ac86..a87ea89 100755 --- a/source/World.cpp +++ b/source/World.cpp @@ -7,16 +7,11 @@ #include "World.h" -#include -#include -#include - #include -#include "util/Interval.h" #include "sprites/TileManager.h" +#include "util/Interval.h" -const float World::WALL_DISTANCE_MULTIPLIER = 1.5f; /** * 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. @@ -45,122 +40,6 @@ World::insertCharacter(std::shared_ptr character) { insert(character); } -/** - * Runs the A* path finding algorithm with areas as nodes and portals as edges. - * - * @warning Areas and portals must not be changed while this is running. - * - * @param start The area to start the path finding from. Must not be null. - * @param end The goal to reach. Must not be null. - * @return Path in reverse order (start being the last item and end the first). - */ -std::vector -World::astarArea(Area* start, Area* end) const { - assert(start); - assert(end); - - std::unordered_set closed; - std::unordered_map openAreasEstimatedCost; - // Navigated areas with previous area/portal. - std::unordered_map> previousAreaAndPortal; - std::unordered_map bestPathCost; - - openAreasEstimatedCost[start] = heuristic_cost_estimate(start, end); - bestPathCost[start] = 0; - - while (!openAreasEstimatedCost.empty()) { - Area* current = std::min_element(openAreasEstimatedCost.begin(), - openAreasEstimatedCost.end())->first; - if (current == end) { - std::vector path; - auto previous = current; - while (previous != start) { - path.push_back(previousAreaAndPortal[previous].second); - previous = previousAreaAndPortal[previous].first; - } - return path; - } - - openAreasEstimatedCost.erase(current); - closed.insert(current); - for (Portal& portal : current->portals) { - Area* neighbor = portal.area; - float tentative_g_score = bestPathCost[current] + - heuristic_cost_estimate(current,neighbor); - if (closed.find(neighbor) != closed.end()) { - if (tentative_g_score >= bestPathCost[neighbor]) - continue; - } - - if ((openAreasEstimatedCost.find(neighbor) == - openAreasEstimatedCost.end()) || - (tentative_g_score < bestPathCost[neighbor])) { - previousAreaAndPortal[neighbor] = std::make_pair(current, - &portal); - bestPathCost[neighbor] = tentative_g_score; - openAreasEstimatedCost[neighbor] = bestPathCost[neighbor] + - heuristic_cost_estimate(neighbor, end); - } - } - } - return std::vector(); -} - -/** - * Returns path in reverse order. - * - * @warning Areas and portals must not be changed while this running. - * - * @param start Position to start the path from. - * @param end Position to move to. - * @param radius Radius of the moving object. - * @return Path from end to start (path from start to end in reverse order). - */ -std::vector -World::getPath(const sf::Vector2f& start, const sf::Vector2f& end, - float radius) const { - if (!getArea(end)) - return std::vector(); - std::vector portals = astarArea(getArea(start), getArea(end)); - if (portals.empty()) - return std::vector(); - std::vector 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)) / - thor::squaredLength(startToEnd); - sf::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())) { - thor::setLength(startToEnd, WALL_DISTANCE_MULTIPLIER * radius); - point = sf::Vector2f(p->start) + startToEnd; - } - else { - thor::setLength(startToEnd, WALL_DISTANCE_MULTIPLIER * radius); - point = sf::Vector2f(p->end) - startToEnd; - } - } - else - point = sf::Vector2f(p->start) + startToEnd * percentage; - - // Take two points on a line orthogonal to the portal. - thor::setLength(startToEnd, radius); - startToEnd = thor::perpendicularVector(startToEnd); - path.push_back(point + startToEnd); - path.push_back(point - startToEnd); - // Make sure the points are in the right order. - if (thor::squaredLength(*(path.end() - 1) - *(path.end() - 3) ) < - thor::squaredLength(*(path.end() - 2) - *(path.end() - 3) )) - std::swap(*(path.end() - 1), *(path.end() - 2)); - } - return path; -} - /** * Returns all characters that are within maxDistance from position. */ @@ -177,23 +56,6 @@ std::vector > return visible; } -/** - * Initializes start and end of an area, sets area to null. - */ -World::Portal::Portal(const sf::Vector2i& start, const sf::Vector2i& end) : - start(start), - end(end), - area(nullptr) { -} - -/** - * Returns the linear distance between two areas (using their center). - */ -float -World::heuristic_cost_estimate(Area* start, Area* end) const { - return thor::length(sf::Vector2f(end->center - start->center)); -} - /** * Checks for collisions and applies movement, also removes sprites if * Sprite::getDelete returns true. @@ -257,90 +119,6 @@ World::think(int elapsed) { } } -/** - * Inserts an area used for path finding. - * - * @parm rect Rectangle the area covers. - */ -void -World::insertArea(const sf::IntRect& rect) { - Area a; - // Not sure why the offset of -50 is required, but with it, areas align - // with tiles perfectly. - a.area = sf::IntRect(rect.left * TileManager::TILE_SIZE.x - 50, - rect.top * TileManager::TILE_SIZE.y - 50, - rect.width * TileManager::TILE_SIZE.x, - rect.height * TileManager::TILE_SIZE.y); - a.center = sf::Vector2i(a.area.left + a.area.width / 2, - a.area.top + a.area.height / 2); - mAreas.push_back(a); -} - -/** - * Generates portals that connect areas. Needs to be run after insertArea for - * path finding to work. - * - * Could be improved by only checking nearby areas. - */ -void -World::generatePortals() { - for (Area& it : mAreas) { - // We currently recreate portals for all existing areas, so we have - // to clear in case this was already generated. - it.portals.clear(); - for (Area& other : mAreas) { - if (&it == &other) - continue; - Portal portal; - portal.area = &other; - if (it.area.left + it.area.width == other.area.left) { - Interval overlap = Interval::IntervalFromPoints(it.area.top, - it.area.top + it.area.height) - .getOverlap(Interval::IntervalFromPoints(other.area.top, - other.area.top + other.area.height)); - if (overlap.getLength() > 0) { - portal.start = sf::Vector2i(other.area.left, overlap.start); - portal.end = sf::Vector2i(other.area.left, overlap.end); - it.portals.push_back(portal); - } - } - if (other.area.left + other.area.width == it.area.left) { - Interval overlap = Interval::IntervalFromPoints(it.area.top, - it.area.top + it.area.height) - .getOverlap(Interval::IntervalFromPoints(other.area.top, - other.area.top + other.area.height)); - if (overlap.getLength() > 0) { - portal.start = sf::Vector2i(it.area.left, overlap.start); - portal.end = sf::Vector2i(it.area.left, overlap.end); - it.portals.push_back(portal); - } - } - else if (it.area.top + it.area.height == other.area.top) { - Interval overlap = Interval::IntervalFromPoints(it.area.left, - it.area.left + it.area.width) - .getOverlap(Interval::IntervalFromPoints(other.area.left, - other.area.left + other.area.width)); - if (overlap.getLength() > 0) { - portal.start = sf::Vector2i(overlap.start, other.area.top); - portal.end = sf::Vector2i(overlap.end, other.area.top); - it.portals.push_back(portal); - } - } - else if (other.area.top + other.area.height == it.area.top) { - Interval overlap = Interval::IntervalFromPoints(it.area.left, - it.area.left + it.area.width) - .getOverlap(Interval::IntervalFromPoints(other.area.left, - other.area.left + other.area.width)); - if (overlap.getLength() > 0) { - portal.start = sf::Vector2i(overlap.start, it.area.top); - portal.end = sf::Vector2i(overlap.end, it.area.top); - it.portals.push_back(portal); - } - } - } - } -} - /** * Tests for collisions using Seperating Axis Theorem (SAT). * @@ -448,20 +226,6 @@ World::testCollision(std::shared_ptr spriteA, return false; } -/** - * Returns the area where point is in. - * Just iterates through all areas and tests each. - */ -World::Area* -World::getArea(const sf::Vector2f& point) const { - for (auto area = mAreas.begin(); area != mAreas.end(); area++) { - if (sf::FloatRect(area->area).contains(point)) - // Make the return value non-const for convenience. - return &const_cast(*area); - } - return nullptr; -} - /** * Draws all elements in the group. */ diff --git a/source/World.h b/source/World.h index a7d3b85..3d338f2 100755 --- a/source/World.h +++ b/source/World.h @@ -26,52 +26,18 @@ public: void insertCharacter(std::shared_ptr character); void step(int elapsed); void think(int elapsed); - void insertArea(const sf::IntRect& rect); - void generatePortals(); - std::vector getPath(const sf::Vector2f& start, - const sf::Vector2f& end, float radius) const; std::vector > getCharacters(const sf::Vector2f& position, float maxDistance) const; private: - struct Area; - /** - * Edges - * - * Redundant data as portals are saved twice. - */ - struct Portal { - Portal() = default; - Portal(const sf::Vector2i& start, const sf::Vector2i& end); - bool operator==(const Portal& p) { - return start == p.start && end == p.end && area == p.area; - } - sf::Vector2i start; - sf::Vector2i end; - Area* area; - }; - - /** - * Nodes - */ - struct Area { - sf::IntRect area; - sf::Vector2i center; - std::vector portals; - }; private: void draw(sf::RenderTarget& target, sf::RenderStates states) const; bool testCollision(std::shared_ptr spriteA, std::shared_ptr spriteB, int elapsed) const; - Area* getArea(const sf::Vector2f& point) const; - float heuristic_cost_estimate(Area* start, Area* end) const; - std::vector astarArea(Area* start, Area* end) const; private: - static const float WALL_DISTANCE_MULTIPLIER; std::map > > mDrawables; - std::vector mAreas; //< This has to be a vector as objects are compared by address. std::vector > mCharacters; }; diff --git a/source/abstract/Character.cpp b/source/abstract/Character.cpp index 20a6db0..62b17c1 100644 --- a/source/abstract/Character.cpp +++ b/source/abstract/Character.cpp @@ -15,23 +15,25 @@ #include "../util/Log.h" #include "../util/Yaml.h" #include "../World.h" +#include "../Pathfinder.h" const float Character::VISION_DISTANCE = 500.0f; /** * Saves pointer to this instance in static var for think(). */ -Character::Character(World& world, TileManager& tileManager, const Data& data, - const Yaml& config) : +Character::Character(World& world, TileManager& tileManager, Pathfinder& pathfinder, + const Data& data, const Yaml& config) : Sprite(data, config), mWorld(world), mTileManager(tileManager), + mPathfinder(pathfinder), mMaxHealth(config.get(YAML_KEY::HEALTH, YAML_DEFAULT::HEALTH)), mCurrentHealth(mMaxHealth), mMovementSpeed(config.get(YAML_KEY::SPEED, YAML_DEFAULT::SPEED)), mWeapon(new Weapon(world, *this, Yaml(config.get(YAML_KEY::WEAPON, YAML_DEFAULT::WEAPON)))), - mLastPosition(getPosition()){ + mLastPosition(getPosition()) { } Character::~Character() { @@ -112,7 +114,7 @@ Character::setDestination(const sf::Vector2f& destination) { mPath.clear(); return true; } - mPath = mWorld.getPath(getPosition(), destination, getRadius()); + mPath = mPathfinder.getPath(getPosition(), destination, getRadius()); if (!mPath.empty()) setSpeed(mPath.back() - getPosition(), mMovementSpeed); else { diff --git a/source/abstract/Character.h b/source/abstract/Character.h index 5bd1d5c..b03a386 100644 --- a/source/abstract/Character.h +++ b/source/abstract/Character.h @@ -10,6 +10,7 @@ #include "Sprite.h" +class Pathfinder; class TileManager; class World; class Weapon; @@ -21,7 +22,7 @@ class Yaml; class Character : public Sprite { public: explicit Character(World& world, TileManager& tileManager, - const Data& data, const Yaml& config); + Pathfinder& pathfinder, const Data& data, const Yaml& config); virtual ~Character() = 0; void onDamage(int damage); @@ -47,6 +48,7 @@ private: friend class World; World& mWorld; TileManager& mTileManager; + Pathfinder& mPathfinder; const int mMaxHealth; int mCurrentHealth; //< Current health. Between 0 and mMaxHealth. diff --git a/source/generator/Generator.cpp b/source/generator/Generator.cpp index bb58a98..d31bc8d 100644 --- a/source/generator/Generator.cpp +++ b/source/generator/Generator.cpp @@ -13,7 +13,7 @@ #include "simplexnoise.h" #include "../sprites/TileManager.h" #include "../util/Log.h" -#include "../World.h" +#include "../Pathfinder.h" /// For usage with simplexnoise.h uint8_t perm[512]; @@ -40,7 +40,7 @@ Generator::Generator() { * power of two. */ void -Generator::generateTiles(TileManager& tm, World& world, +Generator::generateTiles(TileManager& tm, Pathfinder& pathfinder, const sf::IntRect& area) const { // Check if width and height are power of two. assert(area.width && !(area.width & (area.width - 1))); @@ -74,8 +74,9 @@ Generator::generateTiles(TileManager& tm, World& world, TileManager::Type::FLOOR); } } - generateAreas(world, filtered, area, sf::Vector2f(area.left, area.top)); - world.generatePortals(); + generateAreas(pathfinder, filtered, area, + sf::Vector2f(area.left, area.top)); + pathfinder.generatePortals(); } /** @@ -155,13 +156,13 @@ Generator::filterWalls(std::vector >& in, * @param offset Offset of tiles[0][0] from World coordinate (0, 0). */ void -Generator::generateAreas(World& world, std::vector >& tiles, +Generator::generateAreas(Pathfinder& pathfinder, std::vector >& tiles, const sf::IntRect& area, const sf::Vector2f& offset) { assert(area.width > 0 && area.height > 0); int count = countWalls(sf::IntRect(area.left - offset.y, area.top - offset.x, area.width, area.height), tiles); if (count == 0) { - world.insertArea(sf::IntRect(area)); + pathfinder.insertArea(sf::IntRect(area)); } else if (count == area.width * area.height) { return; @@ -169,13 +170,13 @@ Generator::generateAreas(World& world, std::vector >& tiles, else { int halfWidth = area.width / 2.0f; int halfHeight = area.height / 2.0f; - generateAreas(world, tiles, sf::IntRect(area.left, + generateAreas(pathfinder, tiles, sf::IntRect(area.left, area.top, halfWidth, halfHeight), offset); - generateAreas(world, tiles, sf::IntRect(area.left + halfWidth, + generateAreas(pathfinder, tiles, sf::IntRect(area.left + halfWidth, area.top, halfWidth, halfHeight), offset); - generateAreas(world, tiles, sf::IntRect(area.left, + generateAreas(pathfinder, tiles, sf::IntRect(area.left, area.top + halfHeight, halfWidth, halfHeight), offset); - generateAreas(world, tiles, sf::IntRect(area.left + halfWidth, + generateAreas(pathfinder, tiles, sf::IntRect(area.left + halfWidth, area.top + halfHeight, halfWidth, halfHeight), offset); } } diff --git a/source/generator/Generator.h b/source/generator/Generator.h index e5e347d..35e5d4b 100644 --- a/source/generator/Generator.h +++ b/source/generator/Generator.h @@ -10,13 +10,13 @@ #include +class Pathfinder; class TileManager; -class World; class Generator { public: explicit Generator(); - void generateTiles(TileManager& tm, World& world, + void generateTiles(TileManager& tm, Pathfinder& pathfinder, const sf::IntRect& area) const; //void generateCharacters(World& world, const sf::IntRect& area) const; sf::Vector2f getPlayerSpawn() const; @@ -29,7 +29,7 @@ private: int x, int y, int longside, int shortside, int subtract); static int countWalls(const sf::IntRect& area, std::vector >& tiles); - static void generateAreas(World& world, + static void generateAreas(Pathfinder& pathfinder, std::vector >& tiles, const sf::IntRect& area, const sf::Vector2f& offset); }; diff --git a/source/sprites/Enemy.cpp b/source/sprites/Enemy.cpp index 8363c22..88de5c5 100644 --- a/source/sprites/Enemy.cpp +++ b/source/sprites/Enemy.cpp @@ -9,9 +9,9 @@ #include -Enemy::Enemy(World& world, TileManager& tileManager, +Enemy::Enemy(World& world, TileManager& tileManager, Pathfinder& pathfinder, const sf::Vector2f& position, const Yaml& config) : - Character(world, tileManager, Data(position, CATEGORY_ACTOR, MASK_ALL), + Character(world, tileManager, pathfinder, Data(position, CATEGORY_ACTOR, MASK_ALL), config) { } diff --git a/source/sprites/Enemy.h b/source/sprites/Enemy.h index a942165..300f2fc 100644 --- a/source/sprites/Enemy.h +++ b/source/sprites/Enemy.h @@ -16,7 +16,8 @@ class Yaml; class Enemy : public Character { public: explicit Enemy(World& world, TileManager& tileManager, - const sf::Vector2f& position, const Yaml& config); + Pathfinder& pathfinder, const sf::Vector2f& position, + const Yaml& config); protected: virtual void onThink(int elapsed); diff --git a/source/sprites/Player.cpp b/source/sprites/Player.cpp index e69f87a..b530a77 100644 --- a/source/sprites/Player.cpp +++ b/source/sprites/Player.cpp @@ -12,10 +12,10 @@ /** * Initializes Sprite. */ -Player::Player(World& world, TileManager& tileManager, +Player::Player(World& world, TileManager& tileManager, Pathfinder& pathfinder, const sf::Vector2f& position, const Yaml& config) : - Character(world, tileManager, Data(position, CATEGORY_ACTOR, MASK_ALL), - config), + Character(world, tileManager, pathfinder, + Data(position, CATEGORY_ACTOR, MASK_ALL), config), mDirection(0) { } diff --git a/source/sprites/Player.h b/source/sprites/Player.h index 5e0ab00..31b2fd3 100644 --- a/source/sprites/Player.h +++ b/source/sprites/Player.h @@ -30,7 +30,8 @@ public: public: explicit Player(World& world, TileManager& tileManager, - const sf::Vector2f& position, const Yaml& config); + Pathfinder& pathfinder, const sf::Vector2f& position, + const Yaml& config); void setCrosshairPosition(const sf::Vector2f& position); void pullTrigger();