Enemy가 대기(Idle) 상태일 때 플레이어를 감지하는 시야각을 전방의 좌우 각각 45도로 제한하는 기능을 구현.
bool 형으로 각도를 확인하는 함수를 만들기
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;
}
}
UpdateIdle에서 CheckPlayerAngle을 호출한다.
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;
agent.destination = target.transform.position;
}
}
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
}
NavMeshAgent agent;
public State state;
PlayerHP php;
GameObject target;
float currentTime = 0;
float attackTime = 1;
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.Attack)
{
UpdateAttack();
}
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;
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;
agent.isStopped = true;
}
}
private void UpdateAttack()
{
// 시간이 흐르다가
currentTime += Time.deltaTime;
// 만약 현재시간이 공격시간이 되면
if (currentTime > attackTime)
{
// 현재시간을 초기화하고
currentTime = 0;
// 만약 target이 공격거리 밖에 있으면 Move상태로 전이하고싶다.
// 나와 target의 거리를 구해서
float distance = Vector3.Distance(transform.position, target.transform.position);
// 만약 그 거리가 공격거리보다 크다면
if (distance > attackDistance)
{
// Move상태로 전이하고싶다.
state = State.Move;
agent.isStopped = false;
}
// 공격 성공
else
{
// 플레이어를 공격하고
php.AddDamage();
}
}
}
public void AddDamage (int damage)
{
agent.isStopped = true;
Destroy(gameObject);
}
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 FPS - 13 / 사다리 이동 (0) | 2022.05.24 |
---|---|
3D FPS - 12 / 모델링 적용 (0) | 2022.05.23 |
3D FPS - 10 / 적 생성 유지 (0) | 2022.05.21 |
3D FPS - 9 / 네비게이션 알고리즘으로 길찾기 (0) | 2022.05.21 |
3D FPS - 8 / 게임 오버 처리 (0) | 2022.05.19 |