애니메이터에 애니메이션을 추가하고
트리거를 추가, transition을 설정해준다.
Animation창에서 Event 추가
EnemyAnimation 스크립트를 enemy에 연결
public Enemy enemy;
public void OnEventAttack()
{
enemy.OnEventAttack();
}
enemy에서 OnEventAttack 함수를 만들어 기존의 Attack 상태로 전이하던것을 함수 호출식으로 변경
internal void OnEventAttack()
{
// 공격 행위
// 나와 target의 거리를 구해서
float distance = Vector3.Distance(transform.position, target.transform.position);
// 만약 그 거리가 공격거리보다 크다면
if (distance > attackDistance)
{
// Move상태로 전이하고싶다.
state = State.Move;
anim.SetTrigger("Move");
agent.isStopped = false;
}
// 공격 성공
else
{
// 플레이어를 공격하고
php.AddDamage();
// HitManager의 Hit함수를 호출하고싶다.
HitManager.instance.Hit();
}
Enemy 전문
더보기
using System;
using System.Collections;
using System.Collections.Generic;
using UnityEngine;
using UnityEngine.AI;
// FSM으로 상태를 제어하고싶다.
// 정지, 이동, 공격, 죽음
public class Enemy : MonoBehaviour
{
public float speed = 1;
public float findDistance = 5;
public float attackDistance = 1.5f;
public float traceDistance = 15;
public float sightDegree = 45;
public enum State
{
Idle,
Move,
Attack,
Die,
Return
}
// Animator > Animation Controller > Animation Clips
public Animator anim;
NavMeshAgent agent;
public State state;
PlayerHP php;
GameObject target;
Vector3 originPosition;
// Start is called before the first frame update
void Start()
{
agent = GetComponent<NavMeshAgent>();
state = State.Idle;
target = GameObject.Find("Player");
php = target.GetComponent<PlayerHP>();
// 최초 위치를 originPosition 변수에 저장한다.
originPosition = transform.position;
}
// Update is called once per frame
void Update()
{
if (state == State.Idle)
{
UpdateIdle();
}
else if (state == State.Move)
{
UpdateMove();
}
else if (state == State.Return)
{
UpdateReturn();
}
}
private void UpdateIdle()
{
// 나와 target의 거리를 구해서
float distance = Vector3.Distance(transform.position, target.transform.position);
bool isInSight = CheckPlayerAngle(target.transform.position);
// 만약 그 거리가 감지거리보다 작으면
if (distance < findDistance && isInSight)
{
// Move상태로 전이하고싶다.
state = State.Move;
anim.SetTrigger("Move");
agent.destination = target.transform.position;
}
}
bool CheckPlayerAngle(Vector3 position)
{
// 체크하려는 대상을 바라보는 벡터를 구한다.
Vector3 direction = position - transform.position;
// 나의 정면 벡터와 앞에서 구한 벡터를 비교해서 사잇각을 구한다.
float checkDegree = Vector3.Angle(transform.forward, direction);
// 구해진 각도가 45도 이내라면 true, 45도 밖이면 false라고 반환한다.
if (checkDegree <= sightDegree)
{
return true;
}
else
{
return false;
}
}
private void UpdateMove()
{
// 현재 위치가 최대 추적 가능 거리를 넘어갔는지 여부를 판단한다.
float trace = Vector3.Distance(originPosition, transform.position);
// 만일, 최대 추적 가능 거리를 넘어갔다면 상태를 복귀 상태로 전환한다.
if (trace > traceDistance)
{
state = State.Return;
}
// target방향으로 이동하다가
//Vector3 dir = target.transform.position - transform.position;
//dir.Normalize();
//transform.position += dir * speed * Time.deltaTime;
agent.destination = target.transform.position;
// 나와 target의 거리를 구해서
float distance = Vector3.Distance(transform.position, target.transform.position);
// 만약 그 거리가 공격거리보다 작으면
if (distance < attackDistance)
{
// Attack으로 전이하고싶다.
state = State.Attack;
anim.SetTrigger("Attack");
agent.isStopped = true;
}
}
internal void OnEventAttack()
{
// 공격 행위
// 나와 target의 거리를 구해서
float distance = Vector3.Distance(transform.position, target.transform.position);
// 만약 그 거리가 공격거리보다 크다면
if (distance > attackDistance)
{
// Move상태로 전이하고싶다.
state = State.Move;
anim.SetTrigger("Move");
agent.isStopped = false;
}
// 공격 성공
else
{
// 플레이어를 공격하고
php.AddDamage();
// HitManager의 Hit함수를 호출하고싶다.
HitManager.instance.Hit();
}
}
public void AddDamage (int damage)
{
agent.isStopped = true;
state = State.Die;
anim.SetTrigger("Die");
Destroy(gameObject, 3);
}
private void OnDestroy()
{
EnemyManager.instance.COUNT--;
}
void UpdateReturn()
{
// 만일, 나의 현재 위치가 originPosition 위치에서 10센티미터 이상이라면
Vector3 dir = originPosition - transform.position;
if (dir.magnitude > 0.1f)
{
// originPosition 방향으로 이동한다.
transform.position += dir.normalized * speed * Time.deltaTime;
}
// 그렇지 않다면, 나의 위치를 originPosition으로 설정한다.
else
{
transform.position = originPosition;
// 상태를 다시 대기 상태로 전환한다.
state = State.Idle;
}
// 나와 target의 거리를 구해서
//float distance = Vector3.Distance(transform.position, target.transform.position);
// 복귀 중 감지거리 안으로 Player가 들어오면
//if (distance < findDistance)
{
// 상태를 Move 상태로 전이한다.
//state = State.Move;
}
}
}
'공부 > Unity 기초' 카테고리의 다른 글
3D 그래픽 - 1 / Material (0) | 2022.05.27 |
---|---|
3D FPS - 15 / 애니메이션 순환 (0) | 2022.05.26 |
3D FPS - 13 / 사다리 이동 (0) | 2022.05.24 |
3D FPS - 12 / 모델링 적용 (0) | 2022.05.23 |
3D FPS - 11 / 적 시야각 (0) | 2022.05.23 |