Unity용 RTS 및 MOBA 플레이어 컨트롤러
비디오 게임에서 RTS라는 용어는 실시간 전략을 의미합니다.
RTS와 기존 1인칭/3인칭 슈팅 게임의 차이점은 일반적인 W, A, S, D 버튼이 아닌 마우스 포인터를 사용하여 캐릭터를 제어한다는 점입니다.
플레이어는 군대를 직접 조종하지 않고도 군대에 명령을 내릴 수 있는 능력을 통해 전장을 한눈에 볼 수 있습니다. RTS 게임의 예로는 Warcraft, Starcraft, Cossacks 등이 있습니다.

반면, MOBA는 Multiplayer Online Battle Arena의 약자로, 플레이어가 여러 캐릭터가 아닌 단 한 명의 캐릭터만 제어하는 RTS 게임의 다소 새로운 하위 장르입니다.
이러한 게임의 예로는 리그 오브 레전드(League of Legends)와 도타 2(Dota 2)가 있습니다.
이 튜토리얼에서는 Unity에서 RTS/MOBA 스타일 컨트롤러를 만드는 방법을 보여 드리겠습니다.
1단계: 필요한 스크립트를 만들어 보겠습니다.
이 튜토리얼은 하나의 스크립트만 필요하므로 매우 간단합니다.
RTSPlayerController.cs
//You are free to use this script in Free or Commercial projects
//sharpcoderblog.com @2018
using UnityEngine;
using UnityEngine.AI;
[RequireComponent(typeof(NavMeshAgent))]
public class RTSPlayerController : MonoBehaviour
{
public Camera playerCamera;
public Vector3 cameraOffset;
public GameObject targetIndicatorPrefab;
NavMeshAgent agent;
GameObject targetObject;
// Use this for initialization
void Start()
{
agent = GetComponent<NavMeshAgent>();
//Instantiate click target prefab
if (targetIndicatorPrefab)
{
targetObject = Instantiate(targetIndicatorPrefab, Vector3.zero, Quaternion.identity) as GameObject;
targetObject.SetActive(false);
}
}
// Update is called once per frame
void Update()
{
#if (UNITY_ANDROID || UNITY_IOS || UNITY_WP8 || UNITY_WP8_1) && !UNITY_EDITOR
//Handle mobile touch input
for (var i = 0; i < Input.touchCount; ++i)
{
Touch touch = Input.GetTouch(i);
if (touch.phase == TouchPhase.Began)
{
MoveToTarget(touch.position);
}
}
#else
//Handle mouse input
if (Input.GetKeyDown(KeyCode.Mouse0))
{
MoveToTarget(Input.mousePosition);
}
#endif
//Camera follow
playerCamera.transform.position = Vector3.Lerp(playerCamera.transform.position, transform.position + cameraOffset, Time.deltaTime * 7.4f);
playerCamera.transform.LookAt(transform);
}
void MoveToTarget(Vector2 posOnScreen)
{
//print("Move To: " + new Vector2(posOnScreen.x, Screen.height - posOnScreen.y));
Ray screenRay = playerCamera.ScreenPointToRay(posOnScreen);
RaycastHit hit;
if (Physics.Raycast(screenRay, out hit, 75))
{
agent.destination = hit.point;
//Show marker where we clicked
if (targetObject)
{
targetObject.transform.position = agent.destination;
targetObject.SetActive(true);
}
}
}
}
2 단계
이제 플레이어 컨트롤러와 게임 레벨을 설정해 보겠습니다.
- 새로운 GameObject를 생성하고 호출합니다. 'RTSPlayer'
- RTSPlayerController.cs 스크립트를 연결합니다(참고: 연결 시 NavMeshAgent라는 다른 구성 요소가 자동으로 추가됩니다. 이 구성 요소는 나중에 필요합니다)

- 플레이어 본체를 추가합니다(제 경우에는 큐브가 포함된 간단한 캡슐을 사용하지만 플레이어 모델이 있으면 추가할 수 있습니다). 원하는 크기가 될 때까지 크기를 줄입니다.
- 플레이어 모델을 'RTSPlayer' GameObject 내부로 이동합니다. (참고: 부모 역할을 하기 전에 'RTSPlayer'이 플레이어 모델 하단에 배치되어 있는지 확인하세요.)


- 'RTSPlayer'을 선택하고 NavMeshAgent에서 플레이어 모델과 일치할 때까지 반경 및 높이를 조정합니다.

- 다음은 대상 표시기 prefab를 만드는 것입니다. 이것은 지도에서 클릭한 위치를 나타내는 쿼드가 있는 단순한 게임 개체입니다.

![]()

아래 텍스처를 사용할 수 있습니다.

- 마지막으로 'RTSPlayer'을 선택하고 RTSPlayerController 스크립트에 필요한 모든 변수를 할당합니다.
플레이어 카메라 - 설명이 필요 없으며 모든 카메라가 가능합니다.
카메라 오프셋 - 카메라가 플레이어로부터 얼마나 멀리 떨어져 있어야 하는지
Target Indicator Prefab - 방금 생성한 프리팹

플레이 모드에서는 지도를 클릭해도 플레이어가 움직이지 않는다는 것을 알 수 있습니다. 마지막으로 해야 할 일이 하나 있기 때문입니다. 바로 내비게이션 메시(Navmesh)를 굽는 것입니다.
- 지도의 일부인 모든 객체를 선택하고 정적으로 표시합니다.

![]()
- 창 -> AI -> 탐색으로 이동합니다.

- Bake 탭에서 Agent Radius 및 Agent Height 값(NavMeshAgent의 값과 일치해야 함)을 변경한 다음 Bake를 클릭합니다.

- 베이킹이 완료되면 걸어갈 수 있는 영역을 나타내는 파란색 윤곽선의 메시가 표시됩니다.

참고: 플레이어가 언덕 위로 걷는 것을 방지하려면 굽기 탭으로 돌아가서 최대 경사 각도를 줄인 다음 내비메시를 다시 굽습니다.
![]()

훨씬 낫다!
마지막으로 플레이 모드로 돌아가서 지도의 아무 곳이나 마우스 왼쪽 버튼으로 클릭하세요.
이제 플레이어는 장애물을 피하면서 목표를 향해 움직여야 합니다.
![]()
팁: NavMeshagent에서 필요에 맞게 속도, 각속도 및 가속도 값을 조정하세요.