Merge pull request #28 from Degulleo/DEG-95-원거리-마법사-보스-몬스터-기획-및-설계
DEG-95 DEG-100 원거리 마법사 보스 몬스터 기획 및 설계
This commit is contained in:
commit
363589d35f
@ -27,9 +27,6 @@ public class EnemyControllerEditor : Editor
|
|||||||
case EnemyState.Trace:
|
case EnemyState.Trace:
|
||||||
GUI.backgroundColor = new Color(1, 0, 1, 1f);
|
GUI.backgroundColor = new Color(1, 0, 1, 1f);
|
||||||
break;
|
break;
|
||||||
case EnemyState.Attack:
|
|
||||||
GUI.backgroundColor = new Color(1, 1, 0, 1f);
|
|
||||||
break;
|
|
||||||
case EnemyState.Dead:
|
case EnemyState.Dead:
|
||||||
GUI.backgroundColor = new Color(1, 0, 0, 1f);
|
GUI.backgroundColor = new Color(1, 0, 0, 1f);
|
||||||
break;
|
break;
|
||||||
@ -49,10 +46,6 @@ public class EnemyControllerEditor : Editor
|
|||||||
EditorGUILayout.BeginHorizontal();
|
EditorGUILayout.BeginHorizontal();
|
||||||
if (GUILayout.Button("Idle")) enemyController.SetState(EnemyState.Idle);
|
if (GUILayout.Button("Idle")) enemyController.SetState(EnemyState.Idle);
|
||||||
if (GUILayout.Button("Trace")) enemyController.SetState(EnemyState.Trace);
|
if (GUILayout.Button("Trace")) enemyController.SetState(EnemyState.Trace);
|
||||||
EditorGUILayout.EndHorizontal();
|
|
||||||
|
|
||||||
EditorGUILayout.BeginHorizontal();
|
|
||||||
if (GUILayout.Button("Attack")) enemyController.SetState(EnemyState.Attack);
|
|
||||||
if (GUILayout.Button("Dead")) enemyController.SetState(EnemyState.Dead);
|
if (GUILayout.Button("Dead")) enemyController.SetState(EnemyState.Dead);
|
||||||
EditorGUILayout.EndHorizontal();
|
EditorGUILayout.EndHorizontal();
|
||||||
}
|
}
|
||||||
|
BIN
Assets/JYY/Animator/Dummy Monster.controller
(Stored with Git LFS)
Normal file
BIN
Assets/JYY/Animator/Dummy Monster.controller
(Stored with Git LFS)
Normal file
Binary file not shown.
8
Assets/JYY/Animator/Dummy Monster.controller.meta
Normal file
8
Assets/JYY/Animator/Dummy Monster.controller.meta
Normal file
@ -0,0 +1,8 @@
|
|||||||
|
fileFormatVersion: 2
|
||||||
|
guid: cb4d2ce283530414f92984caccad61a0
|
||||||
|
NativeFormatImporter:
|
||||||
|
externalObjects: {}
|
||||||
|
mainObjectFileID: 9100000
|
||||||
|
userData:
|
||||||
|
assetBundleName:
|
||||||
|
assetBundleVariant:
|
BIN
Assets/JYY/Animator/PldDogControl.controller
(Stored with Git LFS)
BIN
Assets/JYY/Animator/PldDogControl.controller
(Stored with Git LFS)
Binary file not shown.
@ -1,6 +1,7 @@
|
|||||||
fileFormatVersion: 2
|
fileFormatVersion: 2
|
||||||
guid: 3f431e991bd65014c833e89305ddd5e3
|
guid: 81ad24bdbd6cad44990b4f077f0687e7
|
||||||
PrefabImporter:
|
folderAsset: yes
|
||||||
|
DefaultImporter:
|
||||||
externalObjects: {}
|
externalObjects: {}
|
||||||
userData:
|
userData:
|
||||||
assetBundleName:
|
assetBundleName:
|
BIN
Assets/JYY/Materials/Dummy/Dummy Monster.mat
(Stored with Git LFS)
Normal file
BIN
Assets/JYY/Materials/Dummy/Dummy Monster.mat
(Stored with Git LFS)
Normal file
Binary file not shown.
8
Assets/JYY/Materials/Dummy/Dummy Monster.mat.meta
Normal file
8
Assets/JYY/Materials/Dummy/Dummy Monster.mat.meta
Normal file
@ -0,0 +1,8 @@
|
|||||||
|
fileFormatVersion: 2
|
||||||
|
guid: 9a8690b5dbb7c5643896a7d881a8fd6f
|
||||||
|
NativeFormatImporter:
|
||||||
|
externalObjects: {}
|
||||||
|
mainObjectFileID: 2100000
|
||||||
|
userData:
|
||||||
|
assetBundleName:
|
||||||
|
assetBundleVariant:
|
BIN
Assets/JYY/Materials/Dummy/Dummy Player.mat
(Stored with Git LFS)
Normal file
BIN
Assets/JYY/Materials/Dummy/Dummy Player.mat
(Stored with Git LFS)
Normal file
Binary file not shown.
8
Assets/JYY/Materials/Dummy/Dummy Player.mat.meta
Normal file
8
Assets/JYY/Materials/Dummy/Dummy Player.mat.meta
Normal file
@ -0,0 +1,8 @@
|
|||||||
|
fileFormatVersion: 2
|
||||||
|
guid: fc5cecc864a5b0c49b266cec5aaec666
|
||||||
|
NativeFormatImporter:
|
||||||
|
externalObjects: {}
|
||||||
|
mainObjectFileID: 2100000
|
||||||
|
userData:
|
||||||
|
assetBundleName:
|
||||||
|
assetBundleVariant:
|
8
Assets/JYY/Prefabs/AoE Indicator.meta
Normal file
8
Assets/JYY/Prefabs/AoE Indicator.meta
Normal file
@ -0,0 +1,8 @@
|
|||||||
|
fileFormatVersion: 2
|
||||||
|
guid: 2dbfaa22c1aa28242a4e80ed518bfae2
|
||||||
|
folderAsset: yes
|
||||||
|
DefaultImporter:
|
||||||
|
externalObjects: {}
|
||||||
|
userData:
|
||||||
|
assetBundleName:
|
||||||
|
assetBundleVariant:
|
BIN
Assets/JYY/Prefabs/AoE Slash Blue Chariot.prefab
(Stored with Git LFS)
BIN
Assets/JYY/Prefabs/AoE Slash Blue Chariot.prefab
(Stored with Git LFS)
Binary file not shown.
BIN
Assets/JYY/Prefabs/[Enemy] PldDog.prefab
(Stored with Git LFS)
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)
BIN
Assets/JYY/Scenes/MonsterTest.unity
(Stored with Git LFS)
Binary file not shown.
19
Assets/Scripts/Character/Enemy/CasterDemonController.cs
Normal file
19
Assets/Scripts/Character/Enemy/CasterDemonController.cs
Normal file
@ -0,0 +1,19 @@
|
|||||||
|
using System.Collections;
|
||||||
|
using System.Collections.Generic;
|
||||||
|
using UnityEngine;
|
||||||
|
|
||||||
|
public class CasterDemonController : EnemyController
|
||||||
|
{
|
||||||
|
|
||||||
|
public override void BattleSequence()
|
||||||
|
{
|
||||||
|
// TODO : 배틀 중일 때 루프
|
||||||
|
Debug.Log("## 몬스터의 교전 행동 루프");
|
||||||
|
}
|
||||||
|
|
||||||
|
|
||||||
|
public override void OnCannotFleeBehaviour()
|
||||||
|
{
|
||||||
|
Debug.Log("## 몬스터가 막다른 길에 몰려 뭔가 함");
|
||||||
|
}
|
||||||
|
}
|
11
Assets/Scripts/Character/Enemy/CasterDemonController.cs.meta
Normal file
11
Assets/Scripts/Character/Enemy/CasterDemonController.cs.meta
Normal file
@ -0,0 +1,11 @@
|
|||||||
|
fileFormatVersion: 2
|
||||||
|
guid: 79bc1ad21773bcf4e982d5fc7a93887b
|
||||||
|
MonoImporter:
|
||||||
|
externalObjects: {}
|
||||||
|
serializedVersion: 2
|
||||||
|
defaultReferences: []
|
||||||
|
executionOrder: 0
|
||||||
|
icon: {instanceID: 0}
|
||||||
|
userData:
|
||||||
|
assetBundleName:
|
||||||
|
assetBundleVariant:
|
@ -1,8 +1,10 @@
|
|||||||
using System.Collections.Generic;
|
using System;
|
||||||
|
using System.Collections.Generic;
|
||||||
using UnityEngine;
|
using UnityEngine;
|
||||||
using UnityEngine.AI;
|
using UnityEngine.AI;
|
||||||
|
|
||||||
public enum EnemyState { None, Idle, Trace, Attack, Dead }
|
public enum EnemyState { None, Idle, Trace, Dead, Flee}
|
||||||
|
public enum MonsterType { Melee, Caster, Ranged }
|
||||||
|
|
||||||
[RequireComponent(typeof(NavMeshAgent))]
|
[RequireComponent(typeof(NavMeshAgent))]
|
||||||
[RequireComponent(typeof(Animator))]
|
[RequireComponent(typeof(Animator))]
|
||||||
@ -11,10 +13,12 @@ public abstract class EnemyController : CharacterBase
|
|||||||
[Header("AI")]
|
[Header("AI")]
|
||||||
[SerializeField] private float detectCircleRadius = 10f; // 플레이어 탐지 범위
|
[SerializeField] private float detectCircleRadius = 10f; // 플레이어 탐지 범위
|
||||||
[SerializeField] private LayerMask targetLayerMask; // 플레이어 레이어 마스크
|
[SerializeField] private LayerMask targetLayerMask; // 플레이어 레이어 마스크
|
||||||
|
[SerializeField] private MonsterType monsterType;
|
||||||
|
|
||||||
|
public MonsterType MonsterType => monsterType;
|
||||||
public Transform TraceTargetTransform { get; private set; }
|
public Transform TraceTargetTransform { get; private set; }
|
||||||
public NavMeshAgent Agent { get; private set; }
|
public NavMeshAgent Agent { get; private set; }
|
||||||
public Animator EnemyAnimator { get; private set; }
|
private Animator EnemyAnimator { get; set; }
|
||||||
public EnemyState CurrentState {get; private set;}
|
public EnemyState CurrentState {get; private set;}
|
||||||
public LayerMask TargetLayerMask => targetLayerMask;
|
public LayerMask TargetLayerMask => targetLayerMask;
|
||||||
public float MoveSpeed => moveSpeed;
|
public float MoveSpeed => moveSpeed;
|
||||||
@ -31,10 +35,14 @@ public abstract class EnemyController : CharacterBase
|
|||||||
|
|
||||||
// -----
|
// -----
|
||||||
// 상태 변수
|
// 상태 변수
|
||||||
|
// Commons
|
||||||
private EnemyStateIdle _enemyStateIdle;
|
private EnemyStateIdle _enemyStateIdle;
|
||||||
private EnemyStateTrace _enemyStateTrace;
|
|
||||||
private EnemyStateAttack _enemyStateAttack;
|
|
||||||
private EnemyStateDead _enemyStateDead;
|
private EnemyStateDead _enemyStateDead;
|
||||||
|
// Melee
|
||||||
|
private EnemyStateTrace _enemyStateTrace;
|
||||||
|
// Caster
|
||||||
|
private EnemyStateFlee _enemyStateFlee;
|
||||||
|
|
||||||
|
|
||||||
private Dictionary<EnemyState, IEnemyState> _enemyStates;
|
private Dictionary<EnemyState, IEnemyState> _enemyStates;
|
||||||
|
|
||||||
@ -49,18 +57,34 @@ public abstract class EnemyController : CharacterBase
|
|||||||
base.Start();
|
base.Start();
|
||||||
|
|
||||||
// 상태 객체 생성
|
// 상태 객체 생성
|
||||||
|
// Commons
|
||||||
_enemyStateIdle = new EnemyStateIdle();
|
_enemyStateIdle = new EnemyStateIdle();
|
||||||
_enemyStateTrace = new EnemyStateTrace();
|
|
||||||
_enemyStateAttack = new EnemyStateAttack();
|
|
||||||
_enemyStateDead = new EnemyStateDead();
|
_enemyStateDead = new EnemyStateDead();
|
||||||
|
|
||||||
_enemyStates = new Dictionary<EnemyState, IEnemyState>
|
switch (MonsterType)
|
||||||
{
|
{
|
||||||
{ EnemyState.Idle, _enemyStateIdle },
|
case MonsterType.Melee:
|
||||||
{ EnemyState.Trace, _enemyStateTrace },
|
_enemyStateTrace = new EnemyStateTrace();
|
||||||
{ EnemyState.Attack, _enemyStateAttack },
|
_enemyStates = new Dictionary<EnemyState, IEnemyState>
|
||||||
{ EnemyState.Dead, _enemyStateDead },
|
{
|
||||||
};
|
{ EnemyState.Idle, _enemyStateIdle },
|
||||||
|
{ EnemyState.Trace, _enemyStateTrace },
|
||||||
|
{ EnemyState.Dead, _enemyStateDead },
|
||||||
|
};
|
||||||
|
break;
|
||||||
|
case MonsterType.Caster:
|
||||||
|
_enemyStateFlee = new EnemyStateFlee();
|
||||||
|
_enemyStates = new Dictionary<EnemyState, IEnemyState>
|
||||||
|
{
|
||||||
|
{ EnemyState.Idle, _enemyStateIdle },
|
||||||
|
{ EnemyState.Flee, _enemyStateFlee },
|
||||||
|
{ EnemyState.Dead, _enemyStateDead },
|
||||||
|
};
|
||||||
|
break;
|
||||||
|
case MonsterType.Ranged:
|
||||||
|
break;
|
||||||
|
}
|
||||||
|
|
||||||
|
|
||||||
SetState(EnemyState.Idle);
|
SetState(EnemyState.Idle);
|
||||||
}
|
}
|
||||||
@ -84,6 +108,24 @@ public abstract class EnemyController : CharacterBase
|
|||||||
}
|
}
|
||||||
|
|
||||||
|
|
||||||
|
#region 몬스터의 행동 패턴 위임
|
||||||
|
|
||||||
|
// 전략 패턴과 템플릿 메서드 패턴을 활용
|
||||||
|
public virtual void BattleSequence()
|
||||||
|
{
|
||||||
|
// 이 메서드는 자식 요소에서 오버라이드하여 구현합니다.
|
||||||
|
Debug.LogWarning("BattleSequence가 구현되지 않음 : BattleSequence()를 오버라이드하여 구현하십시오.");
|
||||||
|
}
|
||||||
|
|
||||||
|
// 도망치며 싸우는 몬스터가 도망칠 곳이 없을때 취할 행동
|
||||||
|
public virtual void OnCannotFleeBehaviour()
|
||||||
|
{
|
||||||
|
Debug.LogWarning("OnCannotFleeBehaviour가 구현되지 않음 : OnCannotFleeBehaviour() 오버라이드하여 구현하십시오.");
|
||||||
|
}
|
||||||
|
|
||||||
|
#endregion
|
||||||
|
|
||||||
|
|
||||||
public override void Die()
|
public override void Die()
|
||||||
{
|
{
|
||||||
base.Die();
|
base.Die();
|
||||||
@ -106,6 +148,12 @@ public abstract class EnemyController : CharacterBase
|
|||||||
return null;
|
return null;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
private void OnDrawGizmos()
|
||||||
|
{
|
||||||
|
Gizmos.color = Color.red;
|
||||||
|
Gizmos.DrawWireSphere(transform.position, detectCircleRadius);
|
||||||
|
}
|
||||||
|
|
||||||
#endregion
|
#endregion
|
||||||
|
|
||||||
#region 애니메이션 제어
|
#region 애니메이션 제어
|
||||||
|
3
Assets/Scripts/Character/Enemy/EnemyState/Caster.meta
Normal file
3
Assets/Scripts/Character/Enemy/EnemyState/Caster.meta
Normal file
@ -0,0 +1,3 @@
|
|||||||
|
fileFormatVersion: 2
|
||||||
|
guid: 06fb9eac62a34336b6023cc088be367d
|
||||||
|
timeCreated: 1745554862
|
@ -0,0 +1,109 @@
|
|||||||
|
using UnityEngine;
|
||||||
|
using UnityEngine.AI;
|
||||||
|
|
||||||
|
public class EnemyStateFlee :IEnemyState
|
||||||
|
{
|
||||||
|
private EnemyController _enemyController;
|
||||||
|
private Transform _playerTransform;
|
||||||
|
private float _fleeDistance = 5f; // 도망치는 거리
|
||||||
|
private float _attackRange = 7f; // 공격 범위
|
||||||
|
|
||||||
|
// 막다른길 검사용
|
||||||
|
private Vector3 _lastPosition;
|
||||||
|
private float _stuckTimer = 0f;
|
||||||
|
private const float StuckThresholdTime = 1f; // 1초 동안 거의 못 움직이면 막힌 걸로 간주
|
||||||
|
private const float StuckMoveThreshold = 0.1f; // 이내 이동은 “제자리”로 본다
|
||||||
|
|
||||||
|
public void Enter(EnemyController enemyController)
|
||||||
|
{
|
||||||
|
_enemyController = enemyController;
|
||||||
|
Debug.Log("## Flee 상태 진입");
|
||||||
|
|
||||||
|
_playerTransform = _enemyController.TraceTargetTransform;
|
||||||
|
_lastPosition = _enemyController.transform.position;
|
||||||
|
_stuckTimer = 0f;
|
||||||
|
|
||||||
|
|
||||||
|
}
|
||||||
|
|
||||||
|
public void Update()
|
||||||
|
{
|
||||||
|
if (!_playerTransform)
|
||||||
|
{
|
||||||
|
_enemyController.SetState(EnemyState.Idle);
|
||||||
|
return;
|
||||||
|
}
|
||||||
|
|
||||||
|
FindPositionFlee();
|
||||||
|
|
||||||
|
// 막힘 감지 (실제 이동 체크)
|
||||||
|
CheckPath();
|
||||||
|
|
||||||
|
_lastPosition = _enemyController.transform.position;
|
||||||
|
}
|
||||||
|
|
||||||
|
private void CheckPath()
|
||||||
|
{
|
||||||
|
float distance = Vector3.Distance(_enemyController.transform.position, _playerTransform.position);
|
||||||
|
if (distance < StuckMoveThreshold)
|
||||||
|
{
|
||||||
|
_stuckTimer += Time.deltaTime;
|
||||||
|
if (_stuckTimer >= StuckThresholdTime)
|
||||||
|
{
|
||||||
|
// 막다른 길임 : 대체 행동 실행
|
||||||
|
HandleDeadEnd();
|
||||||
|
_stuckTimer = 0f;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
else
|
||||||
|
{
|
||||||
|
// 정상적인 길: 배틀 루프 실행
|
||||||
|
_enemyController.BattleSequence();
|
||||||
|
_stuckTimer = 0f;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
private void FindPositionFlee()
|
||||||
|
{
|
||||||
|
// 1) 목표 도망 위치 계산
|
||||||
|
Vector3 fleeDirection = (_enemyController.transform.position - _playerTransform.position).normalized;
|
||||||
|
Vector3 fleeTarget = _enemyController.transform.position + fleeDirection * _fleeDistance;
|
||||||
|
|
||||||
|
// 2) 경로 계산해 보기
|
||||||
|
NavMeshPath path = new NavMeshPath();
|
||||||
|
_enemyController.Agent.CalculatePath(fleeTarget, path);
|
||||||
|
|
||||||
|
if (path.status == NavMeshPathStatus.PathComplete)
|
||||||
|
{
|
||||||
|
// 제대로 도망갈 수 있으면 목적지 설정
|
||||||
|
_enemyController.Agent.SetDestination(fleeTarget);
|
||||||
|
}
|
||||||
|
else
|
||||||
|
{
|
||||||
|
// 막다른 길임 : 대체 행동 실행
|
||||||
|
HandleDeadEnd();
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
private void HandleDeadEnd()
|
||||||
|
{
|
||||||
|
// 무작위 도망 지점 샘플링 시도
|
||||||
|
Vector3 randomDirection = Random.insideUnitSphere * (_fleeDistance * 2);
|
||||||
|
randomDirection += _playerTransform.position;
|
||||||
|
|
||||||
|
if (NavMesh.SamplePosition(randomDirection, out var hit, (_fleeDistance * 2), NavMesh.AllAreas))
|
||||||
|
{
|
||||||
|
_enemyController.Agent.SetDestination(hit.position);
|
||||||
|
return;
|
||||||
|
}
|
||||||
|
|
||||||
|
// 대체 경로도 찾을 수 없는 경우
|
||||||
|
_enemyController.OnCannotFleeBehaviour();
|
||||||
|
}
|
||||||
|
|
||||||
|
public void Exit()
|
||||||
|
{
|
||||||
|
_playerTransform = null;
|
||||||
|
_enemyController = null;
|
||||||
|
}
|
||||||
|
}
|
@ -0,0 +1,3 @@
|
|||||||
|
fileFormatVersion: 2
|
||||||
|
guid: 52fff5e2310f42608e3e3c5b45dcae38
|
||||||
|
timeCreated: 1745554266
|
3
Assets/Scripts/Character/Enemy/EnemyState/Commons.meta
Normal file
3
Assets/Scripts/Character/Enemy/EnemyState/Commons.meta
Normal file
@ -0,0 +1,3 @@
|
|||||||
|
fileFormatVersion: 2
|
||||||
|
guid: 452917766030468e87209330ca1b410e
|
||||||
|
timeCreated: 1745554696
|
@ -1,8 +1,8 @@
|
|||||||
using UnityEngine;
|
using System;
|
||||||
|
using UnityEngine;
|
||||||
|
|
||||||
public class EnemyStateIdle: IEnemyState
|
public class EnemyStateIdle: IEnemyState
|
||||||
{
|
{
|
||||||
|
|
||||||
private EnemyController _enemyController;
|
private EnemyController _enemyController;
|
||||||
|
|
||||||
public void Enter(EnemyController enemyController)
|
public void Enter(EnemyController enemyController)
|
||||||
@ -17,7 +17,17 @@ public class EnemyStateIdle: IEnemyState
|
|||||||
var detectPlayerTransform = _enemyController.DetectPlayerInCircle();
|
var detectPlayerTransform = _enemyController.DetectPlayerInCircle();
|
||||||
if (detectPlayerTransform)
|
if (detectPlayerTransform)
|
||||||
{
|
{
|
||||||
_enemyController.SetState(EnemyState.Trace);
|
switch (_enemyController.MonsterType)
|
||||||
|
{
|
||||||
|
case MonsterType.Melee:
|
||||||
|
_enemyController.SetState(EnemyState.Trace);
|
||||||
|
break;
|
||||||
|
case MonsterType.Caster:
|
||||||
|
_enemyController.SetState(EnemyState.Flee);
|
||||||
|
break;
|
||||||
|
case MonsterType.Ranged:
|
||||||
|
break;
|
||||||
|
}
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
@ -1,24 +0,0 @@
|
|||||||
using System.Collections;
|
|
||||||
using System.Collections.Generic;
|
|
||||||
using UnityEngine;
|
|
||||||
|
|
||||||
public class EnemyStateAttack : IEnemyState
|
|
||||||
{
|
|
||||||
private EnemyController _enemyController;
|
|
||||||
|
|
||||||
|
|
||||||
public void Enter(EnemyController enemyController)
|
|
||||||
{
|
|
||||||
_enemyController = enemyController;
|
|
||||||
}
|
|
||||||
|
|
||||||
public void Update()
|
|
||||||
{
|
|
||||||
|
|
||||||
}
|
|
||||||
|
|
||||||
public void Exit()
|
|
||||||
{
|
|
||||||
_enemyController = null;
|
|
||||||
}
|
|
||||||
}
|
|
@ -1,3 +0,0 @@
|
|||||||
fileFormatVersion: 2
|
|
||||||
guid: 29b87c92807e4f6b94c8a08ccc510321
|
|
||||||
timeCreated: 1744799701
|
|
3
Assets/Scripts/Character/Enemy/EnemyState/Melee.meta
Normal file
3
Assets/Scripts/Character/Enemy/EnemyState/Melee.meta
Normal file
@ -0,0 +1,3 @@
|
|||||||
|
fileFormatVersion: 2
|
||||||
|
guid: 64b8e3ece30b427eb71a9b6e33292292
|
||||||
|
timeCreated: 1745554748
|
@ -30,16 +30,13 @@ public class EnemyStateTrace : IEnemyState
|
|||||||
|
|
||||||
public void Update()
|
public void Update()
|
||||||
{
|
{
|
||||||
if(_enemyController.IsMeleeCombat) return;
|
if (_enemyController.Agent.enabled != true ||
|
||||||
if (_enemyController.Agent.enabled != true) return;
|
_enemyController.IsMeleeCombat) return;
|
||||||
|
|
||||||
PlayerTracking();
|
PlayerTracking();
|
||||||
|
|
||||||
if (_enemyController.Agent.remainingDistance <= _enemyController.Agent.stoppingDistance)
|
// 전투 패턴은 몬스터 객체에게 위임
|
||||||
{
|
_enemyController.BattleSequence();
|
||||||
// TODO: 타겟에 도착함 -> 공격 준비
|
|
||||||
// _enemyController.SetState(EnemyState.Attack);
|
|
||||||
}
|
|
||||||
}
|
}
|
||||||
|
|
||||||
public void Exit()
|
public void Exit()
|
@ -1,6 +1,7 @@
|
|||||||
using System;
|
using System;
|
||||||
using System.Collections;
|
using System.Collections;
|
||||||
using System.Collections.Generic;
|
using System.Collections.Generic;
|
||||||
|
using System.Linq;
|
||||||
using Unity.VisualScripting;
|
using Unity.VisualScripting;
|
||||||
using UnityEngine;
|
using UnityEngine;
|
||||||
using UnityEngine.Serialization;
|
using UnityEngine.Serialization;
|
||||||
@ -8,6 +9,8 @@ using Random = UnityEngine.Random;
|
|||||||
|
|
||||||
public class PldDogController : EnemyController
|
public class PldDogController : EnemyController
|
||||||
{
|
{
|
||||||
|
// ----
|
||||||
|
// 팔라딘 독 고유 액션
|
||||||
private static readonly int WindUp = Animator.StringToHash("WindUp");
|
private static readonly int WindUp = Animator.StringToHash("WindUp");
|
||||||
private static readonly int Slash = Animator.StringToHash("Slash");
|
private static readonly int Slash = Animator.StringToHash("Slash");
|
||||||
private static readonly int BoomShot = Animator.StringToHash("BoomShot");
|
private static readonly int BoomShot = Animator.StringToHash("BoomShot");
|
||||||
@ -35,7 +38,7 @@ public class PldDogController : EnemyController
|
|||||||
[SerializeField] private GameObject horizontalSlash;
|
[SerializeField] private GameObject horizontalSlash;
|
||||||
|
|
||||||
private float _patternTimer = 0f;
|
private float _patternTimer = 0f;
|
||||||
private int _currentPatternIndex = 0;
|
private int _lastPatternIndex = -1;
|
||||||
private bool _isPatternRunning = false;
|
private bool _isPatternRunning = false;
|
||||||
private bool _isFirstAttack = true;
|
private bool _isFirstAttack = true;
|
||||||
|
|
||||||
@ -53,23 +56,20 @@ public class PldDogController : EnemyController
|
|||||||
};
|
};
|
||||||
}
|
}
|
||||||
|
|
||||||
protected override void Update()
|
public override void BattleSequence()
|
||||||
{
|
{
|
||||||
base.Update();
|
_patternTimer += Time.deltaTime;
|
||||||
|
if (_isPatternRunning) return;
|
||||||
if (CurrentState != EnemyState.Trace || _isPatternRunning)
|
|
||||||
return;
|
|
||||||
|
|
||||||
float distanceToPlayer = Vector3.Distance(transform.position, TraceTargetTransform.position);
|
float distanceToPlayer = Vector3.Distance(transform.position, TraceTargetTransform.position);
|
||||||
|
|
||||||
if (distanceToPlayer <= meleeRange) // 근접 범위
|
if (distanceToPlayer <= meleeRange) // 근접 범위
|
||||||
{
|
{
|
||||||
if (!Agent.isStopped) Agent.isStopped = true;
|
if (!Agent.isStopped) Agent.isStopped = true;
|
||||||
_patternTimer += Time.deltaTime;
|
|
||||||
|
|
||||||
if (!_isPatternRunning && (_isFirstAttack || _patternTimer >= patternInterval))
|
if (!_isPatternRunning && (_isFirstAttack || _patternTimer >= patternInterval))
|
||||||
{
|
{
|
||||||
ExecutePattern(_currentPatternIndex);
|
ExecutePattern();
|
||||||
|
|
||||||
_isFirstAttack = false;
|
_isFirstAttack = false;
|
||||||
}
|
}
|
||||||
@ -78,24 +78,31 @@ public class PldDogController : EnemyController
|
|||||||
{
|
{
|
||||||
if (Agent.isStopped) Agent.isStopped = false;
|
if (Agent.isStopped) Agent.isStopped = false;
|
||||||
Agent.SetDestination(TraceTargetTransform.position);
|
Agent.SetDestination(TraceTargetTransform.position);
|
||||||
_patternTimer += Time.deltaTime;
|
|
||||||
|
|
||||||
if (!_isPatternRunning && _patternTimer >= patternInterval)
|
if (!_isPatternRunning && _patternTimer >= patternInterval)
|
||||||
{
|
{
|
||||||
|
Debug.Log("## 폭탄 던질 조건 만족");
|
||||||
BombThrowPattern();
|
BombThrowPattern();
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
private void ExecutePattern(int patternIndex)
|
private void ExecutePattern()
|
||||||
{
|
{
|
||||||
_isPatternRunning = true;
|
_isPatternRunning = true;
|
||||||
Agent.isStopped = true;
|
Agent.isStopped = true;
|
||||||
IsMeleeCombat = true;
|
IsMeleeCombat = true;
|
||||||
|
|
||||||
_patternActions[_currentPatternIndex]?.Invoke();
|
var available = Enumerable
|
||||||
|
.Range(0, _patternActions.Count)
|
||||||
|
.Where(i => i != _lastPatternIndex)
|
||||||
|
.ToList();
|
||||||
|
|
||||||
_currentPatternIndex = (_currentPatternIndex + 1) % _patternActions.Count; // 패턴 순환
|
int nextIndex = available[Random.Range(0, available.Count)];
|
||||||
|
|
||||||
|
_patternActions[nextIndex]?.Invoke();
|
||||||
|
|
||||||
|
_lastPatternIndex = nextIndex;
|
||||||
}
|
}
|
||||||
|
|
||||||
// 순환 패턴과 별개로 동작하는 특수 패턴
|
// 순환 패턴과 별개로 동작하는 특수 패턴
|
||||||
|
Loading…
x
Reference in New Issue
Block a user