Chapter 7-8. AI : 공격하는 동물
카테고리: Unity Lesson 3
태그: Unity Game Engine
인프런에 있는 케이디님의 [유니티 3D] 실전! 생존게임 만들기 - Advanced 강의를 듣고 정리한 필기입니다. 😀
🌜 강의 들으러 가기 Click
Chapter 7. 동물들의 공격형 AI, 도망형 AI 구현
🚖 공격하는 동물
- 📜Animal
- 시야각 내에서 플레이어를 발견했다면
- 📜WeakAnimal 👉 Run
- 플레이어의 반대 방향으로 도망간다.
- 📜Pig.cs
- 📜StrongAnimal 👉 Chase
- 플레이어 방향으로 플레이어를 따라와 추격한다.
- 플레이어를 추격 중이다가 가까이 있고 + 시야 내에도 있게 될 때 공격한다.
- 📜Lion.cs
- 플레이어 방향으로 플레이어를 따라와 추격한다.
- 📜WeakAnimal 👉 Run
- 시야각 내에서 플레이어를 발견했다면
공격 애니메이션
사자의 공격 애니메이션 만듬.
📜Animal.cs
protected bool isAttacking; // 공격중인지 판별
protected FieldOfViewAngle theFieldOfViewAngle;
protected StatusController thePlayerStatus;
protected void Start()
{
currentTime = waitTime; // 대기 시작
isAction = true; // 대기도 행동
theAudio = GetComponent<AudioSource>();
nav = GetComponent<NavMeshAgent>();
theFieldOfViewAngle = GetComponent<FieldOfViewAngle>();
thePlayerStatus = FindObjectOfType<StatusController>();
}
protected void ElapseTime()
{
if (isAction)
{
currentTime -= Time.deltaTime;
if (currentTime <= 0 && !isChasing && !isAttacking) // 랜덤하게 다음 행동을 개시
ReSet();
}
}
- 공격 중일 땐 다음 행동을 개시하지 않도록 한다.
- 공격이 가능한 상황일 땐 계속 공격을 이어나가야 하므로.
- 공격하면 플레이어의 HP, DP를 깎기 위해 📜StatusController 로딩
📜StrongAnimal.cs
using System.Collections;
using System.Collections.Generic;
using UnityEngine;
public class StrongAnimal : Animal
{
[SerializeField]
protected int attackDamage; // 공격 데미지
[SerializeField]
protected float attackDelay; // 공격 딜레이
[SerializeField]
protected float attackDistance; // 공격 가능한 사정 거리. 이 안에 플레이어가 들어오면 가까이 있다고 판단.
[SerializeField]
protected LayerMask targetMask; // 플레이어 레이어가 할당 될 것.
[SerializeField]
protected float chaseTime; // 총 추격 시간
protected float currentChaseTime;
[SerializeField]
protected float chaseDelayTime; // 추격 딜레이
public void Chase(Vector3 _targetPos)
{
destination = _targetPos;
isChasing = true;
isWalking = false;
isRunning = true;
nav.speed = runSpeed;
anim.SetBool("Running", isRunning);
if(!isDead)
nav.SetDestination(destination);
}
public override void Damage(int _dmg, Vector3 _targetPos)
{
base.Damage(_dmg, _targetPos);
if (!isDead)
Chase(_targetPos);
}
protected IEnumerator ChaseTargetCoroutine()
{
currentChaseTime = 0;
Chase(theFieldOfViewAngle.GetTargetPos());
while (currentChaseTime < chaseTime)
{
Chase(theFieldOfViewAngle.GetTargetPos());
// 플레이어와 충분히 가까이 있고
if (Vector3.Distance(transform.position, theFieldOfViewAngle.GetTargetPos()) <= attackDistance)
{
if (theFieldOfViewAngle.View()) // 눈 앞에 있을 경우
{
Debug.Log("플레이어 공격 시도");
StartCoroutine(AttackCoroutine());
}
}
yield return new WaitForSeconds(chaseDelayTime);
currentChaseTime += chaseDelayTime;
}
isChasing = false;
isRunning = false;
anim.SetBool("Running", isRunning);
nav.ResetPath();
}
protected IEnumerator AttackCoroutine()
{
isAttacking = true;
// 공격은 제자리에서 이루어져야 함.
nav.ResetPath();
currentChaseTime = chaseTime;
// 공격은 대상을 바라보고 하도록. (0.5초 대기한 후)
yield return new WaitForSeconds(0.5f);
transform.LookAt(theFieldOfViewAngle.GetTargetPos());
// 공격 애니메이션이 어느정도 진행된 후 데미지를 입히도록 대기
anim.SetTrigger("Attack");
yield return new WaitForSeconds(0.5f);
RaycastHit _hit;
if (Physics.Raycast(transform.position + Vector3.up, transform.forward, out _hit, attackDistance, targetMask))
{
Debug.Log("플레이어가 적중!!");
thePlayerStatus.DecreaseHP(attackDamage);
}
else
{
Debug.Log("플레이어 빗나감!!");
}
yield return new WaitForSeconds(attackDelay);
isAttacking = false;
StartCoroutine(ChaseTargetCoroutine());
}
}
추격과 공격 실제 처리를 📜StrongAnimal 로 옮겼다.
- ChaseTargetCoroutine() 추격 코루틴
- 추격하다가 1️⃣ 플레이어와 충분히 가까이 있고 + 2️⃣ 눈 앞에 있을 경우
- 플레이어를 공격한다.
- 추격하다가 1️⃣ 플레이어와 충분히 가까이 있고 + 2️⃣ 눈 앞에 있을 경우
- AttackCoroutine() 공격 코루틴
isAttacking
True 👉 공격 중일땐 다음 랜덤 행동을 개시하지 않도록- 공격은 제자리에서 이루어지도록 한다.
- 목적지 추적 리셋
currentChaseTime
를chaseTime
로 만들어 ChaseTargetCoroutine 코루틴의 실제 추적 처리가 이루어지지 않도록 한다.- 코루틴 함수는 병행하여 실행되므로 병렬적으로 ChaseTargetCoroutine가 실행될 수 있기 때문. 공격할 땐 추적을 멈춰야 한다.
- 공격은 플레이어를 바라보고 하도록 한다.
- 공격 애니메이션이 어느정도 진행한 후 데미지를 입힐 수 있도록 공격 애니메이션 재생시킨 후 0.5초 대기
- 이제 공격을 시도한다.
- 공격 애니메이션 도중에 플레이어에게 닿았다면
- 플레이어의 HP 를 깎는다.
- 공격 애니메이션 도중에 플레이어에게 닿지 않았다면
- 이건 공격이 빗나가 실패한 것
- 공격 애니메이션 도중에 플레이어에게 닿았다면
- 이렇게 공격 과정을 한번 할때마다
attackDelay
만큼 대기 시간을 가진다. isAttacking
False- 다시 플레이어를 추적
- Chase(Vector3 _targetPos)
- 사자가 죽으면 더 이상 플레이어를 추격하지 않도록.. (코루틴에 의해서 플레이어가 사라지거나 해도 한동안 추적을 계속 하기 때문에 이 처리를 안해주면 사자가 죽은 상태에서도 플레이어 따라다녔다 ㅠㅠ)
if(!isDead) nav.SetDestination(destination);
- 사자가 죽으면 더 이상 플레이어를 추격하지 않도록.. (코루틴에 의해서 플레이어가 사라지거나 해도 한동안 추적을 계속 하기 때문에 이 처리를 안해주면 사자가 죽은 상태에서도 플레이어 따라다녔다 ㅠㅠ)
🌜 개인 공부 기록용 블로그입니다. 오류나 틀린 부분이 있을 경우
언제든지 댓글 혹은 메일로 지적해주시면 감사하겠습니다! 😄
댓글남기기