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

69 lines
2.9 KiB
C#
Raw Normal View History

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
using UnityEngine;
using Platformer.Mechanics;
namespace EerieVillage.Skills.Effectors
{
/// <summary>
/// PD 지시 2026-05-13 — Inspector 영역 ActiveSkillData 값 변경 시 살아있는 시각화 박스도 즉시 반영.
/// LateUpdate 매 frame data 정합 갱신: position·rotation·localScale.
/// </summary>
public class LiveHitboxSync : MonoBehaviour
{
public enum FollowMode
{
/// <summary>Anchor + (0, OffsetDistance) + OffsetXY · size=HitboxSize · rot=FxRotation (A05 MeleeArea)</summary>
AnchorYOffset,
/// <summary>Anchor (Enemy) + (0, OffsetDistance) + OffsetXY · size=HitboxSize · rot=FxRotation (A04 Lightning·primary 사망 시 마지막 위치 유지)</summary>
EnemyAnchoredAtStrike,
/// <summary>Anchor (Player) + facing × (OffsetDistance + length/2) + OffsetXY · size=(length, width) · rot=facing+FxRotation (A_Laser)</summary>
PlayerFacingLaser,
}
public ActiveSkillData Data;
public Transform Anchor;
public FollowMode Mode;
// PlayerFacingLaser 영역 영역 — Anchor (Player) 영역 PlayerController.Facing 영역 영역
public PlayerController PlayerCtrl;
// EnemyAnchoredAtStrike — Anchor (primary enemy) 사망 시 마지막 위치 캐싱
Vector2 _lastAnchorPos;
bool _hasLastPos;
void LateUpdate()
{
if (Data == null) return;
Vector2 anchorPos;
if (Anchor != null) { anchorPos = Anchor.position; _lastAnchorPos = anchorPos; _hasLastPos = true; }
else if (_hasLastPos) anchorPos = _lastAnchorPos;
else return;
Vector2 pos = anchorPos;
float angle = 0f;
Vector3 scale = transform.localScale;
switch (Mode)
{
case FollowMode.AnchorYOffset:
case FollowMode.EnemyAnchoredAtStrike:
pos += Data.OffsetDistance + Data.OffsetXY;
angle = Data.FxRotation;
scale = new Vector3(Data.HitboxSize.x, Data.HitboxSize.y, 1f);
break;
case FollowMode.PlayerFacingLaser:
Vector2 facing = (PlayerCtrl != null) ? PlayerCtrl.Facing : Vector2.right;
facing = facing.normalized;
float length = Mathf.Max(Data.HitboxSize.x, 1f);
float width = Mathf.Max(Data.HitboxSize.y, 0.5f);
pos += Data.OffsetDistance + Data.OffsetXY + facing * (length * 0.5f);
angle = Mathf.Atan2(facing.y, facing.x) * Mathf.Rad2Deg + Data.FxRotation;
scale = new Vector3(length, width, 1f);
break;
}
transform.position = pos;
transform.rotation = Quaternion.Euler(0f, 0f, angle);
transform.localScale = scale;
}
}
}