[Feat] 넉백 기능 구현
- 플레이어가 PlayerController를 사용한다고 가정하고 넉백 구현 Work in JIRA ISSUE DEG-100
This commit is contained in:
parent
9d46d0e61f
commit
32b3cb918a
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.
8
Assets/Plugins/Editor.meta
Normal file
8
Assets/Plugins/Editor.meta
Normal file
@ -0,0 +1,8 @@
|
||||
fileFormatVersion: 2
|
||||
guid: 0f665d75f6d77274a9371a87e014fd97
|
||||
folderAsset: yes
|
||||
DefaultImporter:
|
||||
externalObjects: {}
|
||||
userData:
|
||||
assetBundleName:
|
||||
assetBundleVariant:
|
43
Assets/Scripts/Character/Debuff/KnockbackEffect.cs
Normal file
43
Assets/Scripts/Character/Debuff/KnockbackEffect.cs
Normal file
@ -0,0 +1,43 @@
|
||||
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 = "Knockback";
|
||||
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)
|
||||
{
|
||||
|
||||
}
|
||||
}
|
3
Assets/Scripts/Character/Debuff/KnockbackEffect.cs.meta
Normal file
3
Assets/Scripts/Character/Debuff/KnockbackEffect.cs.meta
Normal file
@ -0,0 +1,3 @@
|
||||
fileFormatVersion: 2
|
||||
guid: 97861883fd2941e0a40071b12ca13de4
|
||||
timeCreated: 1746082842
|
@ -13,19 +13,14 @@ public class SlowDebuff : StatusEffect
|
||||
|
||||
public override void ApplyEffect(CharacterBase target)
|
||||
{
|
||||
if (target is PlayerController pc)
|
||||
{
|
||||
pc.moveSpeed *= _slowMultiplier;
|
||||
Debug.Log($"{target.characterName}에게 이동 속도 감소 적용됨");
|
||||
}
|
||||
target.moveSpeed *= _slowMultiplier;
|
||||
Debug.Log($"{target.characterName}에게 이동 속도 감소 적용됨");
|
||||
|
||||
}
|
||||
|
||||
public override void RemoveEffect(CharacterBase target)
|
||||
{
|
||||
if (target is PlayerController pc)
|
||||
{
|
||||
pc.moveSpeed /= _slowMultiplier;
|
||||
Debug.Log($"{target.characterName}의 이동 속도 회복됨");
|
||||
}
|
||||
target.moveSpeed /= _slowMultiplier;
|
||||
Debug.Log($"{target.characterName}의 이동 속도 회복됨");
|
||||
}
|
||||
}
|
@ -24,6 +24,7 @@ public abstract class AoeControllerBase : MonoBehaviour
|
||||
protected DamageEffectData _data;
|
||||
private Action _slashAction;
|
||||
private Action _destroyAction;
|
||||
protected string EffectName;
|
||||
|
||||
/// <summary>
|
||||
/// 범위 공격 이펙트를 설정하고, 딜레이 후 폭발을 실행합니다.
|
||||
@ -38,6 +39,17 @@ public abstract class AoeControllerBase : MonoBehaviour
|
||||
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()
|
||||
{
|
||||
if (warningEffectInstance != null)
|
||||
|
@ -13,14 +13,33 @@ public class MagicAoEField : AoeControllerBase
|
||||
Debug.Log($"{hit.name}에게 {_data.damage} 데미지 적용");
|
||||
// TODO: 실제 데미지 처리 로직 호출
|
||||
// 임시 데이미 처리 로직
|
||||
PlayerController playerController = hit.transform.GetComponent<PlayerController>();
|
||||
if (playerController != null)
|
||||
{
|
||||
// playerController.AddStatusEffect(_slowDebuff);
|
||||
var slow = new SlowDebuff(10f, 0.5f); // 10초간 50% 속도
|
||||
playerController.AddStatusEffect(slow);
|
||||
}
|
||||
ApplyEffect(hit);
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
private void ApplyEffect(Collider hit)
|
||||
{
|
||||
PlayerController playerController = hit.transform.GetComponent<PlayerController>();
|
||||
switch (EffectName)
|
||||
{
|
||||
case "Slow":
|
||||
|
||||
if (playerController != null)
|
||||
{
|
||||
var slow = new SlowDebuff(10f, 0.5f); // 10초간 50% 속도
|
||||
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;
|
||||
}
|
||||
}
|
||||
}
|
@ -11,6 +11,9 @@ public class CasterDemonController : EnemyController
|
||||
// Animation
|
||||
public static readonly int Cast = Animator.StringToHash("Cast");
|
||||
public static readonly int Flee = Animator.StringToHash("Flee");
|
||||
public static readonly int MagicMissile = Animator.StringToHash("MagicMissile");
|
||||
public static readonly int Telepo = Animator.StringToHash("Telepo");
|
||||
public static readonly int Spin = Animator.StringToHash("Spin");
|
||||
|
||||
private bool _doneBattleSequence = true;
|
||||
private bool _isFirstNoPath = true;
|
||||
@ -30,12 +33,16 @@ public class CasterDemonController : EnemyController
|
||||
[SerializeField] private GameObject slowFieldWarning;
|
||||
[SerializeField] private GameObject slowFieldEffect;
|
||||
|
||||
private float _teleportDistance = 4f; // 플레이어 뒤로 떨어질 거리
|
||||
// private float _teleportDistance = 4f; // 플레이어 뒤로 떨어질 거리
|
||||
|
||||
// 텔레포트 쿨타임
|
||||
private float _teleportTimer = 0;
|
||||
// 텔레포트 쿨타임 처음엔 빨리 사용 가능함
|
||||
private float _teleportTimer = 10f;
|
||||
private const float TeleportThresholdTime = 20f;
|
||||
|
||||
// 다음 행동 생각 처음엔 즉시 실행
|
||||
private float _tinkingTimer = 3f;
|
||||
private float _tinkingThresholedTime = 3f;
|
||||
|
||||
private bool CanTeleport {
|
||||
get
|
||||
{
|
||||
@ -48,15 +55,29 @@ public class CasterDemonController : EnemyController
|
||||
}
|
||||
}
|
||||
|
||||
private bool CanBattleSequence
|
||||
{
|
||||
get
|
||||
{
|
||||
if (_tinkingTimer >= _tinkingThresholedTime)
|
||||
{
|
||||
_tinkingTimer = 0;
|
||||
return true;
|
||||
}
|
||||
return false;
|
||||
}
|
||||
}
|
||||
|
||||
private void LateUpdate()
|
||||
{
|
||||
_teleportTimer += Time.deltaTime;
|
||||
_tinkingTimer += Time.deltaTime;
|
||||
}
|
||||
|
||||
public override void BattleSequence()
|
||||
{
|
||||
// 전투 행동이 이미 진행 중일 경우 실행 막기
|
||||
if (_doneBattleSequence)
|
||||
if (_doneBattleSequence && CanBattleSequence)
|
||||
{
|
||||
// 전투 행동 시작
|
||||
_doneBattleSequence = false;
|
||||
@ -74,13 +95,13 @@ public class CasterDemonController : EnemyController
|
||||
switch (selectedPattern)
|
||||
{
|
||||
case 0:
|
||||
|
||||
case 1:
|
||||
|
||||
case 2:
|
||||
|
||||
case 3:
|
||||
|
||||
SetSequence(ShotMagicMissile());
|
||||
break;
|
||||
case 4:
|
||||
|
||||
case 5:
|
||||
@ -92,7 +113,6 @@ public class CasterDemonController : EnemyController
|
||||
case 8:
|
||||
|
||||
case 9:
|
||||
// SetSequence(ShotMagicMissile());
|
||||
SetSequence(SlowFieldSpell());
|
||||
break;
|
||||
}
|
||||
@ -105,7 +125,9 @@ public class CasterDemonController : EnemyController
|
||||
{
|
||||
action();
|
||||
Teleport();
|
||||
return;
|
||||
}
|
||||
SetSequence(KnockbackSpell());
|
||||
}
|
||||
|
||||
private IEnumerator ShotMagicMissile()
|
||||
@ -116,6 +138,7 @@ public class CasterDemonController : EnemyController
|
||||
|
||||
// 플레이어 위치를 바라보고
|
||||
transform.LookAt(aimPosition);
|
||||
SetAnimation(MagicMissile);
|
||||
|
||||
// 미사일 생성 및 초기화
|
||||
var missile = Instantiate(
|
||||
@ -177,6 +200,7 @@ public class CasterDemonController : EnemyController
|
||||
|
||||
// 중앙으로 이동
|
||||
Agent.Warp(Vector3.zero);
|
||||
SetAnimation(Telepo);
|
||||
|
||||
if (teleportEffectPrefab != null)
|
||||
Instantiate(teleportEffectPrefab, Vector3.zero, Quaternion.identity);
|
||||
@ -210,6 +234,28 @@ public class CasterDemonController : EnemyController
|
||||
_doneBattleSequence = true;
|
||||
}
|
||||
|
||||
private IEnumerator KnockbackSpell()
|
||||
{
|
||||
// 시전 애니메이션
|
||||
SetAnimation(Spin);
|
||||
|
||||
var effectData = new DamageEffectData
|
||||
{
|
||||
damage = 0,
|
||||
radius = 7.5f,
|
||||
delay = 0.5f,
|
||||
targetLayer = TargetLayerMask,
|
||||
explosionEffectPrefab = slowFieldEffect
|
||||
};
|
||||
|
||||
// 넉백 발생
|
||||
var knockback = Instantiate(chariotWarning, transform).GetComponent<MagicAoEField>();
|
||||
knockback.SetEffect(effectData, null, null, "knockback");
|
||||
|
||||
yield return new WaitForSeconds(1f);
|
||||
_doneBattleSequence = true;
|
||||
}
|
||||
|
||||
private void SetSequence(IEnumerator newSequence)
|
||||
{
|
||||
if (_currentSequence != null)
|
||||
|
@ -7,8 +7,8 @@ public class EnemyStateFlee :IEnemyState
|
||||
{
|
||||
private EnemyController _enemyController;
|
||||
private Transform _playerTransform;
|
||||
private float _fleeDistance = 5f; // 도망치는 거리
|
||||
private float _safeRange = 7f; // 공격 범위
|
||||
private float _fleeDistance = 10f; // 도망치는 거리
|
||||
private float _attackRange = 7f; // 공격 범위
|
||||
|
||||
// 경로 탐색 주기 조절용
|
||||
private float _fleeSearchTimer = 0;
|
||||
@ -48,7 +48,7 @@ public class EnemyStateFlee :IEnemyState
|
||||
_enemyController.transform.position,
|
||||
_playerTransform.position
|
||||
);
|
||||
if (currentDist >= _safeRange)
|
||||
if (currentDist >= _attackRange)
|
||||
{
|
||||
// 목적지 리셋 후 전투 시작
|
||||
_enemyController.Agent.isStopped = true;
|
||||
|
Loading…
x
Reference in New Issue
Block a user