我在做一个迷宫游戏,如果玩家进入敌人的射程,敌人就会准备追击玩家,我用A* 寻路算法来做,我用程序化的方式来构建迷宫,迷宫中的每个方块都有一个带x和z位置的MapLocation,所以起始位置是敌人的位置,目标是玩家的位置,但有时候,当玩家进入敌人的射程,路径选择忽略了迷宫中的一些块来到达玩家,我上传了一个视频来说明这个问题:
https://www.youtube.com/watch?v=_amIf75wruw
IEnumerator Search(Vector3 start, Vector3 goal)
{
pathSuccess = false;
waypoints = new Vector3[0];
Heap<Path> open = new Heap<Path>(maze.MaxSize);
HashSet<Path> closed = new HashSet<Path>();
Path startNode = new Path(maze.GetMapLocation(start), 0, 0, 0, null);
Path goalNode = new Path(maze.GetMapLocation(goal), 0, 0, 0, null);
open.Add(startNode);
lastPos = startNode;
while (open.Count > 0)
{
if (lastPos.Equals(goalNode))
{
pathSuccess = true;
break;
}
foreach (MapLocation dir in maze.directions)
{
MapLocation neighbour = dir + lastPos.location;
if (maze.map[neighbour.x, neighbour.z] == 1) continue;
if (neighbour.x < 1 || neighbour.x >= maze.width || neighbour.z < 1 || neighbour.z >= maze.depth) continue;
if (IsClosed(neighbour, closed)) continue;
float G = Vector2.Distance(lastPos.location.ToVector(), neighbour.ToVector()) + lastPos.G;
float H = Vector2.Distance(neighbour.ToVector(), goalNode.location.ToVector());
float F = G + H;
if (!UpdateMarker(neighbour, G, H, F, lastPos, open))
open.Add(new Path(neighbour, G, H, F, lastPos));
}
Path pm = open.RemoveFirst();
closed.Add(pm);
lastPos = pm;
}
yield return null;
if (pathSuccess)
{
waypoints = RetracePath(startNode);
}
PathRequestManager.Instance.FinishedProcessingPath(waypoints, pathSuccess);
}
bool UpdateMarker(MapLocation pos, float g, float h, float f, Path prt, Heap<Path> open)
{
foreach (Path p in open)
{
if (p.location.Equals(pos))
{
p.G = g;
p.H = h;
p.F = f;
p.parent = prt;
return true;
}
}
return false;
}
bool IsClosed(MapLocation marker, HashSet<Path> closed)
{
foreach (Path p in closed)
{
if (p.location.Equals(marker)) return true;
}
return false;
}
Vector3[] RetracePath(Path startNode)
{
Path begin = lastPos;
List<Vector3> path = new List<Vector3>();
while (!startNode.Equals(begin) && begin != null)
{
path.Add(begin.Position(maze));
begin = begin.parent;
}
path.Reverse();
return path.ToArray();
}
public MapLocation GetMapLocation(Vector3 position)
{
MapLocation mapLocation = new MapLocation((int)position.x / scale, (int)position.z / scale);
return mapLocation;
}
public List<MapLocation> directions = new List<MapLocation>() {
new MapLocation(1,0),
new MapLocation(0,1),
new MapLocation(-1,0),
new MapLocation(0,-1) };
迷宫是这样生成的:
public class Recursive : Maze
{
public override void Generate()
{
Generate(5, 5);
}
void Generate(int x, int z)
{
if (CountSquareNeighbours(x, z) >= 2) return;
map[x, z] = 0;
directions.Shuffle();
Generate(x + directions[0].x, z + directions[0].z);
Generate(x + directions[1].x, z + directions[1].z);
Generate(x + directions[2].x, z + directions[2].z);
Generate(x + directions[3].x, z + directions[3].z);
}
}
public byte[,] map;
public virtual void Generate()
{
for (int z = 0; z < depth; z++)
for (int x = 0; x < width; x++)
{
if(Random.Range(0,100) < 50)
map[x, z] = 0; //1 = wall 0 = corridor
}
}
我已经试过使用曼哈顿的距离,它没有任何区别:
float H = Mathf.Abs(neighbour.x - goalNode.location.x) + Mathf.Abs(neighbour.z - goalNode.location.z);
2条答案
按热度按时间flvlnr441#
调试当你在GetMapLocation()中按比例划分时得到的值,它可能会因为缩放/舍入而跳过单元格?
我会有一个map[x,y]数组,然后按比例放大,以使其在屏幕上的像素正确,但在原始未缩放的Map[x,y]数组上进行寻路。IE将逻辑与渲染分开。
e4yzc0pl2#
你的A* 寻路算法的问题与你的迷宫的生成有关。由于你是按程序生成的,有时寻路算法会跳过迷宫的一些区块到达玩家。
可以通过调整迷宫的生成来解决此问题,以确保始终可以从迷宫中的任何其他点到达任何点。
您可以使用迷宫生成算法,例如prim或kruskal算法。
还有一件事我注意到的是,你正在使用的启发式函数来计算从节点到目标的距离,对于迷宫尝试使用欧几里德或切比雪夫距离来说并不是闲置的。
希望能有所帮助