public LinkedList<Node> PathFinding(Vector2Int startPos, Vector2Int endPos)
{
// 닫힌 노드 목록: 이미 경로에 포함된 노드들
LinkedList<Node> closedNodes = new LinkedList<Node>();
// 목적지가 맵 안에 없거나, 출발지와 동일하면 빈 경로 반환
if (!grids.ContainsKey(endPos))
{
closedNodes.Clear();
return closedNodes;
}
if (startPos == endPos)
{
closedNodes.Clear();
return closedNodes;
}
// 열린 노드 목록: 탐색 후보들
LinkedList<Node> openNodes = new LinkedList<Node>();
bool isSearchDone = false;
// 시작 노드를 닫힌 목록에 추가하고 GH값 설정
closedNodes.AddLast(grids[startPos]);
grids[startPos].SetGH(startPos, endPos);
short whileCounterMax = 1000; // 무한루프 방지용 안전장치
// 메인 탐색 루프
while (!isSearchDone)
{
// 현재 닫힌 노드의 주변을 검사해서 이동 가능한 노드를 openNodes에 추가
GetNearOpenNodes(ref openNodes, closedNodes.Last().nodeCenterPosition, closedNodes);
Vector2Int lowerstHNodePos = Vector2Int.zero; // 가장 낮은 H값을 가진 후보 노드
int lowerstHValue = int.MaxValue;
// 열린 노드 중에서 가장 좋은 후보를 고름
while (openNodes.Count > 0)
{
Node node = openNodes.First();
node.SetGH(startPos, endPos); // GH값 업데이트
openNodes.RemoveFirst();
// 이동 가능하고, 해당 위치에 캐릭터가 없거나 목적지인 경우에만 후보로 고려
if (lowerstHValue > node.H && node.isMoveableTile &&
(node.CharacterOnNode == null || endPos == node.nodeCenterPosition))
{
lowerstHValue = node.H;
lowerstHNodePos = node.nodeCenterPosition;
}
// 목적지에 도달하면 탐색 종료
if (endPos == node.nodeCenterPosition)
{
isSearchDone = true;
openNodes.Clear();
}
}
openNodes.Clear();
// 후보가 유효하지 않으면 루프 탈출
if (!grids.ContainsKey(lowerstHNodePos))
break;
// 연결 경로 설정 (현재 노드에 이전 노드 연결)
grids[lowerstHNodePos].connectedNode = closedNodes.Last();
// 최종 후보를 닫힌 노드 목록에 추가
closedNodes.AddLast(grids[lowerstHNodePos]);
// 무한 루프 방지 카운터
--whileCounterMax;
if (whileCounterMax <= 0) isSearchDone = true;
}
// 도착지까지 도달하지 못했거나, 경로가 잘못된 경우
if (closedNodes.Last() != grids[endPos] || closedNodes.First() != grids[startPos])
{
return new LinkedList<Node>();
}
// 경로 이중 확인: 연결된 노드들을 따라 시작점까지 역추적
isSearchDone = false;
whileCounterMax = 1000;
LinkedList<Node> doubleCheckedNodes = new LinkedList<Node>();
doubleCheckedNodes.AddFirst(closedNodes.Last());
while (!isSearchDone)
{
// 이전 노드로 따라가며 경로 재구성
GetNearClosedNodes(ref doubleCheckedNodes, doubleCheckedNodes.First().nodeCenterPosition, closedNodes);
if (doubleCheckedNodes.First() == grids[startPos] || whileCounterMax <= 0)
{
isSearchDone = true;
}
whileCounterMax--;
}
// 다시 추적한 경로가 유효한지 최종 확인
if (doubleCheckedNodes.Last() != grids[endPos] || doubleCheckedNodes.First() != grids[startPos])
{
return new LinkedList<Node>();
}
// 최종 경로 반환 (시작점 → 도착점 방향)
return doubleCheckedNodes;
}
비판점
- 일단 너무 길다. 재 작업을 하려해도 할 수 없는 구조
- 노드 역추적시 While을 통째로 한 함수에 박아놓은 나 자신을 용서 할 수 없는 구조
- 클린코드 작성이 필요할 것 같다(대표적으로 변수명). 내일 TIL의 목표로 작성요망
- 재귀호출을 통해 코드를 좀 더 간결하게 작업하는 연습이 필요
- 일단 이렇게 적진 말아야겠다는 교훈
그나마 잘한거
- 맥스루프를 정해두어 적어도 터지는걸 막았다.
- 기능에 문제는 없었다