반응형
위키북스 출판사 이재현 저자님의 '절대강좌! 유니티' 책을 참고하여 필기한 내용입니다.
using System.Collections;
using UnityEngine;
using UnityEngine.AI; // 내비게이션 기능을 사용하기 위해 추가해야 하는 네임 스페이스
public class MonsterCtrl : MonoBehaviour
{
// 몬스터 상태의 정보
public enum State
{
IDLE,
TRACE,
ATTACK,
DIE
}
// 몬스터 현재 상태
public State state = State.IDLE;
// 추적 사정거리
public float traceDist = 10.0f;
// 공격 사정거리
public float attackDist = 2.0f;
// 몬스터의 사망 여부
public bool isDie = false;
// 컴포넌트의 캐시를 처리할 변수
private Transform monsterTr;
private Transform playerTr;
private NavMeshAgent agent;
private void Start()
{
// 몬스터의 Transform 할당
monsterTr = GetComponent<Transform>();
// 추적 대상인 Player의 Trasnform 할당
playerTr = GameObject.FindWithTag("PLAYER").GetComponent<Transform>();
// NavMEshAgent 컴포넌트 할당
agent = GetComponent<NavMeshAgent>();
// 추적 대상의 위치를 설정하면 바로 추척
// agent.destination = playerTr.position;
StartCoroutine(CheckMonsterState());
}
// 일정한 간격을 몬스터의 행동 상태를 체크
IEnumerator CheckMonsterState()
{
while(!isDie)
{
// 0.3초 동안 대기하는 동안 제어권을 메세지 루프에 양보
yield return new WaitForSeconds(0.3f);
// 몬스터와 주인공 캐릭터 사이의 거리 측정
float distance = Vector3.Distance(playerTr.position, monsterTr.position);
// 공격 사정거리 범위로 들어왔는지 확인
if (distance <= attackDist)
{
state = State.ATTACK;
}
//추적 사정거리 범위로 들어왔는지 확인
else if (distance <= traceDist)
{
state = State.TRACE;
}
else{
state = State.IDLE;
}
}
}
private void OnDrawGizmos()
{
// 추적 사정거리 표시
if(state == State.TRACE){
Gizmos.color = Color.blue;
Gizmos.DrawWireSphere(transform.position, traceDist);
}
// 공격 사정거리 표시
if (state == State.ATTACK){
Gizmos.color = Color.red;
Gizmos.DrawWireSphere(transform.position, attackDist);
}
}
}
Enum 열거형 변수로 설정하면 인스펙터 뷰에 콤보 박스 형태로 표시됨 int, String 타입의 변수보다 가독성이 좋음
// 몬스터 상태의 정보
public enum State
{
IDLE,
TRACE,
ATTACK,
DIE
}
Update 함수에서 코드를 작성해도 제대로 작동되지만 적정한 주기로 상태를 검사하는 방법이 더 효율적
Vector3.Distance함수를 사용하여 거리를 측정한다.
// 몬스터와 주인공 캐릭터 사이의 거리 측정
float distance = Vector3.Distance(playerTr.position, monsterTr.position);
주인공 캐릭터가 접근하여 몬스터의 상태가 변경되는 것을 시각적으로 표현
private void OnDrawGizmos()
{
// 추적 사정거리 표시
if(state == State.TRACE){
Gizmos.color = Color.blue;
Gizmos.DrawWireSphere(transform.position, traceDist);
}
// 공격 사정거리 표시
if (state == State.ATTACK){
Gizmos.color = Color.red;
Gizmos.DrawWireSphere(transform.position, attackDist);
}
}



플레이어와의 사이의 거리에 따라 몬스터 상태가 변하는 것을 확인 할 수 있다.
MonsterAction 코루틴 함수 추가하고 Start 함수에서 해당 코루틴 시
using System.Collections;
using UnityEngine;
using UnityEngine.AI; // 내비게이션 기능을 사용하기 위해 추가해야 하는 네임 스페이스
public class MonsterCtrl : MonoBehaviour
{
// 몬스터 상태의 정보
public enum State
{
IDLE,
TRACE,
ATTACK,
DIE
}
// 몬스터 현재 상태
public State state = State.IDLE;
// 추적 사정거리
public float traceDist = 10.0f;
// 공격 사정거리
public float attackDist = 2.0f;
// 몬스터의 사망 여부
public bool isDie = false;
// 컴포넌트의 캐시를 처리할 변수
private Transform monsterTr;
private Transform playerTr;
private NavMeshAgent agent;
private void Start()
{
// 몬스터의 Transform 할당
monsterTr = GetComponent<Transform>();
// 추적 대상인 Player의 Trasnform 할당
playerTr = GameObject.FindWithTag("PLAYER").GetComponent<Transform>();
// NavMEshAgent 컴포넌트 할당
agent = GetComponent<NavMeshAgent>();
// 추적 대상의 위치를 설정하면 바로 추척
// agent.destination = playerTr.position;
// 몬스터의 상태를 체크하는 코루틴 함수 호출
StartCoroutine(CheckMonsterState());
// 상태에 따라 몬스터의 행동을 수행하는 코루틴 함수 호출
StartCoroutine(MonstorAction());
}
// 일정한 간격을 몬스터의 행동 상태를 체크
IEnumerator CheckMonsterState()
{
... 생략
}
IEnumerator MonstorAction()
{
while(!isDie)
{
switch(state){
// Idle 상태
case State.IDLE:
// 추적 중지
agent.isStopped = true;
break;
// 추적 상태
case State.TRACE:
// 추적 대상의 좌표로 이동 시작
agent.SetDestination(playerTr.position);
agent.isStopped = false;
break;
// 공격 상태
case State.ATTACK:
break;
// 사망
case State.DIE:
break;
}
yield return new WaitForSeconds(0.3f);
}
}
private void OnDrawGizmos()
{
...생략
}
}
추적 중지 여부를 나타내는 것으로 true이면 정지 상태를 의미
false 는 NavMeshAgent를 재시작하는 역할을 함
agent.isStopped = false;
agent.isStopped = true;
추적 사정거리 이내에 위치하면 추적하고
멀어지면 추적하지 않는 모습을 확인할 수 있음
애니메이션 동기화
using System.Collections;
using UnityEngine;
using UnityEngine.AI; // 내비게이션 기능을 사용하기 위해 추가해야 하는 네임 스페이스
public class MonsterCtrl : MonoBehaviour
{
// 몬스터 상태의 정보
public enum State
{
IDLE,
TRACE,
ATTACK,
DIE
}
// 몬스터 현재 상태
public State state = State.IDLE;
// 추적 사정거리
public float traceDist = 10.0f;
// 공격 사정거리
public float attackDist = 2.0f;
// 몬스터의 사망 여부
public bool isDie = false;
// 컴포넌트의 캐시를 처리할 변수
private Transform monsterTr;
private Transform playerTr;
private NavMeshAgent agent;
private Animator anim;
private void Start()
{
// 몬스터의 Transform 할당
monsterTr = GetComponent<Transform>();
// 추적 대상인 Player의 Trasnform 할당
playerTr = GameObject.FindWithTag("PLAYER").GetComponent<Transform>();
// NavMEshAgent 컴포넌트 할당
agent = GetComponent<NavMeshAgent>();
// Animator 컴포넌트 할당
anim = GetComponent<Animator>();
// 몬스터의 상태를 체크하는 코루틴 함수 호출
StartCoroutine(CheckMonsterState());
// 상태에 따라 몬스터의 행동을 수행하는 코루틴 함수 호출
StartCoroutine(MonstorAction());
}
// 일정한 간격을 몬스터의 행동 상태를 체크
IEnumerator CheckMonsterState()
{
...생략
}
IEnumerator MonstorAction()
{
while(!isDie)
{
switch(state){
// Idle 상태
case State.IDLE:
// 추적 중지
agent.isStopped = true;
// Animator의 IsTrace 변수를 false로 설정
anim.SetBool("IsTrace", false);
break;
// 추적 상태
case State.TRACE:
// 추적 대상의 좌표로 이동 시작
agent.SetDestination(playerTr.position);
agent.isStopped = false;
// Animator의 IsTrace 변수를 true로 설정
anim.SetBool("IsTrace", true);
break;
// 공격 상태
case State.ATTACK:
break;
// 사망
case State.DIE:
break;
}
yield return new WaitForSeconds(0.3f);
}
}
private void OnDrawGizmos()
{
...생략
}
}
| Set 함수 | Get 함수 |
| Animator.SetBool | Animator.GetBool |
| Animator.SetFloat | Animator.GetFloat |
| Animator.SetInteger | Animator.GetInteger |
| Animator.SetTrigger | Animator.GetTrigger |
몬스터 공격 루틴

몬스터의 Attack 애니메이션을 추가하고
Make Transition을 양방향으로 추가한 후 각 Transition을 아래와 같이 설정


using System.Collections;
using UnityEngine;
using UnityEngine.AI; // 내비게이션 기능을 사용하기 위해 추가해야 하는 네임 스페이스
public class MonsterCtrl : MonoBehaviour
{
...생략
private readonly int hashTrace = Animator.StringToHash("IsTrace");
private readonly int hashAttack = Animator.StringToHash("IsAttack");
private void Start()
{
...생략
}
// 일정한 간격을 몬스터의 행동 상태를 체크
IEnumerator CheckMonsterState()
{
...생략
}
IEnumerator MonstorAction()
{
while(!isDie)
{
switch(state){
// Idle 상태
case State.IDLE:
// 추적 중지
agent.isStopped = true;
// Animator의 IsTrace 변수를 false로 설정
anim.SetBool(hashTrace, false);
break;
// 추적 상태
case State.TRACE:
// 추적 대상의 좌표로 이동 시작
agent.SetDestination(playerTr.position);
agent.isStopped = false;
// Animator의 IsTrace 변수를 true로 설정
anim.SetBool(hashTrace, true);
// Animator의 IsAttack 변수를 false로 설정
anim.SetBool(hashAttack, false);
break;
// 공격 상태
case State.ATTACK:
// Animator의 IsAttack 변수를 true로 설정
anim.SetBool(hashAttack, true);
break;
// 사망
case State.DIE:
break;
}
yield return new WaitForSeconds(0.3f);
}
}
private void OnDrawGizmos()
{
...생략
}
}
애니메이터 뷰에서 정의한 파라미터에 접근하는 방식을 변경
앞서 전달했던 파라미터는 문자열
anim.SetBool("IsTrace",false);
해시값을 미리 추출해 속도면에서 빨라짐
private readonly int hashTrace = Animator.StringToHash("IsTrace");
private readonly int hashAttack = Animator.StringToHash("IsAttack");
몬스터 피격 리액션
주인공이 캐릭터가 발사한 총에 맞았을 때 타격을 입는 리액션을 구현

몬스터 오브젝트에 Capsule Collider 컴포넌트를 추가하고 위와 같이 속성을 변경한다

goHit애니메이션을 추가하고 Hit라는 이름의 Trigger 파라미터를 추가
각 Transition 은 아래와 같이 설




using System.Collections;
using UnityEngine;
using UnityEngine.AI; // 내비게이션 기능을 사용하기 위해 추가해야 하는 네임 스페이스
public class MonsterCtrl : MonoBehaviour
{
...생략
private readonly int hashTrace = Animator.StringToHash("IsTrace");
private readonly int hashAttack = Animator.StringToHash("IsAttack");
private readonly int hashHit = Animator.StringToHash("Hit");
private void Start()
{
...생략
}
// 일정한 간격을 몬스터의 행동 상태를 체크
IEnumerator CheckMonsterState()
{
...생략
}
IEnumerator MonstorAction()
{
...생략
}
private void OnCollisionEnter(Collision coll)
{
if(coll.collider.CompareTag("BULLET"))
{
// 충돌한 총알을 삭제
Destroy(coll.gameObject);
// 피격 애니메이션 실행
anim.SetTrigger(hashHit);
}
}
private void OnDrawGizmos()
{
..생략
}
}
반응형
'Unity 강의 > Unity Course(2) - 절대강좌! 유니티' 카테고리의 다른 글
| [Unity Course 2] 06. 적 캐릭터 제작 5 (0) | 2024.06.22 |
|---|---|
| [Unity Course 2] 06. 적 캐릭터 제작 4 (0) | 2024.06.21 |
| [Unity Course 2] 06. 적 캐릭터 제작 2 (0) | 2024.06.21 |
| [Unity Course 2] 06. 적 캐릭터 제작 1 (0) | 2024.06.21 |
| [Unity Course 2] 05. 총 발사 로직 7 (0) | 2024.06.20 |