RPG游戏离不开寻路 A星寻路是游戏的最短路径寻路算法。
网上有很多A*寻路的源码,我学习了几份,发现它们都没有对路径进行平滑处理,路径都是不平滑的 这样游戏角色寻路走路会很怪异。看到别人博客思路,自己用c++撸一遍
我的起点为 0,0点 终点为9,6点
思路借鉴:https://blog.csdn.net/m0_37290785/article/details/79655666
//初始化地图数据
int **map = new int*[10];
for (int i = 0; i < 10; i++)//为指针数组的每个元素分配一个数组
map[i] = new int[10];
for (int i = 0; i < 10; i++)
{
for (int j = 0; j < 10; j++)
{
map[i][j] = 0;
}
}
map[2][0] = 1;
map[2][1] = 1;
map[2][2] = 1;
map[2][3] = 1;
map[2][4] = 1;
map[2][5] = 1;
map[2][6] = 1;
map[4][10] = 1;
map[4][9] = 1;
map[4][8] = 1;
map[4][7] = 1;
map[4][6] = 1;
map[4][5] = 1;
map[4][4] = 1;Astar astar;
astar.setDataByMap(map, 10, 10);
std::vector<MapReader::sVec2> path =astar.findAstart(9, 6,0, 0);
看下图的8是原生的的路径。
怎么去优化呢。
第一步比较简单删去路径上的共线点 这些共线点已经没有意义了
//1.将路径去掉共线点
int max = path.size() - 2;
for (int i = 0; i <max; )
{
if ((path[i].x * path[i + 1].y - path[i + 2].y * path[i].x) + (path[i + 1].x * path[i + 2].y - path[i].y * path[i + 1].x) + (path[i + 2].x * path[i].y - path[i + 2].x * path[i + 1].y) == 0)//判断三点共线
{
path.erase(path.begin() + i + 1);
max = path.size() - 2;
}
else
{
i++;
}}
然后我得出了下图路径
第二步,去掉多余拐点,这一步复杂一点,需要判断两节点是否能够直达,若能直达五障碍物即可删除二者的中间节点,可以参考https://blog.csdn.net/midashao/article/details/70237061
然后就得到了最终路径
//2.判断是否直达
cout << "删除多余路径过程" << endl;
int max1 = path.size() - 2;
for (int i = 0; i < max1; )
{
bool okjudge = true;
//获取两点之间斜率
if (path[i].x == path[i + 2].x || path[i].y == path[i + 2].y)
{
cout << i << "斜率0或90" << endl;
i++;
continue;
}
float k = float(path[i + 2].x - path[i].x) / float(path[i + 2].y - path[i].y);
float b = path[i].x + 0.5 - k * (path[i].y + 0.5);
cout << i << "斜率K:" << k << " b:" << b << endl;
if (fabs(k) <= 1)
{
if (k > 0 && path[i + 2].y > path[i].y || k<0 && path[i + 2].y > path[i].y)
{
cout << "斜率小于等于45度 " << endl;
//斜率小于45度
//获取宽度差
int width = fabs(path[i + 2].y - path[i].y);
for (int j = 0; j < width; j++)
{
float y = (1 + path[i].y + j) * k + b;
cout << y << endl;
if (y != int(y))//y不是整数
{
cout << path[i].y + j << " " << int(y) << " " << path[i].y + j + 1 << " " << int(y) << endl;
cout << "1: " << g_Map[path[i].y + j][int(y)].iColor << " " << g_Map[path[i].y + j + 1][int(y)].iColor << endl;
if (g_Map[path[i].y + j][int(y)].iColor == true)
{
okjudge = false;
break;
}
if (g_Map[path[i].y + j + 1][int(y)].iColor == true)
{
okjudge = false;
break;
}}
else
{}
}}
else if (k<0 && path[i + 2].y < path[i].y || k>0 && path[i + 2].y < path[i].y)
{
cout << "斜率小于等于45度 " << endl;
//斜率小于45度
//获取宽度差
int width = fabs(path[i + 2].y - path[i].y);
for (int j = 0; j < width; j++)
{
float y = (0.5 + path[i].y - 0.5 - j) * k + b;
cout << y << endl;
if (y != int(y))//y不是整数
{
cout << path[i].y - j << " " << int(y) << " " << path[i].y - j - 1 << " " << int(y) << endl;
cout << "1: " << g_Map[path[i].y - j][int(y)].iColor << " " << g_Map[path[i].y - j - 1][int(y)].iColor << endl;
if (g_Map[path[i].y - j][int(y)].iColor == true)
{
okjudge = false;
break;
}
if (g_Map[path[i].y - j - 1][int(y)].iColor == true)
{
okjudge = false;
break;
}}
else
{}
}
}
}
else
{
if (k > 0 && path[i + 2].x > path[i].x || k<0 && path[i + 2].x > path[i].x)
{
cout << "斜率大于45度" << endl;
//斜率大于45度
//获取高度差
int height = fabs(path[i + 2].x - path[i].x);
for (int j = 0; j < height; j++)
{
float x = ((0.5 + path[i].x + 0.5 + j) - b) / k;
cout << x << endl;
if (x != int(x))
{
cout << int(x) << " " << path[i].x + j << " " << int(x) << " " << path[i].x + j + 1 << endl;
cout << "2: " << g_Map[int(x)][path[i].x + j].iColor << " " << g_Map[int(x)][path[i].x + j + 1].iColor << endl;
if (g_Map[int(x)][path[i].x + j].iColor == true)
{
okjudge = false;
break;
}
if (g_Map[int(x)][path[i].x + j + 1].iColor == true)
{
okjudge = false;
break;
}}
else
{}
}
}
else if (k<0 && path[i + 2].x < path[i].x || k>0 && path[i + 2].x < path[i].x)
{
cout << "斜率大于45度" << endl;
int height = fabs(path[i + 2].x - path[i].x);
for (int j = 0; j < height; j++)
{
float x = ((0.5 + path[i].x - 0.5 - j) - b) / k;
cout << x << endl;
if (x != int(x))
{
cout << int(x) << " " << path[i].x - j << " " << int(x) << " " << path[i].x - j - 1 << endl;
cout << "2: " << g_Map[int(x)][path[i].x - j].iColor << " " << g_Map[int(x)][path[i].x - j - 1].iColor << endl;
if (g_Map[int(x)][path[i].x - j].iColor == true)
{
okjudge = false;
break;
}
if (g_Map[int(x)][path[i].x - j - 1].iColor == true)
{
okjudge = false;
break;
}}
else
{}
}
}}
if (okjudge == false)
{
i++;
}
else
{
cout << "删除节点成功" << endl;
path.erase(path.begin() + i + 1);
max1 = path.size() - 2;
}
}
最后将两步封装成寻路的一个成员函数。就可以随时调用了
std::vector<MapReader::sVec2> Astar::pathCreat(std::vector<MapReader::sVec2> path)
{
//1.将路径去掉共线点
int max = path.size() - 2;
for (int i = 0; i <max; )
{
if ((path[i].x * path[i + 1].y - path[i + 2].y * path[i].x) + (path[i + 1].x * path[i + 2].y - path[i].y * path[i + 1].x) + (path[i + 2].x * path[i].y - path[i + 2].x * path[i + 1].y) == 0)//判断三点共线
{
path.erase(path.begin() + i + 1);
max = path.size() - 2;
}
else
{
i++;
}}
cout << "去掉共线点路径打印" << endl;
for (int i = 0; i < path.size(); i++)
{
cout << "路径" << i << ": " << path[i].y << "," << path[i].x << endl;
}//2.判断是否直达
cout << "删除多余路径过程" << endl;
int max1 = path.size() - 2;
for (int i = 0; i < max1; )
{
bool okjudge = true;
//获取两点之间斜率
if (path[i].x == path[i + 2].x || path[i].y == path[i + 2].y)
{
cout << i << "斜率0或90" << endl;
i++;
continue;
}
float k = float(path[i + 2].x - path[i].x) / float(path[i + 2].y - path[i].y);
float b = path[i].x + 0.5 - k * (path[i].y + 0.5);
cout << i << "斜率K:" << k << " b:" << b << endl;
if (fabs(k) <= 1)
{
if (k > 0 && path[i + 2].y > path[i].y || k<0 && path[i + 2].y > path[i].y)
{
cout << "斜率小于等于45度 " << endl;
//斜率小于45度
//获取宽度差
int width = fabs(path[i + 2].y - path[i].y);
for (int j = 0; j < width; j++)
{
float y = (1 + path[i].y + j) * k + b;
cout << y << endl;
if (y != int(y))//y不是整数
{
cout << path[i].y + j << " " << int(y) << " " << path[i].y + j + 1 << " " << int(y) << endl;
cout << "1: " << g_Map[path[i].y + j][int(y)].iColor << " " << g_Map[path[i].y + j + 1][int(y)].iColor << endl;
if (g_Map[path[i].y + j][int(y)].iColor == true)
{
okjudge = false;
break;
}
if (g_Map[path[i].y + j + 1][int(y)].iColor == true)
{
okjudge = false;
break;
}}
else
{}
}}
else if (k<0 && path[i + 2].y < path[i].y || k>0 && path[i + 2].y < path[i].y)
{
cout << "斜率小于等于45度 " << endl;
//斜率小于45度
//获取宽度差
int width = fabs(path[i + 2].y - path[i].y);
for (int j = 0; j < width; j++)
{
float y = (0.5 + path[i].y - 0.5 - j) * k + b;
cout << y << endl;
if (y != int(y))//y不是整数
{
cout << path[i].y - j << " " << int(y) << " " << path[i].y - j - 1 << " " << int(y) << endl;
cout << "1: " << g_Map[path[i].y - j][int(y)].iColor << " " << g_Map[path[i].y - j - 1][int(y)].iColor << endl;
if (g_Map[path[i].y - j][int(y)].iColor == true)
{
okjudge = false;
break;
}
if (g_Map[path[i].y - j - 1][int(y)].iColor == true)
{
okjudge = false;
break;
}}
else
{}
}
}
}
else
{
if (k > 0 && path[i + 2].x > path[i].x || k<0 && path[i + 2].x > path[i].x)
{
cout << "斜率大于45度" << endl;
//斜率大于45度
//获取高度差
int height = fabs(path[i + 2].x - path[i].x);
for (int j = 0; j < height; j++)
{
float x = ((0.5 + path[i].x + 0.5 + j) - b) / k;
cout << x << endl;
if (x != int(x))
{
cout << int(x) << " " << path[i].x + j << " " << int(x) << " " << path[i].x + j + 1 << endl;
cout << "2: " << g_Map[int(x)][path[i].x + j].iColor << " " << g_Map[int(x)][path[i].x + j + 1].iColor << endl;
if (g_Map[int(x)][path[i].x + j].iColor == true)
{
okjudge = false;
break;
}
if (g_Map[int(x)][path[i].x + j + 1].iColor == true)
{
okjudge = false;
break;
}}
else
{}
}
}
else if (k<0 && path[i + 2].x < path[i].x || k>0 && path[i + 2].x < path[i].x)
{
cout << "斜率大于45度" << endl;
int height = fabs(path[i + 2].x - path[i].x);
for (int j = 0; j < height; j++)
{
float x = ((0.5 + path[i].x - 0.5 - j) - b) / k;
cout << x << endl;
if (x != int(x))
{
cout << int(x) << " " << path[i].x - j << " " << int(x) << " " << path[i].x - j - 1 << endl;
cout << "2: " << g_Map[int(x)][path[i].x - j].iColor << " " << g_Map[int(x)][path[i].x - j - 1].iColor << endl;
if (g_Map[int(x)][path[i].x - j].iColor == true)
{
okjudge = false;
break;
}
if (g_Map[int(x)][path[i].x - j - 1].iColor == true)
{
okjudge = false;
break;
}}
else
{}
}
}}
if (okjudge == false)
{
i++;
}
else
{
cout << "删除节点成功" << endl;
path.erase(path.begin() + i + 1);
max1 = path.size() - 2;
}
}
return path;
}
使用只需要包裹下就ok了
Astar astar;
astar.setDataByMap(map, 10, 10);
std::vector<MapReader::sVec2> path = astar.pathCreat(astar.findAstart(9, 6,0, 0));
当然我的代码还存在一定的缺陷= =。忘大佬评论指出不足之处。