1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19 20 21 22 23 24 25 26 27 28 29 30 31 32 33 34 35 36 37 38 39 40 41 42 43 44 45 46 47 48 49 50 51 52 53 54 55 56 57 58 59 60 61 62 63 64 65 66 67 68 69 70 71 72 73 74 75 76 77 78 79 80 81 82 83 84 85 86 87 88 89 90 91 92 93 94 95 96 97 98 99 100 101 102 103 104 105 106 107 108 109 110 111 112 113 114 115 116 117 118 119 120 121 122 123 124 125 126 127 128 129 130 131 132 133 134 135 136 137 138 139 140 141 142 | using UnityEngine; using System.Collections; using System.Collections.Generic; using System; public class AStar { public class ANode : IComparable { public Vector3 Location { get; private set; } public int CostFromStart { get; private set; } public float CostToGoal { get; private set; } public ANode Parent { get; private set; } public ANode(Vector3 location) { this.Location = location; } public bool LocationEqual(ANode other) { if (other.Location == this.Location) { return true; } return false; } public int CompareTo(object other) { if ((other is ANode) == false) return 0; return CostFromStart.CompareTo((other as ANode).CostFromStart); } public void SetFromCost(int cost) { CostFromStart = cost; } public void SetToCost(float cost) { CostToGoal = cost; } public void SetParent(ANode node) { Parent = node; } } PriorityQueue<ANode> openList; List<ANode> closeList; ANode startNode; ANode goalNode; public AStar(Vector3 location, Vector3 destination) { openList = new PriorityQueue<ANode>(); closeList = new List<ANode>(); goalNode = new ANode(destination); startNode = new ANode(location); startNode.SetFromCost(0); startNode.SetToCost(PathCostEstimate(startNode)); openList.Add(startNode); AddProximityNode(startNode); Clac(); } private float PathCostEstimate(ANode node) { return Mathf.Pow(goalNode.Location.x - node.Location.x, 2) + Mathf.Pow(goalNode.Location.y - node.Location.y, 2); } public bool Clac() { while (openList.Count != 0 && openList.Count < 20000) { ANode node = openList.Pop(); Debug.Log("Pos:" + node.Location + " FromCost:" + node.CostFromStart + " ToCost:" + node.CostToGoal); if (goalNode.LocationEqual(node)) return true; else { AddProximityNode(node); } closeList.Add(node); } Debug.Log(openList.Count); return false; } public void AddProximityNode(ANode center) { int tempX; int tempY; for (int x = -1; x < 2; x++) { if (x != 0) { tempX = (int)center.Location.x + x; tempY = (int)center.Location.y; if (tempX >= 0) { if (TileLayer.instance.GetWalkable(tempX, tempY)) { ANode node = new ANode(new Vector3(tempX, tempY)); node.SetFromCost(center.CostFromStart + 1); node.SetToCost(PathCostEstimate(node)); node.SetParent(center); openList.Add(node); } } } } for (int y = -1; y < 2; y++) { if (y != 0) { tempX = (int)center.Location.x; tempY = (int)center.Location.y + y; if (tempY >= 0) { if (TileLayer.instance.GetWalkable(tempX, tempY)) { ANode node = new ANode(new Vector3(tempX, tempY)); node.SetFromCost(center.CostFromStart + 1); node.SetToCost(PathCostEstimate(node)); node.SetParent(center); openList.Add(node); } } } } } } | cs |
아직 다만든건 아니지만 테스트하면서 로그찍어보고 멘붕
2만번 루프 결과
시작은 0. 0 목적지 0. 10
알고리즘 이해 자체를 잘못한거 같아서 다시 글들 읽어봐야겟음..
대난하다 난 애초에 포기하고 에셋 구입...
A*는 h cost(시작점부터 현재 노드까지의 비용 + 현재 노드부터 목적지까지 예상비용)가 가장 낮은 노드들을 열고 닫으면서 최적 거리를 찾는 알고리즘임. 이를 위해서 현재노드, open set, close set이 필요함. 현재 노드는 처음에는 start node이고 이후 루프를 돌면서 openset 중에서 가장 h cost가 낮은 노드로 결정됨.(참고로 현재 노드가 되는 순간 open set에서 close set으로 넣어야 함) 그리고 모든 현재 노드의 인접 노드에 대해(이동할 수 있는 노드.. 이 스크립트에서는 상하 좌우인듯?) 해당 인접 노드의 h cost를 계산하는데 h cost는 현재노드의 출발점으로부터의 비용 + 인접노드의 목적까지의 비용으로 계산함
그리고 인접 노드들을 open set에 추가함. 그리고 open set 중에서 가장 h cost가 가장 낮은 노드를 다시 현재 노드로 설정하면서 경로 저장을 위해 자신 이전의 현재노드를 저장함(길찾기를 하기 위함) 이 과정을 계속 반복하면 최단경로를 계산할 수 있다는 이론임..
뭐가 문제인지는 직접 굴려보면서 해보지 않으면 자세히 알 수는 없겠지만 일단 goal까지의 비용은 직선거리를 구할려고 했던 거면 제곱근을 취해야했고, 상하좌우로밖에 못움직이니까 아마 Math.pow를 쓰면 안되고 abs로 절대값을 구해서 더해는게 맞을듯. 글고 처음 노드를 오픈셋에 넣어놨기떔에 calc() 호출 전에 AddProximityNode(startNode)는 필요없음..
아 open set 중에서 h cost가 가장 낮은게 아니라 f cost가 가장 낮은거를 다음 노드로 고르는거였다... 햇갈림. 그런 고로 우선순위 큐말고 리스트로 open set을 관리하고 그 중에서 f cost가 가장 낮은 노드를 다음 현재 노드로 설정하는 부분이 스크립트에 없네..
글고 인접 노드들의 h cost를 결정하고 open set에 추가할 때, 이미 닫힌 close set에 속하는 노드를 제외하는 부분이 스크립트에 없다. 이러면 닫아 놓은 노드에 대해서도 재연산을 하기 때문에 무한루프에 빠져버린건 이 부분이 문제일거임..
아.. h cost랑 f cost랑 헷갈렷네.. 혼란을 줄것같으니 걍 새로 글 써줄께 댓글 무시하셈... 지울수가 없네 ㅋㅋ;
헉 ㅋㅋㅋ ㅇㄴ님 코드리뷰 감사해욧.. 안타깝게도 다른분 도움으로 이미 해결봄 ..