적을 일정 시간마다 생성하는 코루틴 작성
IEnumerator Start()
{
while(true)
{
if (count < maxCount)
{
// 적공장에서 적을 생성
GameObject enemy = Instantiate(EnemyFactory);
// 내 위치에 가져다 놓고싶다.
enemy.transform.position = this.transform.position + new Vector3(Random.value * 2, 0, Random.value * 2);
// 내 방향과 일치시키고 싶다.
enemy.transform.rotation = transform.rotation;
count++;
// 생성시간동안 대기하고싶다.
yield return new WaitForSeconds(createTime);
}
}
}
최대 2개체까지만 생성되게 하며, 적 처치시 추가 생성하는 함수 호출을 위해 싱글톤으로 설정
public static EnemyManager instance;
private void Awake()
{
instance = this;
}
public float createTime = 2;
public GameObject EnemyFactory;
public int maxCount = 2;
int count;
public int COUNT
{
get { return count; }
set {
count = value;
if (count < 0)
{
count = 0;
}
if (count > maxCount)
{
count = maxCount;
}
}
}
maxCount와 count 사이의 생길 수 있는 수치상 오류를 방지하기 위해 COUNT 설정
EnemyManager 전문
더보기
using System.Collections;
using System.Collections.Generic;
using UnityEngine;
// 일정시간마다 적공장에서 적을 생성해서 내 위치에 가져다놓고 싶다.
public class EnemyManager : MonoBehaviour
{
public static EnemyManager instance;
private void Awake()
{
instance = this;
}
public float createTime = 2;
public GameObject EnemyFactory;
public int maxCount = 2;
int count;
public int COUNT
{
get { return count; }
set {
count = value;
if (count < 0)
{
count = 0;
}
if (count > maxCount)
{
count = maxCount;
}
}
}
// Start is called before the first frame update
IEnumerator Start()
{
while(true)
{
if (count < maxCount)
{
// 적공장에서 적을 생성
GameObject enemy = Instantiate(EnemyFactory);
// 내 위치에 가져다 놓고싶다.
enemy.transform.position = this.transform.position + new Vector3(Random.value * 2, 0, Random.value * 2);
// 내 방향과 일치시키고 싶다.
enemy.transform.rotation = transform.rotation;
count++;
// 생성시간동안 대기하고싶다.
yield return new WaitForSeconds(createTime);
}
}
}
// Update is called once per frame
void Update()
{
}
}
파괴될 경우 count 감소를 위해 Enemy에서 COUNT호출
public void AddDamage (int damage)
{
agent.isStopped = true;
Destroy(gameObject);
}
private void OnDestroy()
{
EnemyManager.instance.COUNT--;
}
Enemy 전문
더보기
using System;
using System.Collections;
using System.Collections.Generic;
using UnityEngine;
using UnityEngine.AI;
// FSM으로 상태를 제어하고싶다.
// 정지, 이동, 공격, 죽음
public class Enemy : MonoBehaviour
{
NavMeshAgent agent;
public float speed = 1;
public float findDistance = 5;
public float attackDistance = 1.5f;
public float traceDistance = 15;
enum State
{
Idle,
Move,
Attack,
Die,
Return
}
State state;
PlayerHP php;
GameObject target;
float currentTime;
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);
// 만약 그 거리가 감지거리보다 작으면
if (distance < findDistance)
{
// Move상태로 전이하고싶다.
state = State.Move;
agent.destination = target.transform.position;
}
}
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 - 12 / 모델링 적용 (0) | 2022.05.23 |
---|---|
3D FPS - 11 / 적 시야각 (0) | 2022.05.23 |
3D FPS - 9 / 네비게이션 알고리즘으로 길찾기 (0) | 2022.05.21 |
3D FPS - 8 / 게임 오버 처리 (0) | 2022.05.19 |
3D FPS - 7 / 피격 처리 (0) | 2022.05.19 |