#ifndef AStarCtril_h_
#define AStarCtril_h_
#include "cocos2d.h"
using namespace std;
USING_NS_CC;
#define PATHCOUNT 4 //预定义寻路方向 ,4||8
#define ROWS 8 //创建地图大小横向
#define COLS 14 //创建地图大小纵向
#define ZXDJ 10 //横向/纵向 移动一格的代价 //此处以一个格子为以单位,定义为以单位代价为10
#define XXDJ 14 //斜线 移动一格的代价 如果只考虑上下左右四个方向 可以不适用 如果考虑 四周八个方向 需要加入 //斜线代价,根据勾股定理可得为根号2,乘以一单位10,约等于14
//枚举所有方向,上下左右,左上,左下,右上,右下
enum direction
{
pUp, pDown, pLeft, pRight, pLeftUp, pLeftDown, pRightUp, pRightDown
};
enum APointType {
APT_OPENED, // 开放列表中
APT_CLOSED, // 关闭列表中
APT_STARTPOINT, // 起始点
APT_ENDPOINT, // 结束点
APT_REALY, //被选中后的准备状态
APT_UNKNOWN // 未知状态
};
//定义一个点的结构体类型
struct MyPoint {
int row; //点结构的x轴方向的坐标
int col; //点结构的y轴方向的坐标
int f; //代表从起点到终点 移动所需要的代价
int g; //起点到当前点 已经付出的代价 //累加起点到当前点所有路程的代价
int h; //当前点到终点的预计代价 //当前点走到终点,无视障碍物的 横向和纵向代价和
void setF() {
f= g + h;
};
APointType type; //标记当前点的类型
};
// 定义一个树结构,用来描述 每个点,向外延伸的分支
struct TreeNode
{
MyPoint pos; //当前点的坐标
vector <TreeNode *> childs; //每一个节点之下,可能用众多分支,所有用TreeNode类型的动态数组,存储各个节点的指针
TreeNode *pParent; //记录每一个节点的父节点
};
class AStarCtril:public Ref
{
public:
~AStarCtril();
static AStarCtril*getInstance();
//初始化数据,只初始化一次
void initData();
//创建地图数据模板
void createMap(Vec2 startPos, Vec2 endPos,int w= ROWS,int h= COLS);
//设置某个点的节点类型
void setPointType(MyPoint curPoint, APointType type);
//获取某个点的节点类型
APointType getPointType(MyPoint curPoint);
vector<MyPoint> getShortPath(MyPoint current,MyPoint endPoint );
private:
static AStarCtril*_Instance;
int mMapX;
int mMapY;
MyPoint mMap[ROWS][COLS]; //定义地图
MyPoint mStartPoint;
MyPoint mEndPoint;
};
int getH(MyPoint endPos, MyPoint pos);
bool needAdd(MyPoint pos, MyPoint map[ROWS][COLS], bool pahtMap[ROWS][COLS]);
#endif // !AStarCtril_h_
#include "AStarCtril.h"
AStarCtril*AStarCtril::_Instance = nullptr;
AStarCtril::~AStarCtril()
{
}
AStarCtril * AStarCtril::getInstance()
{
if (!_Instance) {
_Instance = new AStarCtril();
_Instance->initData();
}
return _Instance;
}
void AStarCtril::initData()
{
}
void AStarCtril::createMap(Vec2 startPos, Vec2 endPos, int w, int h)
{
memset(mMap, 0, sizeof TreeNode);
for (int i = 0; i < w; i++)
{
for (int j = 0; j < h; j++) {
MyPoint data = mMap[i][j];
data.row = i;
data.col = j;
data.f = 0;
data.g = 0;
data.h = 0;
if (i == startPos.x&&j == startPos.y) {
data.type = APointType::APT_STARTPOINT;
mStartPoint = data;
}
else if(i == endPos.x&&j == endPos.y)
{
data.type = APointType::APT_ENDPOINT;
mEndPoint = data;
}
else
{
data.type = APointType::APT_OPENED;
}
}
}
}
void AStarCtril::setPointType(MyPoint curPoint, APointType type)
{
curPoint.type = type;
}
APointType AStarCtril::getPointType(MyPoint curPoint)
{
return curPoint.type;
}
vector<MyPoint> AStarCtril::getShortPath(MyPoint current, MyPoint endPoint)
{
//2 创建辅助地图,标示原数据地图中的位置是否可以移动 false 0:没有走过 true:走过
bool pathMap[ROWS][COLS] = {0};
//3. 定义七点终点
MyPoint begPos = current;
MyPoint endPos = endPoint;
//4.标记起点为走过的路线
pathMap[begPos.row][begPos.col] = true;
//5.创建节点树 ,起点为根节点
TreeNode *pNew = new TreeNode;
//开辟节点树空间,以及付初值
memset(pNew,0,sizeof TreeNode);
//pRoot 创建新的树根,快速指向根节点
TreeNode *pRoot = pNew;
pRoot->pos = begPos;
//6. 创建一个动态数组,存储用来比较的子节点群
vector<TreeNode*>buff;
//7.寻路开始
TreeNode *pCurrent = pRoot;
TreeNode *pChild = NULL;
vector<TreeNode*>::iterator it;
vector<TreeNode*>::iterator itMin;
bool isFindEnd = false;
while (true)
{
//7.1 找到当前点周围能走的点
for (int i = 0; i < PATHCOUNT;i++) {
pChild = new TreeNode;
memset(pChild, 0, sizeof TreeNode);
pChild->pos = pCurrent->pos;
switch (i)
{
case pUp:
pChild->pos.row--;
pChild->pos.g += ZXDJ;
break;
case pDown:
pChild->pos.row++;
pChild->pos.g += ZXDJ;
break;
case pLeft:
pChild->pos.col--;
pChild->pos.g += ZXDJ;
break;
case pRight:
pChild->pos.col++;
pChild->pos.g += ZXDJ;
break;
case pLeftUp:
pChild->pos.col--;
pChild->pos.row--;
pChild->pos.g += XXDJ;
break;
case pLeftDown:
pChild->pos.col--;
pChild->pos.row++;
pChild->pos.g += XXDJ;
break;
case pRightUp:
pChild->pos.col++;
pChild->pos.row--;
pChild->pos.g += XXDJ;
break;
case pRightDown:
pChild->pos.col++;
pChild->pos.row++;
pChild->pos.g += XXDJ;
break;
default:
break;
}
//7.2 计算 g h f 的值
pChild->pos.h = getH(endPos,pChild->pos);
pChild->pos.setF();
//7.3 入树,入buff 数组
if (needAdd(pChild->pos, mMap,pathMap)) {
//入树
pCurrent->childs.push_back(pChild);
pChild->pParent = pCurrent;
//入buff数组 用来选出最小的
buff.push_back(pChild);
pathMap[pChild->pos.row][pChild->pos.col] = true;
}
else
{
delete pChild;
}
}
//7.4 从buff数组中找到f值最小的那个
itMin = buff.begin();
for (it= buff.begin(); it!=buff.end(); it++)
{
itMin = ((*itMin)->pos.f > (*it)->pos.f ? it : itMin);
}
// 7.5 删掉 ,变化成当前点
pCurrent = *itMin;
buff.erase(itMin);
//7.6 判断是否寻路结束
if (pCurrent->pos.row == endPos.row&&pCurrent->pos.col == endPos.col) {
isFindEnd = true;
break;
}
if (buff.empty()) {
break;
}
}
vector<MyPoint> shortPath = {};
if (isFindEnd) {
//log("找到终点了\n");
//在此通过树的最终节点,到这找到其根节点,即是最短路径的倒序。此时用数组类型或者 链表类型将树元素返回,既得到最短路径
while (pCurrent)
{
shortPath.insert(shortPath.begin(),pCurrent->pos);
pCurrent = pCurrent->pParent;
}
}
return shortPath;
}
int getH(MyPoint endPos, MyPoint pos) {
int x = (endPos.col > pos.col) ? (endPos.col - pos.col) : (pos.col - endPos.col);
int y = (endPos.row > pos.row) ? (endPos.row - pos.row) : (pos.row - endPos.row);
return (x + y)*ZXDJ;
}
bool needAdd(MyPoint pos, MyPoint map[ROWS][COLS], bool pahtMap[ROWS][COLS]) {
if (pos.row >= ROWS || pos.row < 0 ||
pos.col >= COLS || pos.col < 0)
return false;
if (APT_CLOSED == map[pos.row][pos.col].type)
return false;
if (true == pahtMap[pos.row][pos.col])
return false;
return true;
}