// // BIMapRhombusGrid.hpp // CandyCookie // // Created by 冷晓霆 on 2022/2/22. // // 将地图划分为菱形网格,用于处理角色运动 #ifndef RUMapRhombusGrid_hpp #define RUMapRhombusGrid_hpp #include #include "cocos2d.h" #include "RUDefine.h" ///TODO::两个物件之间的最小zOrder间距 有需求找油代辉改 #define BLOCK_GRID_SPACE 10 USING_NS_CC; NS_RU_BEGIN class RhombusableItem { public: // 得到该物件的z-order virtual int getCurZOrder() = 0; // 得到该物件中心点在地图中的位置 virtual Vec2 getCenterPosition() = 0; // 一系列棱形网格的坐标(相对于中心点而言),表示的是可视区域 virtual const std::vector& getVisibleArea() = 0; // 一系列棱形网格的坐标(相对于中心点而言),表示的是基座区域 virtual const std::vector& getPedestalArea() = 0; // 一系列棱形网格的坐标(相对于中心点而言),表示的是可在上面行走的区域 virtual const std::vector& getWalkableArea() = 0; // 表示该物件的基座区域在极端情况下是否是可以穿行的 virtual bool isCrossable() = 0; // 获取某个物体的名称 virtual std::string getRhombusableItemName() = 0; }; struct RhombusPathNode { Vec2 posGrid; int zOrder; // 如果为-1, 则需要调用者自己去设置一个合适的值 bool bImmediate = false; }; struct RhomArea { std::set grid; int zOrderDefault; }; class MapRhombusGrid : public Ref { public: MapRhombusGrid(); ~MapRhombusGrid(); /// 初始化地图的网格信息 /// @param mapSize 整个地图的大小 /// @param rhombusSize 棱形网格的大小 void initialize(const cocos2d::Size& mapSize, const cocos2d::Size& rhombusSize, bool bSupportStraight = false); /// 某个物件被移除了 /// @param pItem 可被棱形化的物件 void itemRemoved(RhombusableItem* pItem); /// 某个物件被添加到了地图上面,如果该区域被占用了,则返回失败 /// @param pItem 可被棱形化的物件 /// 返回是否添加成功 bool itemAdded(RhombusableItem* pItem); /// 设置区域信息 /// @param areas 区域信息 void addArea(const std::vector& area, int zOrderDefault); /// 设置默认的zorder void setDefaultZOrder(int zOrder); /// 用于编辑器同步数据 /// @param itemName 物件名字 RhombusableItem* getItem(const std::string& itemName); /// 找到一条路径从from到to,返回一个id表示本次请求,id会在回调里面传给调用对象 /// @param fromGrid 起始点的坐标,网格坐标 /// @param toGrid 终点的坐标,网格坐标 /// @param path 路径信息 int findFlyAPath(const Vec2& fromGrid, const Vec2& toGrid, std::list& path); /// 找到一条路径从from到to,返回一个id表示本次请求,id会在回调里面传给调用对象 /// @param fromGrid 起始点的坐标,网格坐标 /// @param toGrid 终点的坐标,网格坐标 /// @param path 路径信息 int findAPath(const Vec2& fromGrid, const Vec2& toGrid, std::list& path, bool bIgnoreCharacter, bool bFlashToEndPos); /// 从地图坐标得到网格坐标 /// @param pos 地图坐标 Vec2 getGridPosition(const Vec2& pos); /// 某个位置是否被占用,也就是该网格位置已经有物件了 /// @param posGrid 该网格的位置 bool isGridOccupied(const Vec2& posGrid); /// 在节点上面绘制棱形网格部分 /// @param pGridContainer 棱形网格所在的节点 void debugGridAt(Node* pGridContainer); /// 画出某个网格 /// @param gridPos 网格坐标 /// @param isTemp 如果为临时的话则过removeNodeDelay秒会被删除 void drawGridNode(const Vec2& gridPos, Color4F color = Color4F::RED, bool isTemp = true, float removeNodeDelay = 20.0); void refreshDebugGrid(bool isEnable = true); /// 得到某个网格的中心点对应的坐标值 /// @param gridPos 网格坐标 Vec2 getGridCenter(const Vec2& gridPos); /// 在某个物件旁边找空余的位置,并返回列表 /// @param pItem 目标物件 /// @param found 返回空余列表,可能为空 /// @param gridPos 物件的中心位置,网格坐标 void findAdjEmptyPoses(RhombusableItem* pItem, const Vec2& gridPos, std::set& found); /// 得到某个位置被遮挡的层数 /// @param gridPos 要查找的位置 int getCntInOverlay(const Vec2& gridPos); /// 获取棱形网格的Zorder /// @param gridPos 棱形网格坐标 /// @param pTargetItem 目标物体,用来排除自己 /// @param bIsOverlayed 是否被遮挡 /// @param bFlyMode 飞行模式下需要遮盖住所有东西 int getGridZorder(const Vec2& gridPos, bool& bIsOverlayed, RhombusableItem* pTargetItem = nullptr, bool bFlyMode = false); /// 格子尺寸 cocos2d::Size getRhombusSize() { return _rhombusSize; } /// 得到某个网格的四个顶点的位置 /// @param gridPos 网格坐标 std::vector getGridPointsAt(const Vec2& gridPos); /// 获取占用了某个网格的所有物件的名称 /// @param gridPos 网格 std::list getItemsInGrid(const Vec2& gridPos); void setSupportStraight(bool value){_bSupportStraight = value;} bool getSupportStraight(){return _bSupportStraight;} /// 将某个网格标记为已经被占用 /// @param gridPos 网格 void setGridObstacle(const Vec2& posGrid); private: /// 得到某个网格的索引值,方便保存 /// @param posGrid 网格坐标 inline int getGridIndex(const Vec2& posGrid); /// 占据某个网格 /// @param posGrid 网格坐标 inline void occupyGrid(const Vec2& posGrid); /// 释放某个网格 /// @param posGrid 网格坐标 inline void releaseGrid(const Vec2& posGrid); /// 调试用,显示某个网格的调试线 /// @param gridPos 该网格的位置 /// @param color 线的颜色 /// @param fill 是否填充 void drawGridWith(const Vec2& gridPos, Color4F color, bool fill = false); /// 实际查找可行走路线 /// @param bIgnoreCrossable 是否忽略掉可穿行区域 int findAPathInternal(const Vec2& fromGrid, const Vec2& toGrid, std::list& path, bool bIgnoreCrossable); /// 实际查找可飞行路线 int findFlyAPathInternal(const Vec2& fromGrid, const Vec2& toGrid, std::list& path); /// 获取某个位置的ZOrder int getDefaultZOrder(const Vec2& posGrid); /// 判断某个位置是否在物件的后面 /// @param posGrid 网格位置 /// @param pItem 物件 bool isBehindItem(const Vec2& posGrid, RhombusableItem* pItem); private: static MapRhombusGrid* _instance; static int _nextId4Find; // 地图信息 cocos2d::Size _mapSize; cocos2d::Size _rhombusSize; int _cntGridsInX = 1; int _cntGridsInY = 1; bool _bSupportStraight = false; // 每个菱形网格的都被哪些物件的遮挡占用了 std::unordered_map> _itemsOverlayInGrid; // 每个菱形网格上面有哪些物件,包括了基座区域 std::unordered_map> _itemsInGrid; // 地图上面每个网格是否有某个物件的基座,每一位表示一个网格 unsigned char* _occupiedFlag4Grid = nullptr; int _flagSize = 0; int _zOrderDefault = 0; std::list _areas; // 可以被穿越的底座区域 // 当前的处理方法在物件可以被移动的时候会有问题,但是当前场景下效率比较高 std::unordered_map _gridsCrossable; // 棱形网格所在的节点 Node* _pGridContainer = nullptr; DrawNode* _pDrawNode4Debug = nullptr; bool _isDebugEnable = false; }; NS_RU_END #endif /* RUMapRhombusGrid_hpp */