EerieVillage/Assets/Scripts/Skills/Effectors/StatusApplier.cs

87 lines
3.5 KiB
C#
Raw Normal View History

using UnityEngine;
using Platformer.Mechanics;
namespace EerieVillage.Skills.Effectors
{
/// <summary>
/// 상태 효과 일괄 적용기.
/// Projectile.OnTriggerEnter2D 등 타격 판정 후 ActiveSkillData 필드를 읽어
/// DoT·Stun·Slow·Knockback·DebuffStack 을 EnemyController 에 적용한다.
/// BT12-Dev Phase 2-B §4-5.
/// </summary>
public static class StatusApplier
{
public static void Apply(ActiveSkillData data, EnemyController enemy)
{
if (data == null || enemy == null) return;
// DoT (화염·독 등) — DotInterval > 0 영역만 발화 (DotDuration 영역 OnDotFxPrefab.ParticleSystem.main.duration 영역 자동 영역)
// BT12-Dev 2026-05-13 — damage = BaseDamage × DotDamageMultiplier (PD 영역: 25%) + OnDotFxPrefab 자식 spawn
if ((data.DotDuration > 0f || data.OnDotFxPrefab != null) && data.DotInterval > 0f)
{
int dotDamage = Mathf.Max(1, Mathf.RoundToInt(data.BaseDamage * data.DotDamageMultiplier));
feat(BT12-Dev): 스킬 시스템 누적 작업물 (PD 지시 2026-05-12~13) 본 세션 (BurningTimes worktree cranky-wescoff-e855b0) 누적 작업물. 직전 commit 4건 (2ebf313·60e28e3·ea7d32f·f6c6eb5) 영역 외 잔존 미커밋 변경 일괄 commit. Scripts: - Health.cs DecrementBypassInvuln (DoT) + DecrementBypassInvulnWithHit (다단 히트) + StartHitFlash + FlashHurtCoroutine + TriggerHitOrHurt - ActiveSkillData.cs 신규 필드 (DamageFrameDelay·EnableRepeatDamage· MaxHitCount·RepeatFrameInterval·OffsetDistance Vector2 등) - PiercingProjectile.cs A13 천둥발 관통 + Kinematic Rigidbody2D + useFullKinematicContacts + OverlapBox 매 frame - StatusApplier.cs ApplyDoT 시 DotFxScale 전달 - TestSkillFireOn1to5.cs 1~5 키 발사 + lazy init EnsureRuntimes Animator: - Enemy.controller Baddie-Hurt self-loop transition (hurt 조건) - Player.controller Player-Hit self-loop transition (hit 조건) Prefab: - FX_Lightningball.prefab ball 자식 PS simulationSpace World → Local - Enemy.prefab 본 세션 측정 조정 Active skill assets (PD Inspector 직접 조정): - A01·A02·A03·A04·A05·A08·A13·A14·A15·A_Laser HitboxSize·OffsetDistance(Vector2)·OffsetXY·FxRotation·HitFxScale· DamageFrameDelay·EnableRepeatDamage·MaxHitCount·RepeatFrameInterval Font: - NotoSansKR-Regular SDF.asset 본 세션 SDF atlas 갱신 → 박스↔이펙트 분리 원칙 표준화 (박스 = facing 만 · 이펙트 = facing + FxRotation · runtime spawn = HideFlags.DontSave) → 모든 피해 시 hit flash + Animator self-loop transition Co-Authored-By: Claude Opus 4.7 (1M context) <noreply@anthropic.com>
2026-05-13 09:05:13 +00:00
ApplyDoT(enemy, dotDamage, data.DotDuration, data.DotInterval, data.OnDotFxPrefab, data.DotFxScale);
}
// 기절 (스턴)
if (data.StunDuration > 0f)
{
ApplyStun(enemy, data.StunDuration);
}
// 감속 (슬로우)
if (data.SlowDuration > 0f && data.SlowMultiplier < 1.0f)
{
ApplySlow(enemy, data.SlowDuration, data.SlowMultiplier);
}
// 넉백
if (data.KnockbackForce > 0f)
{
ApplyKnockback(enemy, data.KnockbackForce);
}
// 저주 스택 (A08 저주의 화살)
if (data.DebuffStackLimit > 0)
{
DebuffStack.AddStack(enemy, data.DebuffStackLimit, data.BaseDamage);
}
}
// -------------------------------------------------------------------
// 내부 헬퍼
// -------------------------------------------------------------------
feat(BT12-Dev): 스킬 시스템 누적 작업물 (PD 지시 2026-05-12~13) 본 세션 (BurningTimes worktree cranky-wescoff-e855b0) 누적 작업물. 직전 commit 4건 (2ebf313·60e28e3·ea7d32f·f6c6eb5) 영역 외 잔존 미커밋 변경 일괄 commit. Scripts: - Health.cs DecrementBypassInvuln (DoT) + DecrementBypassInvulnWithHit (다단 히트) + StartHitFlash + FlashHurtCoroutine + TriggerHitOrHurt - ActiveSkillData.cs 신규 필드 (DamageFrameDelay·EnableRepeatDamage· MaxHitCount·RepeatFrameInterval·OffsetDistance Vector2 등) - PiercingProjectile.cs A13 천둥발 관통 + Kinematic Rigidbody2D + useFullKinematicContacts + OverlapBox 매 frame - StatusApplier.cs ApplyDoT 시 DotFxScale 전달 - TestSkillFireOn1to5.cs 1~5 키 발사 + lazy init EnsureRuntimes Animator: - Enemy.controller Baddie-Hurt self-loop transition (hurt 조건) - Player.controller Player-Hit self-loop transition (hit 조건) Prefab: - FX_Lightningball.prefab ball 자식 PS simulationSpace World → Local - Enemy.prefab 본 세션 측정 조정 Active skill assets (PD Inspector 직접 조정): - A01·A02·A03·A04·A05·A08·A13·A14·A15·A_Laser HitboxSize·OffsetDistance(Vector2)·OffsetXY·FxRotation·HitFxScale· DamageFrameDelay·EnableRepeatDamage·MaxHitCount·RepeatFrameInterval Font: - NotoSansKR-Regular SDF.asset 본 세션 SDF atlas 갱신 → 박스↔이펙트 분리 원칙 표준화 (박스 = facing 만 · 이펙트 = facing + FxRotation · runtime spawn = HideFlags.DontSave) → 모든 피해 시 hit flash + Animator self-loop transition Co-Authored-By: Claude Opus 4.7 (1M context) <noreply@anthropic.com>
2026-05-13 09:05:13 +00:00
private static void ApplyDoT(EnemyController enemy, int damagePerTick, float duration, float interval, GameObject fxPrefab = null, float fxScale = 1f)
{
var existing = enemy.GetComponent<EnemyDoTState>();
if (existing == null) existing = enemy.gameObject.AddComponent<EnemyDoTState>();
feat(BT12-Dev): 스킬 시스템 누적 작업물 (PD 지시 2026-05-12~13) 본 세션 (BurningTimes worktree cranky-wescoff-e855b0) 누적 작업물. 직전 commit 4건 (2ebf313·60e28e3·ea7d32f·f6c6eb5) 영역 외 잔존 미커밋 변경 일괄 commit. Scripts: - Health.cs DecrementBypassInvuln (DoT) + DecrementBypassInvulnWithHit (다단 히트) + StartHitFlash + FlashHurtCoroutine + TriggerHitOrHurt - ActiveSkillData.cs 신규 필드 (DamageFrameDelay·EnableRepeatDamage· MaxHitCount·RepeatFrameInterval·OffsetDistance Vector2 등) - PiercingProjectile.cs A13 천둥발 관통 + Kinematic Rigidbody2D + useFullKinematicContacts + OverlapBox 매 frame - StatusApplier.cs ApplyDoT 시 DotFxScale 전달 - TestSkillFireOn1to5.cs 1~5 키 발사 + lazy init EnsureRuntimes Animator: - Enemy.controller Baddie-Hurt self-loop transition (hurt 조건) - Player.controller Player-Hit self-loop transition (hit 조건) Prefab: - FX_Lightningball.prefab ball 자식 PS simulationSpace World → Local - Enemy.prefab 본 세션 측정 조정 Active skill assets (PD Inspector 직접 조정): - A01·A02·A03·A04·A05·A08·A13·A14·A15·A_Laser HitboxSize·OffsetDistance(Vector2)·OffsetXY·FxRotation·HitFxScale· DamageFrameDelay·EnableRepeatDamage·MaxHitCount·RepeatFrameInterval Font: - NotoSansKR-Regular SDF.asset 본 세션 SDF atlas 갱신 → 박스↔이펙트 분리 원칙 표준화 (박스 = facing 만 · 이펙트 = facing + FxRotation · runtime spawn = HideFlags.DontSave) → 모든 피해 시 hit flash + Animator self-loop transition Co-Authored-By: Claude Opus 4.7 (1M context) <noreply@anthropic.com>
2026-05-13 09:05:13 +00:00
existing.AddDoT(damagePerTick, duration, interval, fxPrefab, fxScale);
}
private static void ApplyStun(EnemyController enemy, float duration)
{
var existing = enemy.GetComponent<EnemyStunState>();
if (existing == null) existing = enemy.gameObject.AddComponent<EnemyStunState>();
existing.ApplyStun(duration);
}
private static void ApplySlow(EnemyController enemy, float duration, float multiplier)
{
var existing = enemy.GetComponent<EnemySlowState>();
if (existing == null) existing = enemy.gameObject.AddComponent<EnemySlowState>();
existing.ApplySlow(duration, multiplier);
}
private static void ApplyKnockback(EnemyController enemy, float force)
{
var rb = enemy.GetComponent<Rigidbody2D>();
if (rb != null)
{
// facing 반대 방향 넉백 — 단순 +x 방향 (Phase 2 범위, Phase 2-C에서 방향 정합 예정)
rb.AddForce(Vector2.right * force, ForceMode2D.Impulse);
}
}
}
}