DEG-41 사용하지 않는 패턴 정리

This commit is contained in:
fiore 2025-04-22 14:24:03 +09:00
parent 3694483a9c
commit c0fde7a8d2
28 changed files with 243 additions and 191 deletions

View File

@ -30,12 +30,6 @@ public class EnemyControllerEditor : Editor
case EnemyState.Attack:
GUI.backgroundColor = new Color(1, 1, 0, 1f);
break;
case EnemyState.Move:
GUI.backgroundColor = new Color(0, 1, 1, 1f);
break;
case EnemyState.GetHit:
GUI.backgroundColor = new Color(0.1f, 0.1f, 0.1f, 1f);
break;
case EnemyState.Dead:
GUI.backgroundColor = new Color(1, 0, 0, 1f);
break;
@ -55,12 +49,10 @@ public class EnemyControllerEditor : Editor
EditorGUILayout.BeginHorizontal();
if (GUILayout.Button("Idle")) enemyController.SetState(EnemyState.Idle);
if (GUILayout.Button("Trace")) enemyController.SetState(EnemyState.Trace);
if (GUILayout.Button("Attack")) enemyController.SetState(EnemyState.Attack);
EditorGUILayout.EndHorizontal();
EditorGUILayout.BeginHorizontal();
if (GUILayout.Button("Move")) enemyController.SetState(EnemyState.Move);
if (GUILayout.Button("GetHit")) enemyController.SetState(EnemyState.GetHit);
if (GUILayout.Button("Attack")) enemyController.SetState(EnemyState.Attack);
if (GUILayout.Button("Dead")) enemyController.SetState(EnemyState.Dead);
EditorGUILayout.EndHorizontal();
}

Binary file not shown.

Binary file not shown.

Binary file not shown.

Binary file not shown.

BIN
Assets/JYY/Prefabs/AoE Indicator Chariot.prefab (Stored with Git LFS) Normal file

Binary file not shown.

View File

@ -1,5 +1,5 @@
fileFormatVersion: 2
guid: e9e020ef2784edf4ca2a83ae9e1edefd
guid: 36d2fcfec062c074ba2dad3a0b0116be
PrefabImporter:
externalObjects: {}
userData:

BIN
Assets/JYY/Prefabs/AoE Slash Blue Chariot.prefab (Stored with Git LFS) Normal file

Binary file not shown.

View File

@ -0,0 +1,7 @@
fileFormatVersion: 2
guid: 3f431e991bd65014c833e89305ddd5e3
PrefabImporter:
externalObjects: {}
userData:
assetBundleName:
assetBundleVariant:

BIN
Assets/JYY/Prefabs/[Enemy] PldDog.prefab (Stored with Git LFS)

Binary file not shown.

BIN
Assets/JYY/Scenes/MonsterTest.unity (Stored with Git LFS)

Binary file not shown.

View File

@ -0,0 +1,81 @@
using System;
using System.Collections.Generic;
using UnityEngine;
using UnityEngine.Serialization;
[System.Serializable]
public struct DamageEffectData
{
public int damage;
public float radius;
public float delay;
public LayerMask targetLayer;
public GameObject explosionEffectPrefab;
}
public class ChariotAoeController : MonoBehaviour
{
private DamageEffectData _data;
[SerializeField] private GameObject warningEffectInstance;
private EnemyController _enemyController;
public void SetEffect(DamageEffectData data, EnemyController enemyController)
{
_data = data;
_enemyController = enemyController;
ShowWarningEffect();
Invoke(nameof(Explode), _data.delay);
}
private void ShowWarningEffect()
{
warningEffectInstance.SetActive(true);
float diameter = _data.radius * 2f;
gameObject.transform.localScale = new Vector3(diameter, 1f, diameter);
}
private void Explode()
{
var effect = Instantiate(_data.explosionEffectPrefab, transform.position, Quaternion.identity);
// 공격 전조 제거
warningEffectInstance.SetActive(false);
effect.transform.localScale = new Vector3(_data.radius, _data.radius, _data.radius);
_enemyController.SetAttackTrigger(true);
// 폭발 반경 내의 모든 콜라이더 가져오기
Collider[] hitColliders = Physics.OverlapSphere(transform.position, _data.radius, _data.targetLayer);
foreach (Collider hit in hitColliders)
{
if (hit.CompareTag("Player"))
{
// TODO : 데미지 부여
Debug.Log(hit.name +"에게 공격 적중");
}
}
Exit(effect);
}
private void Exit(GameObject effect)
{
Destroy(effect, 2f);
Destroy(gameObject, 2f);
}
private void OnDestroy()
{
_enemyController.SetAttackTrigger(false);
_enemyController = null;
}
private void OnDrawGizmosSelected()
{
Gizmos.color = Color.red;
Gizmos.DrawWireSphere(transform.position, _data.radius);
}
}

View File

@ -1,14 +0,0 @@
using System.Collections;
using System.Collections.Generic;
using UnityEngine;
public class EnemyAnimatorStateAttack : StateMachineBehaviour
{
// OnStateExit is called when a transition ends and the state machine finishes evaluating this state
// override public void OnStateExit(Animator animator, AnimatorStateInfo stateInfo, int layerIndex)
// {
// animator.gameObject.GetComponent<EnemyController>().SetState(EnemyState.Trace);
// }
}

View File

@ -1,11 +0,0 @@
fileFormatVersion: 2
guid: a5765847dbef51e4f9bccde712eeda30
MonoImporter:
externalObjects: {}
serializedVersion: 2
defaultReferences: []
executionOrder: 0
icon: {instanceID: 0}
userData:
assetBundleName:
assetBundleVariant:

View File

@ -1,42 +0,0 @@
using System.Collections.Generic;
using UnityEngine;
public class EnemyAttackController : MonoBehaviour
{
[Header("각종 전조 오브젝트")]
[SerializeField] private GameObject verticalWarningArea;
[SerializeField] private GameObject horizontalWarningArea;
[SerializeField] private GameObject chariotWarningArea;
[SerializeField] private GameObject dynamoWarningArea;
// 배열에 담아서 관리
private List<GameObject> warningAreas;
private GameObject _activeArea;
private void Awake()
{
warningAreas = new List<GameObject>()
{
verticalWarningArea,
horizontalWarningArea,
chariotWarningArea,
dynamoWarningArea
};
}
// 랜덤 전조 호출
public void TriggerRandomWarning(Vector3 spawnPosition, Quaternion spawnRotation)
{
// 0 ~ Count-1 사이 랜덤 인덱스
int idx = Random.Range(0, warningAreas.Count);
GameObject selected = warningAreas[idx];
// 예시: Instantiate 방식으로 화면에 띄우기
_activeArea = Instantiate(selected, spawnPosition, spawnRotation);
}
public void DestroyWarningArea()
{
Destroy(_activeArea);
}
}

View File

@ -2,11 +2,10 @@
using UnityEngine;
using UnityEngine.AI;
public enum EnemyState { None, Idle, Trace, Attack, GetHit, Move, Dead }
public enum EnemyState { None, Idle, Trace, Attack, Dead }
[RequireComponent(typeof(NavMeshAgent))]
[RequireComponent(typeof(Animator))]
[RequireComponent(typeof(EnemyAttackController))]
public abstract class EnemyController : CharacterBase
{
[Header("AI")]
@ -15,36 +14,39 @@ public abstract class EnemyController : CharacterBase
public NavMeshAgent Agent { get; private set; }
public Animator EnemyAnimator { get; private set; }
public EnemyState CurrentState {get; private set;}
public LayerMask TargetLayerMask => targetLayerMask;
public bool AttackTrigger { get; protected set; }
public EnemyAttackController EnemyAttackController { get; private set; }
public bool IsInBattle { get => _isInBattle; protected set=> _isInBattle = value; }
private bool _isInBattle = false;
public bool IsBoss { get => _isBoss; protected set => _isBoss = value; }
private bool _isBoss = false;
public float WalkSpeed => walkSpeed;
public float RunSpeed => runSpeed;
public Transform TraceTargetTransform { get; private set; }
[Header("이동 능력")]
[SerializeField] private float walkSpeed = 5;
[SerializeField] private float runSpeed = 8;
// -----
// 상태 변수
private EnemyStateIdle _enemyStateIdle;
private EnemyStateTrace _enemyStateTrace;
private EnemyStateAttack _enemyStateAttack;
private EnemyStateGetHit _enemyStateGetHit;
private EnemyStateDead _enemyStateDead;
private EnemyStateMove _enemyStateMove;
private Dictionary<EnemyState, IEnemyState> _enemyStates;
private void Awake()
protected virtual void Awake()
{
EnemyAnimator = GetComponent<Animator>();
Agent = GetComponent<NavMeshAgent>();
EnemyAttackController = GetComponent<EnemyAttackController>();
}
protected override void Start()
@ -55,24 +57,20 @@ public abstract class EnemyController : CharacterBase
_enemyStateIdle = new EnemyStateIdle();
_enemyStateTrace = new EnemyStateTrace();
_enemyStateAttack = new EnemyStateAttack();
_enemyStateGetHit = new EnemyStateGetHit();
_enemyStateDead = new EnemyStateDead();
_enemyStateMove = new EnemyStateMove();
_enemyStates = new Dictionary<EnemyState, IEnemyState>
{
{ EnemyState.Idle, _enemyStateIdle },
{ EnemyState.Trace, _enemyStateTrace },
{ EnemyState.Attack, _enemyStateAttack },
{ EnemyState.GetHit, _enemyStateGetHit },
{ EnemyState.Dead, _enemyStateDead },
{ EnemyState.Move, _enemyStateMove}
};
SetState(EnemyState.Idle);
}
private void Update()
protected void Update()
{
if (CurrentState != EnemyState.None)
{
@ -90,6 +88,24 @@ public abstract class EnemyController : CharacterBase
_enemyStates[CurrentState].Enter(this);
}
public void SetInBattle(bool battle)
{
_isInBattle = battle;
}
public override void Die()
{
base.Die();
// TODO : 사망 후 동작
}
public void SetAttackTrigger(bool value)
{
AttackTrigger = value;
}
#region
// 일정 반경에 플레이어가 진입하면 플레이어 소리를 감지했다고 판단

View File

@ -1,7 +0,0 @@
using UnityEngine;
public class EnemyDemageField : MonoBehaviour
{
private float damage;
}

View File

@ -1,3 +0,0 @@
fileFormatVersion: 2
guid: 8ac23a14eeef4226962782ab20ec78e0
timeCreated: 1745219566

View File

@ -10,58 +10,47 @@ public class EnemyStateAttack : IEnemyState
private EnemyController _enemyController;
private Animator _animator;
private Coroutine _attackRoutine;
private EnemyAttackController _enemyAttackController;
private enum AttackType
{
VerticalAttack, // 위에서 아래로 베는 것
HorizontalAttack, // 옆으로 베는 것
ChariotAttack, // 원형
DynamoAttack, // 도넛
};
private AttackType _currentAttackType;
private const float AttackInterval = 2f;
private float _attackTimer = 0f;
public void Enter(EnemyController enemyController)
{
_enemyController = enemyController;
_animator = _enemyController.EnemyAnimator;
_enemyAttackController = _enemyController.EnemyAttackController;
_animator.SetBool(VertiAttack, true);
_attackRoutine = _enemyController.StartCoroutine(VerticalAttackSequence());
}
public void Update()
{
if (!_enemyController.IsBoss)
NonBossSequence();
if (_enemyController.AttackTrigger)
{
_animator.SetTrigger(VertiSlash);
_enemyController.SetState(EnemyState.Trace);
}
}
private IEnumerator VerticalAttackSequence()
private void NonBossSequence()
{
yield return new WaitForSeconds(0.1f);
// 1. 전조 이펙트 생성, 검을 들어올림
_enemyAttackController.TriggerRandomWarning(_enemyController.transform.position, _enemyController.transform.rotation);
// 2. 대기(전조와 검 들어올리는 애니메이션을 위함)
yield return new WaitForSeconds(2f);
_animator.SetBool(VertiAttack, true);
_attackTimer += Time.deltaTime;
// 3. 검 휘두르기
_animator.SetTrigger(VertiSlash);
_enemyAttackController.DestroyWarningArea();
// TODO : 4. 공격 판정 발생
yield return new WaitForSeconds(1f);
// 5. 애니메이션 트리거 종료 -> 애니메이터 상태 머신으로 처리
_enemyController.SetState(EnemyState.Trace);
if (_attackTimer >= AttackInterval)
{
_animator.SetTrigger(VertiSlash);
_attackTimer = 0f;
_enemyController.SetState(EnemyState.Trace);
}
}
public void Exit()
{
if (_attackRoutine != null)
{
_enemyController.StopCoroutine(_attackRoutine);
_attackRoutine = null;
}
_enemyController.SetAttackTrigger(false);
_animator.SetBool(VertiAttack, false);
_animator = null;
_enemyAttackController = null;
_enemyController = null;
}
}

View File

@ -6,6 +6,7 @@
{
_enemyController = enemyController;
_enemyController.EnemyAnimator.SetTrigger("Dead");
_enemyController.SetInBattle(false);
}
public void Update()

View File

@ -1,19 +0,0 @@
public class EnemyStateGetHit: IEnemyState
{
private EnemyController _enemyController;
public void Enter(EnemyController enemyController)
{
_enemyController = enemyController;
}
public void Update()
{
}
public void Exit()
{
_enemyController = null;
}
}

View File

@ -1,3 +0,0 @@
fileFormatVersion: 2
guid: 7067b1b0eacf490c863a4cb68c290d3a
timeCreated: 1744799049

View File

@ -2,13 +2,13 @@
public class EnemyStateIdle: IEnemyState
{
private static readonly int Idle = Animator.StringToHash("Idle");
private EnemyController _enemyController;
public void Enter(EnemyController enemyController)
{
_enemyController = enemyController;
_enemyController.EnemyAnimator.SetBool(Idle, true);
_enemyController.EnemyAnimator.SetBool("Idle", true);
_enemyController.SetInBattle(false);
}
public void Update()
@ -22,7 +22,7 @@ public class EnemyStateIdle: IEnemyState
public void Exit()
{
_enemyController.EnemyAnimator.SetBool(Idle, false);
_enemyController.EnemyAnimator.SetBool("Idle", false);
_enemyController = null;
}
}

View File

@ -1,19 +0,0 @@
public class EnemyStateMove : IEnemyState
{
private EnemyController _enemyController;
public void Enter(EnemyController enemyController)
{
_enemyController = enemyController;
}
public void Update()
{
}
public void Exit()
{
_enemyController = null;
}
}

View File

@ -1,3 +0,0 @@
fileFormatVersion: 2
guid: 5abb29c9137942fe95bc66670d8ef521
timeCreated: 1744799142

View File

@ -29,6 +29,7 @@ public class EnemyStateTrace : IEnemyState
}
_enemyController.EnemyAnimator.SetBool(Trace, true);
_enemyController.SetInBattle(true);
}
public void Update()

View File

@ -1,7 +1,90 @@
using System;
using System.Collections;
using Unity.VisualScripting;
using UnityEngine;
public class PldDogController : EnemyController
{
[Header("공격 패턴 관련")]
[SerializeField] private float patternInterval = 3f;
private float _patternTimer = 0f;
private int _currentPatternIndex = 0;
private bool _isPatternRunning = false;
[Header("각종 데미지 이펙트 세트")]
[SerializeField] private GameObject chariotSlashWarning;
[SerializeField] private GameObject chariotSlash;
[Space(10)]
[SerializeField] private GameObject verticalWarning;
[SerializeField] private GameObject verticalSlash;
[Space(10)]
[SerializeField] private GameObject horizontalWarning;
[SerializeField] private GameObject horizontalSlash;
// 몬스터의 행동 스크립트
// IsBoos = 보스몬스터 여부
// IsInBattle = 전투중인지 여부
protected override void Awake()
{
base.Awake();
IsBoss = true;
}
private void Update()
{
base.Update();
if (IsInBattle && !_isPatternRunning && CurrentState == EnemyState.Attack)
{
_patternTimer += Time.deltaTime;
if (_patternTimer >= patternInterval)
{
ExecutePattern(0);
}
}
}
private void ExecutePattern(int patternIndex)
{
_isPatternRunning = true;
switch (patternIndex)
{
case 0:
{
ChariotSlashPattern();
break;
}
case 1:
{
break;
}
case 2:
{
break;
}
}
}
private void ChariotSlashPattern()
{
Debug.Log("ChariotSlashPattern: 보스가 차지 슬래시를 사용합니다.");
EnemyAnimator.SetBool("VertiAttack", true);
var warning = Instantiate(chariotSlashWarning, transform.position, Quaternion.identity)
.GetComponent<ChariotAoeController>();
DamageEffectData effectData = new DamageEffectData()
{
damage = (int)attackPower,
radius = 7.5f,
delay = 2.5f,
targetLayer = TargetLayerMask,
explosionEffectPrefab = chariotSlash
};
warning.SetEffect(effectData, this);
}
}