feat(BT12-Dev): A11 정령불 frame 기반 playback 제어 (PD 지시 2026-05-13)
FX_Rotating shield.anim 측정 정합 (m_SampleRate 60·m_StopTime 2.8166666·총 169 frame).
PD 명시 영역 제어:
- intro: 1~88 frame (0~1.4667s)
- loop: 89~105 frame 반복 (17 frame·0.2833s)
- outro: 남은 frame (106~169 → 1.7500~2.8167s·1.0667s) — duration 종료 전 자동 재생
SpiritFireInstance.Init:
- Animator 캐싱·updateMode = UnscaledTime
- speed=1 (normalizedTime 직접 제어)
SpiritFireInstance.Update:
- elapsed < introEnd → linear sample
- elapsed < outroStart → loop range modulo
- elapsed >= outroStart → outro linear (duration - outroLength 영역)
- Animator.Play(STATE_HASH, 0, normalizedTime) 매 frame 호출
STATE_HASH = Animator.StringToHash("Base Layer.FX_Rotating shield")
Co-Authored-By: Claude Opus 4.7 (1M context) <noreply@anthropic.com>
This commit is contained in:
parent
b1b476a061
commit
ebd0808034
|
|
@ -48,10 +48,19 @@ namespace EerieVillage.Skills.Effectors
|
|||
|
||||
/// <summary>
|
||||
/// 정령불 인스턴스 — Player 자식 부착·duration 동안 OverlapCircle 영역 적 투사체 SelfDestruct·근접 적 매 초 5 피해.
|
||||
/// PD 지시 2026-05-13 — FX_Rotating shield Animator frame 제어 (60fps·intro 1~88·loop 89~105·outro 남은 frame).
|
||||
/// </summary>
|
||||
public class SpiritFireInstance : MonoBehaviour
|
||||
{
|
||||
// PD 지시 2026-05-13 — FX_Rotating shield.anim 정합 (m_SampleRate 60·m_StopTime 2.8166666 → 169 frame·2.8167s)
|
||||
const float FPS = 60f;
|
||||
const int INTRO_END_FRAME = 88;
|
||||
const int LOOP_END_FRAME = 105;
|
||||
const float CLIP_LENGTH = 2.8166666f;
|
||||
static readonly int STATE_HASH = Animator.StringToHash("Base Layer.FX_Rotating shield");
|
||||
|
||||
Transform _player;
|
||||
Animator _animator;
|
||||
float _spawnTime;
|
||||
float _duration;
|
||||
float _radius;
|
||||
|
|
@ -65,10 +74,48 @@ namespace EerieVillage.Skills.Effectors
|
|||
_radius = radius;
|
||||
_damage = damage;
|
||||
_spawnTime = Time.unscaledTime;
|
||||
|
||||
_animator = GetComponent<Animator>();
|
||||
if (_animator == null) _animator = GetComponentInChildren<Animator>();
|
||||
if (_animator != null)
|
||||
{
|
||||
_animator.updateMode = AnimatorUpdateMode.UnscaledTime;
|
||||
_animator.speed = 1f;
|
||||
}
|
||||
}
|
||||
|
||||
void Update()
|
||||
{
|
||||
// PD 지시 2026-05-13 — Animator frame 제어 (intro 0~88f·loop 88~105f·outro 105~clip_end)
|
||||
if (_animator != null)
|
||||
{
|
||||
float introEnd = INTRO_END_FRAME / FPS; // 1.4667s
|
||||
float loopEnd = LOOP_END_FRAME / FPS; // 1.75s
|
||||
float outroLength = Mathf.Max(0f, CLIP_LENGTH - loopEnd); // 1.0666s
|
||||
float outroStart = Mathf.Max(introEnd, _duration - outroLength);
|
||||
|
||||
float elapsed = Time.unscaledTime - _spawnTime;
|
||||
float targetTime;
|
||||
|
||||
if (elapsed < introEnd)
|
||||
{
|
||||
targetTime = elapsed;
|
||||
}
|
||||
else if (elapsed < outroStart)
|
||||
{
|
||||
float loopRange = Mathf.Max(0.01f, loopEnd - introEnd);
|
||||
float loopT = (elapsed - introEnd) % loopRange;
|
||||
targetTime = introEnd + loopT;
|
||||
}
|
||||
else
|
||||
{
|
||||
targetTime = loopEnd + (elapsed - outroStart);
|
||||
}
|
||||
|
||||
float normalized = Mathf.Clamp01(targetTime / CLIP_LENGTH);
|
||||
_animator.Play(STATE_HASH, 0, normalized);
|
||||
}
|
||||
|
||||
if (Time.unscaledTime - _spawnTime >= _duration)
|
||||
{
|
||||
Destroy(gameObject);
|
||||
|
|
|
|||
Loading…
Reference in New Issue