Compare commits
No commits in common. "d5df426b8ff62576805521c2ebeea932c1f537a9" and "885e637119be446dccbe7cab0358d229df731701" have entirely different histories.
d5df426b8f
...
885e637119
BIN
Assets/JYY/Animator/Alien Big Blink.controller
(Stored with Git LFS)
BIN
Assets/JYY/Animator/Alien Big Blink.controller
(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.
@ -1,8 +0,0 @@
|
|||||||
fileFormatVersion: 2
|
|
||||||
guid: 0f665d75f6d77274a9371a87e014fd97
|
|
||||||
folderAsset: yes
|
|
||||||
DefaultImporter:
|
|
||||||
externalObjects: {}
|
|
||||||
userData:
|
|
||||||
assetBundleName:
|
|
||||||
assetBundleVariant:
|
|
@ -1,43 +0,0 @@
|
|||||||
using System.Collections;
|
|
||||||
using UnityEngine;
|
|
||||||
|
|
||||||
public class KnockbackEffect : StatusEffect
|
|
||||||
{
|
|
||||||
private Vector3 _sourcePosition;
|
|
||||||
private float _knockbackForce;
|
|
||||||
private float _elapsed = 0f;
|
|
||||||
|
|
||||||
public KnockbackEffect(Vector3 sourcePosition, float knockbackForce,float duration)
|
|
||||||
{
|
|
||||||
effectName = DebuffType.Knockback.ToString();
|
|
||||||
this.duration = duration;
|
|
||||||
_sourcePosition = sourcePosition;
|
|
||||||
_knockbackForce = knockbackForce;
|
|
||||||
}
|
|
||||||
|
|
||||||
public override void ApplyEffect(CharacterBase target)
|
|
||||||
{
|
|
||||||
|
|
||||||
Vector3 direction = (target.transform.position - _sourcePosition).normalized;
|
|
||||||
direction.y = 0f; // 수직 방향 제거
|
|
||||||
target.StartCoroutine(KnockbackCoroutine(target, direction));
|
|
||||||
}
|
|
||||||
private IEnumerator KnockbackCoroutine(CharacterBase pc, Vector3 direction)
|
|
||||||
{
|
|
||||||
CharacterController controller = pc.GetComponent<CharacterController>();
|
|
||||||
if (controller == null) yield break;
|
|
||||||
|
|
||||||
_elapsed = 0f;
|
|
||||||
while (_elapsed < duration)
|
|
||||||
{
|
|
||||||
controller.Move(direction * (_knockbackForce * Time.deltaTime));
|
|
||||||
_elapsed += Time.deltaTime;
|
|
||||||
yield return null;
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
public override void RemoveEffect(CharacterBase target)
|
|
||||||
{
|
|
||||||
|
|
||||||
}
|
|
||||||
}
|
|
@ -1,3 +0,0 @@
|
|||||||
fileFormatVersion: 2
|
|
||||||
guid: 97861883fd2941e0a40071b12ca13de4
|
|
||||||
timeCreated: 1746082842
|
|
@ -6,21 +6,26 @@ public class SlowDebuff : StatusEffect
|
|||||||
|
|
||||||
public SlowDebuff(float duration, float slowMultiplier)
|
public SlowDebuff(float duration, float slowMultiplier)
|
||||||
{
|
{
|
||||||
this.effectName = DebuffType.Slow.ToString();
|
this.effectName = "Slow";
|
||||||
this.duration = duration;
|
this.duration = duration;
|
||||||
_slowMultiplier = slowMultiplier;
|
_slowMultiplier = slowMultiplier;
|
||||||
}
|
}
|
||||||
|
|
||||||
public override void ApplyEffect(CharacterBase target)
|
public override void ApplyEffect(CharacterBase target)
|
||||||
{
|
{
|
||||||
target.moveSpeed *= _slowMultiplier;
|
if (target is PlayerController pc)
|
||||||
Debug.Log($"{target.characterName}에게 이동 속도 감소 적용됨");
|
{
|
||||||
|
pc.moveSpeed *= _slowMultiplier;
|
||||||
|
Debug.Log($"{target.characterName}에게 이동 속도 감소 적용됨");
|
||||||
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
public override void RemoveEffect(CharacterBase target)
|
public override void RemoveEffect(CharacterBase target)
|
||||||
{
|
{
|
||||||
target.moveSpeed /= _slowMultiplier;
|
if (target is PlayerController pc)
|
||||||
Debug.Log($"{target.characterName}의 이동 속도 회복됨");
|
{
|
||||||
|
pc.moveSpeed /= _slowMultiplier;
|
||||||
|
Debug.Log($"{target.characterName}의 이동 속도 회복됨");
|
||||||
|
}
|
||||||
}
|
}
|
||||||
}
|
}
|
@ -24,7 +24,6 @@ public abstract class AoeControllerBase : MonoBehaviour
|
|||||||
protected DamageEffectData _data;
|
protected DamageEffectData _data;
|
||||||
private Action _slashAction;
|
private Action _slashAction;
|
||||||
private Action _destroyAction;
|
private Action _destroyAction;
|
||||||
protected string EffectName;
|
|
||||||
|
|
||||||
/// <summary>
|
/// <summary>
|
||||||
/// 범위 공격 이펙트를 설정하고, 딜레이 후 폭발을 실행합니다.
|
/// 범위 공격 이펙트를 설정하고, 딜레이 후 폭발을 실행합니다.
|
||||||
@ -39,17 +38,6 @@ public abstract class AoeControllerBase : MonoBehaviour
|
|||||||
StartCoroutine(ExplodeAfterDelay());
|
StartCoroutine(ExplodeAfterDelay());
|
||||||
}
|
}
|
||||||
|
|
||||||
public void SetEffect(DamageEffectData data, Action slashAction, Action destroyAction, string effectName)
|
|
||||||
{
|
|
||||||
_data = data;
|
|
||||||
_slashAction = slashAction;
|
|
||||||
_destroyAction = destroyAction;
|
|
||||||
EffectName = effectName;
|
|
||||||
|
|
||||||
ShowWarningEffect();
|
|
||||||
StartCoroutine(ExplodeAfterDelay());
|
|
||||||
}
|
|
||||||
|
|
||||||
protected virtual void ShowWarningEffect()
|
protected virtual void ShowWarningEffect()
|
||||||
{
|
{
|
||||||
if (warningEffectInstance != null)
|
if (warningEffectInstance != null)
|
||||||
|
@ -2,6 +2,8 @@
|
|||||||
using System.Collections;
|
using System.Collections;
|
||||||
using UnityEngine;
|
using UnityEngine;
|
||||||
|
|
||||||
|
|
||||||
|
|
||||||
public class ChariotAoeController : AoeControllerBase
|
public class ChariotAoeController : AoeControllerBase
|
||||||
{
|
{
|
||||||
protected override void ShowDamageEffect()
|
protected override void ShowDamageEffect()
|
||||||
|
@ -1,11 +1,5 @@
|
|||||||
using UnityEngine;
|
using UnityEngine;
|
||||||
|
|
||||||
public enum DebuffType
|
|
||||||
{
|
|
||||||
Slow,
|
|
||||||
Knockback,
|
|
||||||
}
|
|
||||||
|
|
||||||
public class MagicAoEField : AoeControllerBase
|
public class MagicAoEField : AoeControllerBase
|
||||||
{
|
{
|
||||||
protected override void HitCheck()
|
protected override void HitCheck()
|
||||||
@ -19,33 +13,14 @@ public class MagicAoEField : AoeControllerBase
|
|||||||
Debug.Log($"{hit.name}에게 {_data.damage} 데미지 적용");
|
Debug.Log($"{hit.name}에게 {_data.damage} 데미지 적용");
|
||||||
// TODO: 실제 데미지 처리 로직 호출
|
// TODO: 실제 데미지 처리 로직 호출
|
||||||
// 임시 데이미 처리 로직
|
// 임시 데이미 처리 로직
|
||||||
ApplyEffect(hit);
|
PlayerController playerController = hit.transform.GetComponent<PlayerController>();
|
||||||
}
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
private void ApplyEffect(Collider hit)
|
|
||||||
{
|
|
||||||
PlayerController playerController = hit.transform.GetComponent<PlayerController>();
|
|
||||||
switch (EffectName)
|
|
||||||
{
|
|
||||||
case "Slow":
|
|
||||||
|
|
||||||
if (playerController != null)
|
if (playerController != null)
|
||||||
{
|
{
|
||||||
|
// playerController.AddStatusEffect(_slowDebuff);
|
||||||
var slow = new SlowDebuff(10f, 0.5f); // 10초간 50% 속도
|
var slow = new SlowDebuff(10f, 0.5f); // 10초간 50% 속도
|
||||||
playerController.AddStatusEffect(slow);
|
playerController.AddStatusEffect(slow);
|
||||||
}
|
}
|
||||||
break;
|
}
|
||||||
case "Knockback":
|
|
||||||
if (playerController != null)
|
|
||||||
{
|
|
||||||
var knPos = transform.position;
|
|
||||||
knPos.y += 0.5f;
|
|
||||||
var knockback = new KnockbackEffect(knPos,10f, 0.5f); // 장판 중심에서 10f만큼
|
|
||||||
playerController.AddStatusEffect(knockback);
|
|
||||||
}
|
|
||||||
break;
|
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
}
|
}
|
@ -1,6 +1,9 @@
|
|||||||
using System;
|
using System;
|
||||||
using System.Collections;
|
using System.Collections;
|
||||||
|
using System.Collections.Generic;
|
||||||
|
using Unity.VisualScripting;
|
||||||
using UnityEngine;
|
using UnityEngine;
|
||||||
|
using UnityEngine.AI;
|
||||||
using Random = UnityEngine.Random;
|
using Random = UnityEngine.Random;
|
||||||
|
|
||||||
public class CasterDemonController : EnemyController
|
public class CasterDemonController : EnemyController
|
||||||
@ -8,15 +11,16 @@ public class CasterDemonController : EnemyController
|
|||||||
// Animation
|
// Animation
|
||||||
public static readonly int Cast = Animator.StringToHash("Cast");
|
public static readonly int Cast = Animator.StringToHash("Cast");
|
||||||
public static readonly int Flee = Animator.StringToHash("Flee");
|
public static readonly int Flee = Animator.StringToHash("Flee");
|
||||||
public static readonly int MagicMissile = Animator.StringToHash("MagicMissile");
|
|
||||||
public static readonly int Telepo = Animator.StringToHash("Telepo");
|
private bool _doneBattleSequence = true;
|
||||||
public static readonly int Spin = Animator.StringToHash("Spin");
|
private bool _isFirstNoPath = true;
|
||||||
|
|
||||||
|
private Coroutine _currentSequence;
|
||||||
|
|
||||||
[SerializeField] private Transform teleportTransform;
|
[SerializeField] private Transform teleportTransform;
|
||||||
[SerializeField] private Transform bulletShotPosition;
|
[SerializeField] private Transform bulletShotPosition;
|
||||||
[SerializeField] private GameObject magicMissilePrefab;
|
[SerializeField] private GameObject magicMissilePrefab;
|
||||||
[SerializeField] private GameObject teleportEffectPrefab;
|
[SerializeField] private GameObject teleportEffectPrefab;
|
||||||
[SerializeField] private Vector3 teleportTargetPosition = Vector3.zero;
|
|
||||||
|
|
||||||
[Header("각종 데미지 이펙트 세트")]
|
[Header("각종 데미지 이펙트 세트")]
|
||||||
[SerializeField] private GameObject chariotWarning;
|
[SerializeField] private GameObject chariotWarning;
|
||||||
@ -25,128 +29,40 @@ public class CasterDemonController : EnemyController
|
|||||||
[Space(10)]
|
[Space(10)]
|
||||||
[SerializeField] private GameObject slowFieldWarning;
|
[SerializeField] private GameObject slowFieldWarning;
|
||||||
[SerializeField] private GameObject slowFieldEffect;
|
[SerializeField] private GameObject slowFieldEffect;
|
||||||
[SerializeField] private GameObject knockbackEffect;
|
|
||||||
private float _knockbackTimer = 10f;
|
|
||||||
private const float KnockBackThresholdTime = 10f;
|
|
||||||
|
|
||||||
// 텔레포트 쿨타임 처음엔 빨리 사용 가능함
|
private float _teleportDistance = 4f; // 플레이어 뒤로 떨어질 거리
|
||||||
private float _teleportTimer = 10f;
|
|
||||||
|
// 텔레포트 쿨타임
|
||||||
|
private float _teleportTimer = 0;
|
||||||
private const float TeleportThresholdTime = 20f;
|
private const float TeleportThresholdTime = 20f;
|
||||||
|
|
||||||
// 다음 행동 생각 처음엔 즉시 실행
|
|
||||||
private float _tinkingTimer = 3f;
|
|
||||||
private float _thinkingThresholdTime = 3f;
|
|
||||||
|
|
||||||
private bool _doneBattleSequence = true;
|
|
||||||
private Coroutine _currentSequence;
|
|
||||||
|
|
||||||
|
|
||||||
private DamageEffectData? _knockbackData;
|
|
||||||
private DamageEffectData KnockbackData
|
|
||||||
{
|
|
||||||
get
|
|
||||||
{
|
|
||||||
if (_knockbackData == null)
|
|
||||||
{
|
|
||||||
_knockbackData = new DamageEffectData
|
|
||||||
{
|
|
||||||
damage = 0,
|
|
||||||
radius = 7.5f,
|
|
||||||
delay = 0.5f,
|
|
||||||
targetLayer = TargetLayerMask,
|
|
||||||
explosionEffectPrefab = knockbackEffect
|
|
||||||
};
|
|
||||||
}
|
|
||||||
return _knockbackData.Value;
|
|
||||||
}
|
|
||||||
}
|
|
||||||
private DamageEffectData? _slowFieldEffectData;
|
|
||||||
private DamageEffectData SlowFieldEffectData
|
|
||||||
{
|
|
||||||
get
|
|
||||||
{
|
|
||||||
if (_slowFieldEffectData == null)
|
|
||||||
{
|
|
||||||
_slowFieldEffectData = new DamageEffectData
|
|
||||||
{
|
|
||||||
damage = 0,
|
|
||||||
radius = 7.5f,
|
|
||||||
delay = 2.5f,
|
|
||||||
targetLayer = TargetLayerMask,
|
|
||||||
explosionEffectPrefab = slowFieldEffect
|
|
||||||
};
|
|
||||||
}
|
|
||||||
return _slowFieldEffectData.Value;
|
|
||||||
}
|
|
||||||
}
|
|
||||||
private DamageEffectData? _teleportEffectData;
|
|
||||||
private DamageEffectData TeleportEffectData
|
|
||||||
{
|
|
||||||
get
|
|
||||||
{
|
|
||||||
if (_teleportEffectData == null)
|
|
||||||
{
|
|
||||||
_teleportEffectData = new DamageEffectData
|
|
||||||
{
|
|
||||||
damage = (int)attackPower,
|
|
||||||
radius = 10,
|
|
||||||
delay = 1.5f,
|
|
||||||
targetLayer = TargetLayerMask,
|
|
||||||
explosionEffectPrefab = chariotEffect
|
|
||||||
};
|
|
||||||
}
|
|
||||||
return _teleportEffectData.Value;
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
// 특수 스킬 사용 가능 여부
|
|
||||||
private bool CanKnockback
|
|
||||||
{
|
|
||||||
get
|
|
||||||
{
|
|
||||||
if (!(_knockbackTimer >= KnockBackThresholdTime)) return false;
|
|
||||||
_knockbackTimer = 0f;
|
|
||||||
return true;
|
|
||||||
}
|
|
||||||
}
|
|
||||||
private bool CanTeleport {
|
private bool CanTeleport {
|
||||||
get
|
get
|
||||||
{
|
{
|
||||||
if (!(_teleportTimer >= TeleportThresholdTime)) return false;
|
if (_teleportTimer >= TeleportThresholdTime )
|
||||||
_teleportTimer = 0;
|
|
||||||
return true;
|
|
||||||
}
|
|
||||||
}
|
|
||||||
private bool CanBattleSequence
|
|
||||||
{
|
|
||||||
get
|
|
||||||
{
|
|
||||||
if (_tinkingTimer >= _thinkingThresholdTime)
|
|
||||||
{
|
{
|
||||||
_tinkingTimer = 0;
|
_teleportTimer = 0;
|
||||||
return true;
|
return true;
|
||||||
}
|
}
|
||||||
return false;
|
return false;
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|
||||||
private void LateUpdate()
|
private void LateUpdate()
|
||||||
{
|
{
|
||||||
_teleportTimer += Time.deltaTime;
|
_teleportTimer += Time.deltaTime;
|
||||||
_tinkingTimer += Time.deltaTime;
|
|
||||||
_knockbackTimer += Time.deltaTime;
|
|
||||||
}
|
}
|
||||||
|
|
||||||
public override void BattleSequence()
|
public override void BattleSequence()
|
||||||
{
|
{
|
||||||
// 전투 행동이 이미 진행 중일 경우 실행 막기
|
// 전투 행동이 이미 진행 중일 경우 실행 막기
|
||||||
if (_doneBattleSequence && CanBattleSequence)
|
if (_doneBattleSequence)
|
||||||
{
|
{
|
||||||
// 전투 행동 시작
|
// 전투 행동 시작
|
||||||
_doneBattleSequence = false;
|
_doneBattleSequence = false;
|
||||||
|
|
||||||
// 사용할 공격 생각하기
|
// TODO : 배틀 중일 때 루프
|
||||||
|
// Debug.Log("## 몬스터의 교전 행동 루프");
|
||||||
Thinking();
|
Thinking();
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
@ -158,18 +74,26 @@ public class CasterDemonController : EnemyController
|
|||||||
switch (selectedPattern)
|
switch (selectedPattern)
|
||||||
{
|
{
|
||||||
case 0:
|
case 0:
|
||||||
|
|
||||||
case 1:
|
case 1:
|
||||||
|
|
||||||
case 2:
|
case 2:
|
||||||
|
|
||||||
case 3:
|
case 3:
|
||||||
|
|
||||||
case 4:
|
case 4:
|
||||||
SetSequence(ShotMagicMissile);
|
|
||||||
break;
|
|
||||||
case 5:
|
case 5:
|
||||||
|
|
||||||
case 6:
|
case 6:
|
||||||
|
|
||||||
case 7:
|
case 7:
|
||||||
|
|
||||||
case 8:
|
case 8:
|
||||||
|
|
||||||
case 9:
|
case 9:
|
||||||
SetSequence(SlowFieldSpell);
|
// SetSequence(ShotMagicMissile());
|
||||||
|
SetSequence(SlowFieldSpell());
|
||||||
break;
|
break;
|
||||||
}
|
}
|
||||||
|
|
||||||
@ -179,13 +103,8 @@ public class CasterDemonController : EnemyController
|
|||||||
{
|
{
|
||||||
if (CanTeleport)
|
if (CanTeleport)
|
||||||
{
|
{
|
||||||
action.Invoke();
|
action();
|
||||||
Teleport();
|
Teleport();
|
||||||
return;
|
|
||||||
}
|
|
||||||
if (CanKnockback)
|
|
||||||
{
|
|
||||||
SetSequence(KnockbackSpell);
|
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
@ -197,7 +116,6 @@ public class CasterDemonController : EnemyController
|
|||||||
|
|
||||||
// 플레이어 위치를 바라보고
|
// 플레이어 위치를 바라보고
|
||||||
transform.LookAt(aimPosition);
|
transform.LookAt(aimPosition);
|
||||||
SetAnimation(MagicMissile);
|
|
||||||
|
|
||||||
// 미사일 생성 및 초기화
|
// 미사일 생성 및 초기화
|
||||||
var missile = Instantiate(
|
var missile = Instantiate(
|
||||||
@ -208,11 +126,12 @@ public class CasterDemonController : EnemyController
|
|||||||
missile.GetComponent<MagicMissile>()
|
missile.GetComponent<MagicMissile>()
|
||||||
.Initialize(new BulletData(aimPosition, 5f, 10f, 5f));
|
.Initialize(new BulletData(aimPosition, 5f, 10f, 5f));
|
||||||
|
|
||||||
yield return Wait.For(0.4f);
|
yield return new WaitForSeconds(0.4f);
|
||||||
}
|
}
|
||||||
|
|
||||||
// 짧은 텀 후 끝내기
|
// 짧은 텀 후 끝내기
|
||||||
yield return Wait.For(1f);
|
yield return new WaitForSeconds(1f);
|
||||||
|
_doneBattleSequence = true;
|
||||||
}
|
}
|
||||||
|
|
||||||
private Vector3 TargetPosOracle(out Vector3 basePos, out Rigidbody rb)
|
private Vector3 TargetPosOracle(out Vector3 basePos, out Rigidbody rb)
|
||||||
@ -245,16 +164,22 @@ public class CasterDemonController : EnemyController
|
|||||||
// 텔레포트와 함께 시전하는 범위 공격
|
// 텔레포트와 함께 시전하는 범위 공격
|
||||||
var aoe = Instantiate(chariotWarning, startPos, Quaternion.identity).GetComponent<ChariotAoeController>();
|
var aoe = Instantiate(chariotWarning, startPos, Quaternion.identity).GetComponent<ChariotAoeController>();
|
||||||
|
|
||||||
|
var effectData = new DamageEffectData
|
||||||
|
{
|
||||||
|
damage = (int)attackPower,
|
||||||
|
radius = 10,
|
||||||
|
delay = 1.5f,
|
||||||
|
targetLayer = TargetLayerMask,
|
||||||
|
explosionEffectPrefab = chariotEffect
|
||||||
|
};
|
||||||
|
|
||||||
|
aoe.SetEffect(effectData, null, null);
|
||||||
|
|
||||||
aoe.SetEffect(TeleportEffectData, null, null);
|
// 중앙으로 이동
|
||||||
|
Agent.Warp(Vector3.zero);
|
||||||
// 텔레포트 타겟 위치로 이동
|
|
||||||
Agent.Warp(teleportTargetPosition);
|
|
||||||
SetAnimation(Telepo);
|
|
||||||
|
|
||||||
if (teleportEffectPrefab != null)
|
if (teleportEffectPrefab != null)
|
||||||
Instantiate(teleportEffectPrefab, teleportTargetPosition, Quaternion.identity);
|
Instantiate(teleportEffectPrefab, Vector3.zero, Quaternion.identity);
|
||||||
}
|
}
|
||||||
|
|
||||||
private IEnumerator SlowFieldSpell()
|
private IEnumerator SlowFieldSpell()
|
||||||
@ -263,42 +188,35 @@ public class CasterDemonController : EnemyController
|
|||||||
// 1. 시전 애니메이션
|
// 1. 시전 애니메이션
|
||||||
transform.LookAt(aimPosition);
|
transform.LookAt(aimPosition);
|
||||||
SetAnimation(Cast);
|
SetAnimation(Cast);
|
||||||
|
|
||||||
// 2. 장판 생성과 세팅
|
// 2. 장판 생성과 세팅
|
||||||
|
|
||||||
|
var effectData = new DamageEffectData
|
||||||
|
{
|
||||||
|
damage = 0,
|
||||||
|
radius = 7.5f,
|
||||||
|
delay = 2.5f,
|
||||||
|
targetLayer = TargetLayerMask,
|
||||||
|
explosionEffectPrefab = slowFieldEffect
|
||||||
|
};
|
||||||
|
|
||||||
var fixedPos = new Vector3(aimPosition.x, 0, aimPosition.z);
|
var fixedPos = new Vector3(aimPosition.x, 0, aimPosition.z);
|
||||||
var warning = Instantiate(chariotWarning, fixedPos, Quaternion.identity).GetComponent<MagicAoEField>();
|
var warning = Instantiate(chariotWarning, fixedPos, Quaternion.identity).GetComponent<MagicAoEField>();
|
||||||
|
|
||||||
warning.SetEffect(SlowFieldEffectData, null, null);
|
warning.SetEffect(effectData, null, null);
|
||||||
|
// TODO : 효과 적용
|
||||||
|
|
||||||
// 3. 짧은 텀 후 끝내기
|
// 3. 짧은 텀 후 끝내기
|
||||||
yield return Wait.For(1f);
|
yield return new WaitForSeconds(1f);
|
||||||
}
|
|
||||||
|
|
||||||
private IEnumerator KnockbackSpell()
|
|
||||||
{
|
|
||||||
// 시전 애니메이션
|
|
||||||
SetAnimation(Spin);
|
|
||||||
|
|
||||||
// 넉백 발생
|
|
||||||
var knockback = Instantiate(chariotWarning, transform).GetComponent<MagicAoEField>();
|
|
||||||
knockback.SetEffect(KnockbackData, null, null, DebuffType.Knockback.ToString());
|
|
||||||
|
|
||||||
yield return Wait.For(1f);
|
|
||||||
}
|
|
||||||
|
|
||||||
#region 유틸리티
|
|
||||||
private void SetSequence(Func<IEnumerator> newSequence)
|
|
||||||
{
|
|
||||||
if (_currentSequence != null)
|
|
||||||
StopCoroutine(_currentSequence);
|
|
||||||
|
|
||||||
_currentSequence = StartCoroutine(RunPattern(newSequence));
|
|
||||||
}
|
|
||||||
|
|
||||||
private IEnumerator RunPattern(Func<IEnumerator> pattern)
|
|
||||||
{
|
|
||||||
yield return StartCoroutine(pattern());
|
|
||||||
_doneBattleSequence = true;
|
_doneBattleSequence = true;
|
||||||
}
|
}
|
||||||
#endregion
|
|
||||||
}
|
private void SetSequence(IEnumerator newSequence)
|
||||||
|
{
|
||||||
|
if (_currentSequence != null)
|
||||||
|
{
|
||||||
|
StopCoroutine(_currentSequence);
|
||||||
|
}
|
||||||
|
_currentSequence = StartCoroutine(newSequence);
|
||||||
|
}
|
||||||
|
|
||||||
|
}
|
||||||
|
@ -7,11 +7,8 @@ public class EnemyStateFlee :IEnemyState
|
|||||||
{
|
{
|
||||||
private EnemyController _enemyController;
|
private EnemyController _enemyController;
|
||||||
private Transform _playerTransform;
|
private Transform _playerTransform;
|
||||||
private float _attackRange = 7f; // 공격 범위
|
private float _fleeDistance = 5f; // 도망치는 거리
|
||||||
private float _fleeDistance = 15f; // 도망치는 거리
|
private float _safeRange = 7f; // 공격 범위
|
||||||
|
|
||||||
private float _attackRangeSqr;
|
|
||||||
private float _fleeDistanceSqr;
|
|
||||||
|
|
||||||
// 경로 탐색 주기 조절용
|
// 경로 탐색 주기 조절용
|
||||||
private float _fleeSearchTimer = 0;
|
private float _fleeSearchTimer = 0;
|
||||||
@ -36,9 +33,6 @@ public class EnemyStateFlee :IEnemyState
|
|||||||
_stuckTimer = 0f;
|
_stuckTimer = 0f;
|
||||||
_fleeSearchTimer = 0;
|
_fleeSearchTimer = 0;
|
||||||
|
|
||||||
_attackRangeSqr = _attackRange * _attackRange;
|
|
||||||
_fleeDistanceSqr = _fleeDistance * _fleeDistance;
|
|
||||||
|
|
||||||
_enemyController.SetAnimation(CasterDemonController.Flee, true);
|
_enemyController.SetAnimation(CasterDemonController.Flee, true);
|
||||||
}
|
}
|
||||||
|
|
||||||
@ -50,17 +44,11 @@ public class EnemyStateFlee :IEnemyState
|
|||||||
return;
|
return;
|
||||||
}
|
}
|
||||||
|
|
||||||
float currentDist = (_enemyController.transform.position - _playerTransform.position).sqrMagnitude;
|
float currentDist = Vector3.Distance(
|
||||||
|
_enemyController.transform.position,
|
||||||
if (currentDist >= _fleeDistanceSqr)
|
_playerTransform.position
|
||||||
{
|
);
|
||||||
_enemyController.Agent.isStopped = true;
|
if (currentDist >= _safeRange)
|
||||||
_enemyController.Agent.ResetPath();
|
|
||||||
_enemyController.SetState(EnemyState.Idle);
|
|
||||||
return;
|
|
||||||
}
|
|
||||||
|
|
||||||
if (currentDist >= _attackRangeSqr)
|
|
||||||
{
|
{
|
||||||
// 목적지 리셋 후 전투 시작
|
// 목적지 리셋 후 전투 시작
|
||||||
_enemyController.Agent.isStopped = true;
|
_enemyController.Agent.isStopped = true;
|
||||||
@ -86,8 +74,8 @@ public class EnemyStateFlee :IEnemyState
|
|||||||
|
|
||||||
private void CheckPath()
|
private void CheckPath()
|
||||||
{
|
{
|
||||||
float moved = (_enemyController.transform.position - _lastPosition).sqrMagnitude;
|
float moved = Vector3.Distance(_enemyController.transform.position, _lastPosition);
|
||||||
if (moved < StuckMoveThreshold * StuckMoveThreshold)
|
if (moved < StuckMoveThreshold)
|
||||||
{
|
{
|
||||||
_stuckTimer += Time.deltaTime;
|
_stuckTimer += Time.deltaTime;
|
||||||
if (_stuckTimer >= StuckThresholdTime)
|
if (_stuckTimer >= StuckThresholdTime)
|
||||||
@ -107,12 +95,14 @@ public class EnemyStateFlee :IEnemyState
|
|||||||
_fleeSearchTimer += Time.deltaTime;
|
_fleeSearchTimer += Time.deltaTime;
|
||||||
if (_fleeSearchTimer <= FleeThresholdTime) return;
|
if (_fleeSearchTimer <= FleeThresholdTime) return;
|
||||||
|
|
||||||
// 플레이어 반대방향으로 도망
|
// 1) 목표 도망 위치 계산
|
||||||
Vector3 fleeDirection = (_enemyController.transform.position - _playerTransform.position).normalized;
|
Vector3 fleeDirection = (_enemyController.transform.position - _playerTransform.position).normalized;
|
||||||
Vector3 fleeTarget = _enemyController.transform.position + fleeDirection * _fleeDistance;
|
Vector3 fleeTarget = _enemyController.transform.position + fleeDirection * _fleeDistance;
|
||||||
|
|
||||||
// 경로 설정
|
// 2) 경로 계산해 보기
|
||||||
_enemyController.Agent.SetDestination(fleeTarget);
|
_enemyController.Agent.SetDestination(fleeTarget);
|
||||||
|
|
||||||
|
// 3) 이동
|
||||||
_enemyController.Agent.isStopped = false;
|
_enemyController.Agent.isStopped = false;
|
||||||
_fleeSearchTimer = 0;
|
_fleeSearchTimer = 0;
|
||||||
}
|
}
|
||||||
|
@ -1,3 +0,0 @@
|
|||||||
fileFormatVersion: 2
|
|
||||||
guid: 6757ce2a26e44e9c931666533e7e8036
|
|
||||||
timeCreated: 1746594438
|
|
@ -1,18 +0,0 @@
|
|||||||
using System.Collections.Generic;
|
|
||||||
using UnityEngine;
|
|
||||||
|
|
||||||
// 코루틴의 WaitForSeconds를 캐싱하는 유틸
|
|
||||||
public static class Wait
|
|
||||||
{
|
|
||||||
private static readonly Dictionary<float, WaitForSeconds> _waits = new();
|
|
||||||
|
|
||||||
public static WaitForSeconds For(float seconds)
|
|
||||||
{
|
|
||||||
if (!_waits.TryGetValue(seconds, out var wait))
|
|
||||||
{
|
|
||||||
wait = new WaitForSeconds(seconds);
|
|
||||||
_waits[seconds] = wait;
|
|
||||||
}
|
|
||||||
return wait;
|
|
||||||
}
|
|
||||||
}
|
|
@ -1,3 +0,0 @@
|
|||||||
fileFormatVersion: 2
|
|
||||||
guid: e6fe7172532f42069e3fc7088ebd0718
|
|
||||||
timeCreated: 1746594464
|
|
Loading…
x
Reference in New Issue
Block a user