在c#中,如何在A星寻径类中添加对角线?

本文关键字:对角线 添加 | 更新日期: 2023-09-27 18:15:37

我有一个使用a *的简单寻径类,但是它只覆盖贴图中的四个基本方向。它服从墙壁并避开它们,但在开放空间中,它创造了一个曲折的模式来到达它的目的地。

我想简化这个模式,包括对角线-在地图的开放区域,但到目前为止,如果我使用对角线,它似乎完全忽略了墙壁。

我如何解决这个问题并正确地添加对角线?

using UnityEngine;
using System.Collections.Generic;
public class AStar {
    private List<Node> openList;
    private List<Node> closeList;
    private List<Node> neighbors;
    private List<Node> finalPath;
    private Node start;
    private Node end;
    public AStar()
    {
        openList = new List<Node>();
        closeList = new List<Node>();
        neighbors = new List<Node>();
        finalPath = new List<Node>();
    }
    public void FindPath(MazeCell startCell, MazeCell goalCell)
    {
        start = new Node(0, 0, 0, null, startCell);
        end = new Node(0, 0, 0, null, goalCell);
        openList.Add(start);
        bool keepSearching = true;
        bool pathExists = true;
        while(keepSearching && pathExists)
        {
            Node currentNode = ExtractBestNodeFromOpenList();
            if (currentNode == null)
            {
                pathExists = false;
                break;
            }
            closeList.Add(currentNode);
            if (NodeIsGoal(currentNode))
            {
                keepSearching = false;
            } else
            {
                FindValidFourNeighbors(currentNode);
            }
            foreach(Node neighbor in neighbors)
            {
                if (FindInList(neighbor, closeList) != null)
                    continue;
                Node inOpenList = FindInList(neighbor, openList);
                if (inOpenList == null)
                {
                    openList.Add(neighbor);
                } else
                {
                    if (neighbor.G < inOpenList.G)
                    {
                        inOpenList.G = neighbor.G;
                        inOpenList.F = inOpenList.G + inOpenList.H;
                        inOpenList.parent = currentNode;
                    }
                }
            }
        }
        if (pathExists)
        {
            Node n = FindInList(end, closeList);
            while (n != null)
            {
                finalPath.Add(n);
                n = n.parent;
            }
        }
    }
    public bool ContainsCoordinates(IntVector2 coordinate)
    {
        return coordinate.x >= 0 && coordinate.x < GameConfig.mazeSize && coordinate.z >= 0 && coordinate.z < GameConfig.mazeSize;
    }
    private void FindValidFourNeighbors(Node node)
    {
        neighbors.Clear();
        // Check South of this Cell //
        int south = node.cell.mazeCellCoordinates.z - 1;
        IntVector2 SouthNeighbor = new IntVector2(node.cell.mazeCellCoordinates.x , south);
        int north = node.cell.mazeCellCoordinates.z + 1;
        IntVector2 NorthNeighbor = new IntVector2(node.cell.mazeCellCoordinates.x, north);
        int east = node.cell.mazeCellCoordinates.x + 1;
        IntVector2 EastNeighbor = new IntVector2(east, node.cell.mazeCellCoordinates.z);
        int west = node.cell.mazeCellCoordinates.x - 1;
        IntVector2 WestNeighbor = new IntVector2(west, node.cell.mazeCellCoordinates.z);
        IntVector2 SouthEastNeighbor = new IntVector2(south, east);
        IntVector2 SouthWestNeighbor = new IntVector2(south, west);
        IntVector2 NorthEastNeighbor = new IntVector2(north, east);
        IntVector2 NorthWestNeighbor = new IntVector2(north, west);
        if (ContainsCoordinates(SouthNeighbor))
        {
            if (Maze.Instance.cellStorage[SouthNeighbor.x, SouthNeighbor.z].IsWalkable)
            {
                MazeCell c = Maze.Instance.cellStorage[SouthNeighbor.x, SouthNeighbor.z];
                if (!(c.cellEdges[(int)MazeDirection.North] is MazeCellWall))
                {
                    Node vn = PrepareNewNode(node, 0, -1);
                    neighbors.Add(vn);
                }
            }
        }

        if (ContainsCoordinates(NorthNeighbor))
        {
            if (Maze.Instance.cellStorage[NorthNeighbor.x, NorthNeighbor.z].IsWalkable)
            {
                MazeCell c = Maze.Instance.cellStorage[NorthNeighbor.x, NorthNeighbor.z];
                if (!(c.cellEdges[(int)MazeDirection.South] is MazeCellWall))
                {
                    Node vn = PrepareNewNode(node, 0, 1);
                    neighbors.Add(vn);
                }
            }
        }
        if (ContainsCoordinates(WestNeighbor))
        {
            if (Maze.Instance.cellStorage[WestNeighbor.x, WestNeighbor.z].IsWalkable)
            {
                MazeCell c = Maze.Instance.cellStorage[WestNeighbor.x, WestNeighbor.z];
                if (!(c.cellEdges[(int)MazeDirection.East] is MazeCellWall))
                {
                    Node vn = PrepareNewNode(node, -1, 0);
                    neighbors.Add(vn);
                }
            }
        }
        if (ContainsCoordinates(EastNeighbor))
        {
            if (Maze.Instance.cellStorage[EastNeighbor.x, EastNeighbor.z].IsWalkable)
            {
                MazeCell c = Maze.Instance.cellStorage[EastNeighbor.x, EastNeighbor.z];
                if (!(c.cellEdges[(int)MazeDirection.West] is MazeCellWall))
                {
                    Node vn = PrepareNewNode(node, 1, 0);
                    neighbors.Add(vn);
                }
            }
        }
    }
    private float Heuristic(Node n)
    {
        return Mathf.Sqrt((n.cell.mazeCellCoordinates.x - end.cell.mazeCellCoordinates.x) * (n.cell.mazeCellCoordinates.x - end.cell.mazeCellCoordinates.x) + (n.cell.mazeCellCoordinates.z - end.cell.mazeCellCoordinates.z) * (n.cell.mazeCellCoordinates.z - end.cell.mazeCellCoordinates.z));
    }
    private float MovementCost(Node a, Node b)
    {
        return Maze.Instance.cellStorage[b.cell.mazeCellCoordinates.x, b.cell.mazeCellCoordinates.z].movementCost();
    }
    private Node PrepareNewNode(Node n, int x, int z)
    {
        IntVector2 iv = new IntVector2(n.cell.mazeCellCoordinates.x + x, n.cell.mazeCellCoordinates.z + z);
        Node node = new Node(0, 0, 0, n, Maze.Instance.cellStorage[iv.x, iv.z]);
        node.G = n.G + MovementCost(n, node);
        node.H = Heuristic(node);
        node.F = node.G + node.H;
        node.parent = n;
        return node;
    }
    public List<MazeCell> CellsFromPath()
    {
        List<MazeCell> path = new List<MazeCell>();
        foreach (Node n in finalPath)
        {
            path.Add(n.cell);
        }
        if (path.Count != 0)
        {
            path.Reverse();
            path.RemoveAt(0);
        }
        return path;
    }
    public List<int> PointsFromPath()
    {
        List<int> points = new List<int>();
        foreach (Node n in finalPath)
        {
            points.Add(n.cell.mazeCellCoordinates.x);
            points.Add(n.cell.mazeCellCoordinates.z);
        }
        return points;
    }
    bool NodeIsGoal(Node node)
    {
        return ((node.cell.mazeCellCoordinates.x == end.cell.mazeCellCoordinates.x) && (node.cell.mazeCellCoordinates.z == end.cell.mazeCellCoordinates.z));
    }
    Node FindInList(Node n, List<Node> xl)
    {
        foreach (Node nn in xl)
        {
            if ((nn.cell.mazeCellCoordinates.x == n.cell.mazeCellCoordinates.x) && (nn.cell.mazeCellCoordinates.z == n.cell.mazeCellCoordinates.z))
                return nn;
        }
        return null;
    }
    private Node ExtractBestNodeFromOpenList()
    {
        float minF = float.MaxValue;
        Node bestNode = null;
        foreach(Node n in openList)
        {
            if (n.F < minF)
            {
                minF = n.F;
                bestNode = n;
            }
        }
        if (bestNode != null)
        openList.Remove(bestNode);
        return bestNode;
    }
}

在c#中,如何在A星寻径类中添加对角线?

我之前已经用对角线实现了A*,您只需要将它们包含在可行的邻居列表中。

从技术上讲,你应该在启发式函数中做成本计算/排除,但看看你的代码,你肯定可以在private void FindValidFourNeighbors(Node node)中添加4个检查:

if (ContainsCoordinates(SouthEastNeighbor))
    {
        if (Maze.Instance.cellStorage[SouthEastNeighbor.x, SouthEastNeighbor.z].IsWalkable)
        {
            MazeCell c = Maze.Instance.cellStorage[SouthEastNeighbor.x, SouthEastNeighbor.z];
            if (!(c.cellEdges[(int)MazeDirection.South] is MazeCellWall) && !(c.cellEdges[(int)MazeDirection.East] is MazeCellWall))
            {
                Node vn = PrepareNewNode(node, 0, -1);
                neighbors.Add(vn);
            }
        }
    }

(不太清楚' cellledges '检查到底在做什么,但我认为你需要检查对角线的两边,这可能是你失败的地方。)