// // AniMapUtils.h // SteveMaggieCpp // // Created by Katarzyna Kalinowska-Górska on 05.06.2017. // // #ifndef AniMapUtils_h #define AniMapUtils_h #include #include #include "cocos2d.h" class AniMapUtils { public: typedef struct TileData { int col {-1}; int row {-1}; TileData(){} TileData(int pCol, int pRow){ col = pCol; row = pRow; }; TileData(cocos2d::Vec2 vec){ col = vec.x; row = vec.y; }; // todo operator overloading would be better. or the best would be just to use Vec2 all along. But it's too late for that :(. float distanceColRowToTile(const TileData& tileData) const { return cocos2d::Vec2(col - tileData.col, row - tileData.row).length(); } cocos2d::Vec2 convertToVec2() const{ return cocos2d::Vec2(col, row); } TileData operator-(const TileData& tile) { return TileData(col - tile.col, row - tile.row); } } TileData; //for the path finding algorithm class PathTileData { public: PathTileData(TileData tileData, std::vector pNeighbours) { tile = tileData; neighbours = pNeighbours; }; std::vector neighbours; int tempDistance {-1}; bool visited { false}; TileData tile {-1,-1}; TileData previousTile {-1, -1}; }; static AniMapUtils& getInstance() { static AniMapUtils instance; return instance; } void clearMap(); std::vector calculatePathOnTmxMap(TileData fromTile, TileData toTile, cocos2d::TMXTiledMap* tmxMap, cocos2d::TMXLayer* tmxTileLayer, bool allowStartTileInaccessible, bool useLastMapGraph = true); // better to keep toTiles small std::vector calculatePathToClosestFromTileSet(TileData fromTile, std::vector toTiles, cocos2d::TMXTiledMap* tmxMap, cocos2d::TMXLayer* tmxTileLayer, bool allowStartTileInaccessible, bool useLastMapGraph = true); // the last tile in the returned vector will be the chosen tile from the tile set bool recalculateMapGraphAsync(cocos2d::TMXTiledMap* tmxMap, cocos2d::TMXLayer* tmxTileLayer, std::function callback); void recalculateMapGraph(cocos2d::TMXTiledMap* tmxMap, cocos2d::TMXLayer* tmxTileLayer); void recalculateMapGraph(cocos2d::TMXTiledMap* tmxMap, cocos2d::TMXLayer* tmxTileLayer, std::vector justForTiles); TileData findClosestAccessibleTile(TileData toTile, cocos2d::TMXTiledMap* tmxMap, cocos2d::TMXLayer* tmxLayer); std::vector listTileNeighbours(TileData tile, cocos2d::TMXTiledMap* tmxMap, cocos2d::TMXLayer* tmxLayer, bool ignoreAllChecks = false); std::vector calculatePath(TileData fromTile, TileData toTile, std::vector> mapGraph); int getTileLevel(cocos2d::TMXTiledMap* tmxMap, cocos2d::TMXLayer* tmxLayer, TileData p_tileData); bool isTileAccessible(cocos2d::TMXTiledMap* tmxMap, cocos2d::TMXLayer* tmxLayer, int col, int row); bool isTileAccessible(cocos2d::TMXTiledMap* tmxMap, cocos2d::TMXLayer* tmxLayer, TileData p_tileData); bool areTilesNeighbours(TileData tile1, TileData tile2, cocos2d::TMXTiledMap* tmxMap, cocos2d::TMXLayer* tmxLayer, int maxDeltaLevel = 1, bool ignoreAllChecks = false); //TODO set to zero and load in map props std::vector closestTiles(TileData tile, cocos2d::TMXTiledMap* tmxMap, cocos2d::TMXLayer* tmxLayer, int dirX, int dirY, int range = 3, int maxDeltaLevel = 2); std::vector closestXTiles(TileData tile, cocos2d::TMXTiledMap* tmxMap, cocos2d::TMXLayer* tmxLayer, int dir, int range = 3, int maxDeltaLevel = 2); //dir -1 or 1 std::vector closestYTiles(TileData tile, cocos2d::TMXTiledMap* tmxMap, cocos2d::TMXLayer* tmxLayer, int dir, int range = 3, int maxDeltaLevel = 2); //dir -1 or 1 TileData getClosestTileInDirection(cocos2d::TMXTiledMap* tmxMap, cocos2d::TMXLayer* tmxLayer, TileData origin, int colDir, int rowDir, int maxFlatDelta = 3, int maxLevelDelta = 2); TileData getClosestTileInXDirection(cocos2d::TMXTiledMap* tmxMap, cocos2d::TMXLayer* tmxLayer, TileData origin, int colDir, int maxFlatDelta = 3, int maxLevelDelta = 2); TileData getClosestTileInYDirection(cocos2d::TMXTiledMap* tmxMap, cocos2d::TMXLayer* tmxLayer, TileData origin, int rowDir, int maxFlatDelta = 3, int maxLevelDelta = 2); // TileData closestNeighbour TileData translateXYPointToColRow (cocos2d::Point xypoint, float tileWidth, float tileHeight, int totalMapCols, int totalMapRows); int translateXToCol(float x, float tileWidth, int totalMapCols); int translateYToRow(float y, float tileHeight, int totalMapRows); cocos2d::Point getTileMiddlePosition(const cocos2d::TMXTiledMap* map, int col, int row); cocos2d::Rect getTileRect(const cocos2d::TMXTiledMap* map, int col, int row); cocos2d::Point translateScreenPositionToMapPosition(cocos2d::Point pointOnScreen, cocos2d::Point mapPosition); cocos2d::Point translateMapPositionToScreenPosition(cocos2d::Point pointOnMap, cocos2d::Point mapPosition); std::vector getTilesIntersectingRect (cocos2d::Rect rect, float tileWidth, float tileHeight, int totalMapCols, int totalMapRows); std::vector getTilesIntersectingRect (cocos2d::Rect rect, float tileWidth, float tileHeight, int totalMapCols, int totalMapRows, std::vector& borderTiles); cocos2d::Point getRandomFreeTile(TileData& randomTile, cocos2d::TMXTiledMap* map, cocos2d::TMXLayer* layer, int minCol = 0, int maxCol = 150, int minRow = 0, int maxRow = 150); void setTilePassable(TileData tile, bool passable); // the pathfinding algorithm will stop and return the path after reaching a tile that is further from the starting tile than this range (by either col or row) // can be set e.g. to the number of tiles that fit the screen // by default, it's a number big enough not to make a difference inline void setMaxTileRangeOnPath(int p_maxTileRange) {m_maxTileRangeOnPath = p_maxTileRange;} cocos2d::Value getTileProperty(cocos2d::TMXTiledMap* p_map, cocos2d::TMXLayer* p_layer, const TileData& p_tile, const std::string& p_propertyName){ auto tileProperties = p_map->getPropertiesForGID(p_layer->getTileGIDAt(p_tile.convertToVec2())); if(tileProperties.getType() == cocos2d::Value::Type::MAP){ auto map = tileProperties.asValueMap(); if(map.find(p_propertyName) != map.end()){ return map[p_propertyName]; } } return cocos2d::Value::Null; } protected: std::vector> _cachedMapGraph; std::map _tempImpassableTiles; int m_maxTileRangeOnPath {1000}; bool m_threadIsRunning { false }; cocos2d::TMXTiledMap* m_threadTempMap { nullptr}; cocos2d::TMXLayer* m_threadTempLayer { nullptr}; std::function m_threadTempCallback = [](){}; // only one should be running at a time void asyncGraphRecalcThread(); }; bool operator==(const AniMapUtils::TileData& lhs, const AniMapUtils::TileData& rhs); bool operator!=(const AniMapUtils::TileData& lhs, const AniMapUtils::TileData& rhs); // for the std::map bool operator<(const AniMapUtils::TileData& lhs, const AniMapUtils::TileData& rhs); #endif /* AniMapUtils_h */