Contents
Introduction
참고: 이 튜토리얼을 진행하기 전에 Get Started 튜토리얼을 읽는 것이 좋습니다. |
턴제 게임에서는 유닛이 이동할 수 있는 노드와 그 노드를 이동하는 데 드는 비용을 더 자세히 제어해야 할 때가 많습니다. 반면 대부분의 유닛이 한 번에 정지 상태에 있으므로 최대 경로 탐색 성능이 항상 필요한 것은 아닙니다.
모든 경로 요청 전에 그래프의 모든 노드에 대한 이동 비용 및 유사한 속성을 업데이트할 수 있지만, 이는 특히 깔끔한 해결책이 아니므로 이 패키지는 이를 수행할 수 있는 다른 방법을 제공합니다.
더 많은 제어가 필요한 경우 ITraversalProvider 섹션을 참조하십시오.
Blocking nodes
가장 일반적인 시나리오는 일부 유닛이 특정 노드를 통과하지 못하도록 차단하는 것입니다. 예를 들어, 턴제 게임에서는 유닛이 같은 타일에 서지 않도록 하는 경우가 많지만, 유닛 자체는 자신이 서 있는 타일에서 차단되지 않아야 합니다.
이 목적을 위해 BlockManager 컴포넌트와 그에 따른 SingleNodeBlocker 컴포넌트가 존재합니다. SingleNodeBlocker는 특정 노드를 쉽게 차단하기 위해 사용되며, 각 SingleNodeBlocker 컴포넌트는 정확히 하나의 노드를 차단합니다. BlockManager 컴포넌트는 모든 SingleNodeBlocker 컴포넌트를 추적하며, 경로에서 추가적으로 차단된 노드를 지정하는 데 사용할 수 있는 TraversalProvider 인스턴스를 생성할 수 있습니다.
참고: 이 기능의 별도 예제는 "Turnbased"라는 예제 장면에서 볼 수 있습니다. 이 예제 장면은 프로 기능에 의존하므로 무료 버전의 패키지에는 포함되어 있지 않습니다. 그러나 이 튜토리얼에서 언급된 기능은 프로 버전을 필요로 하지 않습니다. |
이 튜토리얼에서는 새로운 장면과 몇 가지 스크립트를 만들어 API를 테스트해 보겠습니다.
새 장면을 만들고 프로젝트에 저장한 후 원하는 이름으로 "TurnBasedTest"로 이름을 지정합니다. 새로운 GameObject를 추가하고 이름을 "BlockManager"로 지정한 다음, 선택하고 BlockManager 컴포넌트를 추가합니다.
이제 구체를 추가하고 위치를 (1.5, 0, 2.5)에 배치합니다. 이렇게 하면 노드의 중심에 위치하게 됩니다. SingleNodeBlocker 스크립트를 추가하고 이전에 만든 BlockManager 컴포넌트를 SingleNodeBlocker 컴포넌트의 "manager" 필드에 할당합니다. 구체의 콜라이더를 삭제하는 것을 잊지 마십시오. 그렇지 않으면 구체가 장애물로 감지되므로 SingleNodeBlocker를 사용하여 차단하려는 것입니다. 새로운 GameObject를 만들고 이름을 "A*"로 지정한 다음, AstarPath 컴포넌트를 추가합니다(메뉴 바 -> Pathfinding -> AstarPath). 장면에 큰 평면을 추가하여 바닥 평면으로 사용할 수 있습니다. AstarPath 컴포넌트에 그리드 그래프를 추가하고 "Unwalkable when no ground" 설정을 false로 설정합니다. 이제 Scan 버튼을 클릭하면 작은 빈 그리드에 단일 구체가 있는 것을 볼 수 있습니다. 구체가 그래프의 어떤 노드도 차단하지 않는다는 점에 유의하십시오.
이제 SingleNodeBlocker가 실제로 위치를 차단하도록 해야 합니다. 새로운 C# 스크립트 "BlockerTest.cs"를 만들고 다음 코드를 추가합니다:
using UnityEngine;
using System.Collections;
using Pathfinding;
public class BlockerTest : MonoBehaviour {
public void Start () {
var blocker = GetComponent<SingleNodeBlocker>();
blocker.BlockAtCurrentPosition();
}
}
그 새로운 스크립트를 우리가 이전에 만든 구체에 추가합니다. 게임이 시작되면, 해당 스크립트는 SingleNodeBlocker 컴포넌트가 BlockManager에게 그 객체의 위치에 있는 노드를 점유하고 있다고 알리도록 합니다. 그러나 이것만으로는 충분하지 않습니다. 아직 어떤 경로도 노드가 차단되었다는 것을 알지 못합니다.
실제로 경로를 계산하려면 "BlockerPathTest.cs"라는 새로운 스크립트를 만들어야 하며, 이 스크립트에는 다음 코드를 포함해야 합니다:
using UnityEngine;
using System.Collections.Generic;
using Pathfinding;
public class BlockerPathTest : MonoBehaviour {
public BlockManager blockManager;
public List<SingleNodeBlocker> obstacles;
public Transform target;
BlockManager.TraversalProvider traversalProvider;
public void Start () {
// obstacles 배열에 있는 모든 SingleNodeBlocker에 의해 경로가 차단되어야 한다고 말하는 traversal provider를 생성합니다.
traversalProvider = new BlockManager.TraversalProvider(blockManager, BlockManager.BlockMode.OnlySelector, obstacles);
}
public void Update () {
// 새로운 Path 객체를 생성합니다.
var path = ABPath.Construct(transform.position, target.position, null);
// 경로가 특정 traversal provider를 사용하도록 만듭니다.
path.traversalProvider = traversalProvider;
// 경로를 동기적으로 계산합니다.
AstarPath.StartPath(path);
path.BlockUntilCalculated();
if (path.error) {
Debug.Log("No path was found");
} else {
Debug.Log("A path was found with " + path.vectorPath.Count + " nodes");
// 씬 뷰에 경로를 그립니다.
for (int i = 0; i < path.vectorPath.Count - 1; i++) {
Debug.DrawLine(path.vectorPath[i], path.vectorPath[i + 1], Color.red);
}
}
}
}
이 스크립트는 지정된 리스트에 있는 장애물을 피하기 위해 생성된 TraversalProvider를 사용하여 자신의 위치에서 대상의 위치까지의 경로를 매 프레임 계산합니다.
BlockManager.TraversalProvider에는 두 가지 모드가 있습니다: AllExceptSelector와 OnlySelector. AllExceptSelector 모드가 설정되면 지정된 리스트에 있는 노드를 제외한 모든 SingleNodeBlocker 컴포넌트에 의해 차단된 노드는 통행 불가능한 것으로 처리됩니다. 예를 들어, 특정 유닛이 자신을 제외한 모든 유닛을 피하도록 하거나, 아군은 피하고 적군은 피하지 않도록 하고 싶을 때 유용합니다. OnlySelector 모드가 설정되면 리스트에 있는 SingleNodeBlocker에 의해 차단된 모든 노드는 통행 불가능한 것으로 처리됩니다. 성능상의 이유로 선택기 리스트를 상대적으로 작게 유지하는 것이 좋습니다.
Pathfinding.BlockManager.BlockMode 참조 |
새로운 GameObject를 "Target"이라는 이름으로 만들고 예를 들어 위치를 (3.5, 0, 3.5)에 배치합니다. 또한 "Path Searcher"라는 이름의 GameObject를 만들고 새로운 BlockerPathTest 컴포넌트를 추가합니다. 객체를 위치 (-2.5, 0, 3.5)로 이동시키고 "Block Manager"와 "Target" 필드를 할당합니다. 이제 재생 버튼을 누르면 빨간색 선이 "Path Searcher"에서 "Target"으로 이어지는 것을 볼 수 있습니다. 이 선이 구체를 통과하는 것처럼 보일 것입니다. 이는 검색기의 "Obstacles" 리스트에 추가하지 않았기 때문입니다.
게임을 중지하고 구체의 SingleNodeBlocker 컴포넌트를 리스트에 추가한 다음 다시 재생 버튼을 누르면 이제 피하게 되는 것을 볼 수 있습니다.
이제 이것을 확장하여 예를 들어 여러 개의 빨간 구체와 여러 개의 파란 구체를 만들고, 하나는 파란 구체만 장애물로 간주하고 다른 하나는 빨간 구체만 장애물로 간주하는 두 검색기를 만들 수 있습니다. 아래 비디오에서 이를 확인할 수 있습니다.
ITraversalProvider
위 시스템은 간단한 경우에 적합하고 사용하기 쉽습니다. 그러나 더 복잡한 경우에는 ITraversalProvider 인터페이스를 사용하는 것이 좋습니다. 이에 대해서는 Agent-Specific Pathfinding에서 더 읽어볼 수 있습니다.
'유니티 에셋 > A* Pathfinding project pro' 카테고리의 다른 글
Manual Player Movement (0) | 2024.05.26 |
---|---|
Circling a target (0) | 2024.05.26 |
Pathfinding in 2D > Pathfinding on tilemaps (0) | 2024.05.25 |
Pathfinding in 2D (0) | 2024.05.25 |
Agent-Specific Pathfinding (0) | 2024.05.25 |