보통의 인체형 모델은 애미메이션을 수행하기 위해 Rig(본 구조, 뼈대)가 설정돼 있다.적 캐릭터 모델도 이러한 관절이 설정돼 있으며 하리라키 뷰에서 확인할 수 있다. 하이라키 뷰상에 표시된 각 관절은 게임오브젝트이며 모드 Transform 컴포넌트를 가지고 있다. 이렇게 하나의 3D모델안의 많은 Transform연산은 로드가 높으므로 최적화가 필요하다. 필요한것만 두고 다른것들은 노출되지 않게 하면 속도 향상에 도움을 줄 수 있다.
몬스터 모델에서 필요한 Rig는 Sphere Collider와 Rigidbody를 추가한 양손이므로 이부분만을 하이라키 뷰에 노출되게 설정해보자. 05.Models/Monster폴더에 있는 Monster원본 모델을 선택후 인스펙터뷰 Rig 탭의 Optimize Game Objects 옵션을 선택하면 하단에 Extra Transforms to Exppose 항목이 나타난다.
L_wrist와 R_wrist만 선택하고 Apply를 누르면 하이라키뷰의 Monster가 정리된걸 볼 수 있다.
)
본 구조 최적화는 프리팹으로 만들기 전에 해야한다. 하이라키뷰의 Monster는 아직 프리팹으로 만들기 전이므로 원본 Monster모델을 선택하고 본 구조를 최적화 할 수 있었다.
물론 스크린좌표를 월드좌표로 변환해서 레이를 쏴서 그 오브젝트를 바라보게해도 되는데 간단하게 LookAt()을 이용해보겠다.
스크립트를 하나 만들고 RightClick으로 이름 짓는다. 스크립트를 Player에 적용한다.
Monster 인스펙터 TAG가 MONSTER로 되어 있어야 한다.
FindwidhtTag()로 간단히 찾아 monsterTR에 저장하고 LookAt()을 이용해 방향을 바꾼다.
다만. 순간적으로 바꿔지기 때문에 부드럽게 바꾸려면 다른 함수를 써야 한다.
using System.Collections;
using System.Collections.Generic;
using UnityEngine;
public class RightClick : MonoBehaviour
{
// Start is called before the first frame update
private Transform monsterTr; //컴포넌트의 캐시를 처리할 변수
void Start()
{
monsterTr = GameObject.FindWithTag("MONSTER").GetComponent<Transform>();
}
// Update is called once per frame
void Update()
{
if (Input.GetMouseButtonDown(1)) {
transform.LookAt(monsterTr);
}
}
}
다른 방법은 어차피 NavMesh가 적에 적용되어 있으니 그걸 응용해보기로 했다. 목적은 자동추적보다는 플레이어의 자동 회전에 가깝다. 일단 하이리키 Player에 NavMesh Agent를 추가한다.
교재의 프로젝트에 영향을 주지 않게 하기 위해 따로 스크립트도 추가하고 NavCtrl로 이름짓는다.
코드는 간단하다. 마우스 우클릭을 하면 Player가 자동으로 적을 따라가고 다시 우클릭을 하면 멈춘다.
다른 스크립트에도 Navigation을 멈추게 하기 위해 SetNavStop()을 추가한다.
public void SetNavStop() {
agent.isStopped = true;
}
추가된 NavCtrl 전체코드, 대부분 MonsterCtrl에서 NavMesh에 관련된 코드를 복붙했다.
using System.Collections;
using System.Collections.Generic;
using UnityEngine;
using UnityEngine.AI; //for Navigation
public class NavCtrl : MonoBehaviour
{
// Start is called before the first frame update
private NavMeshAgent agent;
private Transform monsterTr; //컴포넌트의 캐시를 처리할 변수
void Start()
{
agent = GetComponent<NavMeshAgent>();
agent.isStopped = true; //추적을 중지
monsterTr = GameObject.FindWithTag("MONSTER").GetComponent<Transform>();
}
// Update is called once per frame
void Update()
{
if (Input.GetMouseButtonDown(1)) {
if (agent.isStopped == true) {
agent.SetDestination(monsterTr.position); //목표설정
agent.isStopped = false; //추적을 개시
} else {
agent.isStopped = true; //추적을 중지
}
}
}
public void SetNavStop() {
agent.isStopped = true;
}
}
WASD키를 눌렀을때 Navigation을 멈추기 위해 다음 코드를 PlayerCtrl스크립트 PlayerAnim() 맨윗에 추가한다.
GetComponent<NavCtrl>().SetNavStop();로 NavCtrl의 SetNavStop에 접근할 수 있다. 스크립트 이름이 class이름이고 이걸 GetComponet<T>의 인수로 바로 사용할 수 있다.
주인공 캐릭터(Player)가 쏜 총알이 몬스터에 명중하면 몬스터가 피를 흘리는 혈흔 효과(Blood Effect)를 추가해보자. 혈은 효과는 파티클로 구현하며 프로젝트뷰의 03.Prefabs/EffecExamples/Blood/Prefabs폴더에 있는 BloodSprayeffect를 사용한다. 버전의 차이인지 발견하지 못해서 아래 EffectExamples > Goop Effects > Prefabs> GoopSpray를 사용하였다.
Resources 폴더
지금까지는 프리팹을 사용하기 위해 public GameObject xxx를 선언하고 인스펙터에서 연결해놓고 사용하였다. 이번에는 스크립트에서 런모드(동적)으로 로드하는 방법을 사용한다. 이방법을 쓰기 위해서는 프리팹이나 에셋이 Resouces 폴더안에 있어야 한다.
Assets root에 Resources 폴더를 하나 만들자. BloodSprayeffect나 GoopSpray를 끌어다 놓는다. 이 Resources폴더는 빌드할때 포함되므로 필요한 것들만 놓기 바랍니다.
MonsterCtrl 스크립트에 다음과 같이 추가한다. Goopspray효과는 피튀는게 좀 작아서 localScale을 변경해 크게했다
blood.transform.localScale = new Vector3(5, 5, 5); //효과가 작아서 확대했다.
효과의 인스턴스를 만드는데 인수가 4개이다 마지막 monsterTr의 Child로 만들겠다는 뜻이다.