从A *

时间:2018-05-21 11:52:30

标签: c# unity3d a-star

我开始创建A *算法。玩家应该从左下角走到右上角。每个单元有不同的现场成本。成本为0意味着细胞不能走路。

有时玩家跳来跳去,因为在我的封闭列表中我没有最佳路径,一些“错误”的单元格也在那里。

你可以看看这里

https://cdn.discordapp.com/attachments/370618181892571136/446345906464358410/zgzugzzu.gif

我有一个map对象,用于创建地图并将所有cell个对象保存在cell类型的2D数组中。每个单元都知道自己的场成本,但是他们不需要知道它们的位置,因为数组通过传入x和y值来知道它。

有些解释说我必须存储当前检查节点的前任,并在将此路径用于其他路径时比较当前的成本值。

我该怎么做?

我当前的代码

private List < Vector2Int > openCells = new List < Vector2Int > ();
private List < Vector2Int > closedCells = new List < Vector2Int > ();

private void CalculatePath() {
 openCells.Clear();
 closedCells.Clear();

 openCells.Add(Settings.startPosition);

 Vector2Int currentCellPosition = Settings.startPosition;

 while (!PositionEquals(currentCellPosition, Settings.targetPosition) && openCells.Count > 0) {
  Vector2Int cheapestCellPosition = openCells
   .OrderBy(x => GetCostToTarget(x, Settings.targetPosition) + GetCell(x).Cost)
   .First();

  AddNeighbourPosition(cheapestCellPosition, Vector2Int.up);
  AddNeighbourPosition(cheapestCellPosition, Vector2Int.left);
  AddNeighbourPosition(cheapestCellPosition, Vector2Int.down);
  AddNeighbourPosition(cheapestCellPosition, Vector2Int.right);

  closedCells.Add(cheapestCellPosition);
  openCells.Remove(cheapestCellPosition);

  currentCellPosition = cheapestCellPosition;
 }
}

private void AddNeighbourPosition(Vector2Int currentPosition, Vector2Int neighbourDirection) {
 Vector2Int targetPosition = currentPosition + neighbourDirection;

 if (CellExistsOnMap(targetPosition)) {
  if (CellIsWalkable(targetPosition)) {
   if (!CellExamined(targetPosition)) {
    openCells.Add(targetPosition);
   }
  }
 }
}

private bool PositionEquals(Vector2Int startPosition, Vector2Int targetPosition) {
 return startPosition.Equals(targetPosition);
}

private bool CellIsWalkable(Vector2Int position) {
 return GetCell(position).Cost != 0;
}

private Cell GetCell(Vector2Int position) {
 return map.Cells[position.x, position.y];
}

private int GetCostToTarget(Vector2Int startPosition, Vector2Int targetPosition) {
 return Mathf.Abs(startPosition.x - targetPosition.x) + Mathf.Abs(startPosition.y - targetPosition.y);
}

private bool CellExistsOnMap(Vector2Int position) {
 int horizontalLength = Settings.fields.GetLength(0);
 int verticalLength = Settings.fields.GetLength(1);
 Rect mapRect = new Rect(0, 0, horizontalLength, verticalLength);

 return mapRect.Contains(position);
}

private bool CellExamined(Vector2Int position) {
 return openCells.Contains(position) || closedCells.Contains(position);
}

1 个答案:

答案 0 :(得分:2)

首先,你没有正确实施A *而错过了一些观点,

  1. 到目前为止路径距离的代码中没有任何功能 (G)
  2. 只有在不包含邻居时才将邻居添加到开放列表中 已经,这是错误的,你必须比较当前的细胞总数 成本并将其与公开名单中的旧成本进行比较,如果是 您需要更新列表中的单元成本...
  3. 为了保持对当前单元格的前任的引用,您需要更改单元格数据结构,建议将其作为避免GC分配的结构,但结构不能具有相同类型结构的字段存储前一个,因为它创建一个循环。 如果您的地图大小很小并且每个单元格预先没有调用路径查找过程,那么使用类实现它就可以了。

    public class Cell
    {
    public Vector2Int Position { get;set;}
    public int Cost {get;set;}
    public Cell Parent {get;set;}
    }
    

    另一种选择是使用LinkedList为您的封闭列表跟踪目标单元格到当前单元格。

    您还没有分享代码,当您的计算结束时,如何从封闭列表中找到路径,我相信跳跃问题来自那里