AniMapUtils.h 7.73 KB
//
//  AniMapUtils.h
//  SteveMaggieCpp
//
//  Created by Katarzyna Kalinowska-Górska on 05.06.2017.
//
//

#ifndef AniMapUtils_h
#define AniMapUtils_h

#include <stdio.h>
#include <vector>
#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<TileData> pNeighbours) {
                    tile = tileData;
                    neighbours = pNeighbours;
                };
            
                std::vector<TileData> 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<TileData> calculatePathOnTmxMap(TileData fromTile, TileData toTile, cocos2d::TMXTiledMap* tmxMap, cocos2d::TMXLayer* tmxTileLayer, bool allowStartTileInaccessible, bool useLastMapGraph = true);
    // better to keep toTiles small
     std::vector<TileData> calculatePathToClosestFromTileSet(TileData fromTile, std::vector<TileData> 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<void()> callback);
     void recalculateMapGraph(cocos2d::TMXTiledMap* tmxMap, cocos2d::TMXLayer* tmxTileLayer);
    void recalculateMapGraph(cocos2d::TMXTiledMap* tmxMap, cocos2d::TMXLayer* tmxTileLayer, std::vector<AniMapUtils::TileData> justForTiles);
     TileData findClosestAccessibleTile(TileData toTile, cocos2d::TMXTiledMap* tmxMap, cocos2d::TMXLayer* tmxLayer);
     std::vector<TileData> listTileNeighbours(TileData tile, cocos2d::TMXTiledMap* tmxMap, cocos2d::TMXLayer* tmxLayer, bool ignoreAllChecks = false);
     std::vector<TileData> calculatePath(TileData fromTile, TileData toTile, std::vector<std::vector<PathTileData*>> 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<TileData> closestTiles(TileData tile, cocos2d::TMXTiledMap* tmxMap, cocos2d::TMXLayer* tmxLayer, int dirX, int dirY, int range = 3, int maxDeltaLevel = 2);
    std::vector<TileData> closestXTiles(TileData tile, cocos2d::TMXTiledMap* tmxMap, cocos2d::TMXLayer* tmxLayer, int dir, int range = 3, int maxDeltaLevel = 2); //dir -1 or 1
    std::vector<TileData> 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<TileData> getTilesIntersectingRect (cocos2d::Rect rect, float tileWidth, float tileHeight, int totalMapCols, int totalMapRows);
    std::vector<TileData> getTilesIntersectingRect (cocos2d::Rect rect, float tileWidth, float tileHeight, int totalMapCols, int totalMapRows, std::vector<TileData>& 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<std::vector<PathTileData*>> _cachedMapGraph;
    std::map<TileData, bool> _tempImpassableTiles;
    int m_maxTileRangeOnPath {1000};
    
    bool m_threadIsRunning { false };
    cocos2d::TMXTiledMap* m_threadTempMap { nullptr};
    cocos2d::TMXLayer* m_threadTempLayer { nullptr};
    std::function<void()> 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 */