Practice_Unity/Assets/Scripts/Controllers/EnemyController.cs
Seonkyu.kim 886822a545 작업
1. 적 <-> 플레이어 공격해서 값 체력깎기 기능 추가
2. 적 죽으면(explore)시 정해진 양만큼의 경험치 큐브 생성
  - but 아직 1과 연동해서 공격해서 피 깎아서 죽는건 아직 아님
3. 경험치 큐브 범위내에 있으면 당기기 기능 추가
4. 경험치 큐브 캐릭터 최근접 범위에 닿으면 흡수하기 기능 추가
5. 경험치 획득시 레벨업 기능 추가
6. UI 경험치 바 화면에 구현
7. UI 경험치 바 플레이어 정보의 경험치와 연계

Todo
1. UI 다른 요소들 죄다 UIManaer로 이동
2. 몬스터 공격해서 에너지 덩어리로 바꾸는 동작 추가
3. 레벨업시 레벨 화면 표기
4. 몬스터가 캐릭터에게 다가오는 동작 추가
5. 투사체 공격 기능 추가
2025-10-01 17:56:13 +09:00

145 lines
4.5 KiB
C#

using System;
using Unity.VisualScripting;
using UnityEngine;
using UnityEngine.AI;
using UnityEngine.SceneManagement;
using EnemyType = Define.EnemyType;
using Random = UnityEngine.Random;
//EnemyController는 몬스터의 '뇌' 역할을 하며, 상태 머신 패턴을 기반으로 동작하고, 외부에서 데이터를 주입받아 초기화되는 구조로 설계하기
public class EnemyController : MonoBehaviour, IDamageable
{
// 데미지를 입력하기 위한 클래스 선언 필드
private Damage _damage;
// 이동을 하기 위한 클래스 선언 필드
private Movement_Base _movement;
// 상태 정보가 담긴 클래스 선언 필드
private Status_Enemy _status;
public Status_Enemy Status
{
get { return _status; }
private set { _status = value;}
}
[SerializeField] private EnemyType _type = EnemyType.Unknown;
[SerializeField] private int _expRate = 5;
public Movement_Base Movement => _movement;
public EnemyType Type => _type;
private AI_State _currentState;
public AI_State CurrentState
{
get { return _currentState; }
set
{
if (_currentState != null)
_currentState.Exit();
_currentState = value;
if (_currentState != null)
_currentState.Enter();
}
}
[SerializeField] private bool _explose = false;
private bool _hasExploded = false;
private void Awake()
{
_movement = gameObject.GetComponent<Movement_Base>();
_status = gameObject.GetComponent<Status_Enemy>();
_damage = gameObject.AddComponent<Damage_Melee>();
_damage._targetlayer = LayerMask.GetMask("Player");
}
void Start()
{
}
public void Init(EnemyData data)
{
_type = data.E_Type;
if (_damage != null)
{
_damage.OnHit -= OnBodyHit;
_damage.OnHit += OnBodyHit;
}
}
void Update()
{
if (CurrentState != null)
CurrentState.Update();
_damage?.SetTriggerActive(true);
if (_explose && !_hasExploded)
{
_hasExploded = true;
OnExplose();
}
}
private void OnBodyHit(IDamageable target, Collider collider)
{
Debug.Log($"Player Hit! {collider.name}");
}
public void TakeDamage(float damage)
{
float hp = Status.ApplyDamage(damage);
Debug.Log($"피격! 데미지: {damage} / 남은 체력: {hp}");
}
private void OnExplose()
{
Vector3 currentPosition = transform.position;
int totalExp = Mathf.RoundToInt(_status.ExpAmount);
int cubeCount = (totalExp / _expRate) + (totalExp % _expRate > 0 ? 1 : 0);
// 5/5/5/3 = 18
// count = 4
for (int i = 0; i < cubeCount; i++)
{
float amount = Mathf.Min(_expRate, (totalExp - (i * _expRate)));
Vector3 spawnPosition = currentPosition + Random.insideUnitSphere * 2f;
spawnPosition.y = currentPosition.y;
GameObject expCube =
Manager.Resource.Instantiate("Prefabs/Objects/ExpCube", GameObject.Find("@Object").transform);
expCube.GetComponent<ExpCubeComponent>().SetExpAmount(amount);
expCube.transform.position = spawnPosition;
}
Destroy(gameObject, 0.1f);
}
}
/*
* 행동 패턴
* - 종류 : Idle(대기), Patrol(순찰), Chase(추적), Run(도망), Return(귀환), Hide(숨기), Fight(싸우기)
* 1. Idle : 제자리에서 대기
* 2. Patrol : 지정된 경로를 따라 순찰
* 3. Chase : 플레이어를 발견하면 추적
* 4. Run : (옵션) 체력이 너무 낮으면 도망
* 5. Return : 일정 시간 동안 플레이어를 찾지 못하면 원래 위치로 귀환
* 6. Hide : 플레이어의 시야에서 벗어나 숨기
* 7. Fight : 플레이어와 일정 거리 내에 들어오면 싸우기
* - 행동 전환
* 1. Idle -> Patrol : 일정 시간 후
* 2. Idle/Patrol -> Chase : 플레이어 발견 시
* 2.1. 플레이어 발견 조건 : 시야각, 거리, 장애물 유무 등
* 3. Idle/Patrol/Chase -> Run : (옵션) 체력이 일정 이하로 떨어지면
* 4. Idle/Patrol/Chase/Run -> Fight : 플레이어와 일정 거리 내에 들어오면
* 5. Patrol -> Idle : 일정 시간 동안 움직이지 않으면
* 6. Patrol/Chase/Run/Fight -> Return : 플레이어를 일정 시간 동안 찾지 못하면
* 7. Patrol/Chase/Run/Fight -> Hide : 플레이어의 시야에서 벗어나면
*/