Animation fixes Demon
This commit is contained in:
@@ -1,12 +1,13 @@
|
||||
using Invector.vCharacterController.AI.FSMBehaviour;
|
||||
using Lean.Pool;
|
||||
using UnityEngine;
|
||||
using UnityEngine.Animations;
|
||||
using UnityEngine.Playables;
|
||||
|
||||
namespace DemonBoss.Magic
|
||||
{
|
||||
/// <summary>
|
||||
/// Spawns a meteor behind the BOSS and launches it toward the player's position
|
||||
/// Similar mechanics to FireballProjectile but coming from above
|
||||
/// Spawns a meteor behind the BOSS and launches it toward the player's position.
|
||||
/// </summary>
|
||||
[CreateAssetMenu(menuName = "Invector/FSM/Actions/DemonBoss/Call Meteor")]
|
||||
public class SA_CallMeteor : vStateAction
|
||||
@@ -31,18 +32,37 @@ namespace DemonBoss.Magic
|
||||
[Tooltip("Tag used to find the target (usually Player)")]
|
||||
public string targetTag = "Player";
|
||||
|
||||
[Header("One-off Overlay Clip (No Animator Params)")]
|
||||
public AnimationClip overlayClip;
|
||||
|
||||
[Tooltip("Playback speed (1 = normal)")] public float overlaySpeed = 1f;
|
||||
[Tooltip("Blend-in seconds (instant in this minimal impl)")] public float overlayFadeIn = 0.10f;
|
||||
[Tooltip("Blend-out seconds (instant in this minimal impl)")] public float overlayFadeOut = 0.10f;
|
||||
|
||||
[Header("Debug")]
|
||||
public bool enableDebug = false;
|
||||
|
||||
private Transform _boss;
|
||||
private Transform _target;
|
||||
|
||||
// --- Playables runtime ---
|
||||
private PlayableGraph _overlayGraph;
|
||||
|
||||
private AnimationPlayableOutput _overlayOutput;
|
||||
private AnimationClipPlayable _overlayPlayable;
|
||||
private bool _overlayPlaying;
|
||||
private float _overlayStopAtTime;
|
||||
|
||||
public override void DoAction(vIFSMBehaviourController fsm, vFSMComponentExecutionType execType = vFSMComponentExecutionType.OnStateUpdate)
|
||||
{
|
||||
if (execType == vFSMComponentExecutionType.OnStateEnter)
|
||||
{
|
||||
OnEnter(fsm);
|
||||
}
|
||||
else if (execType == vFSMComponentExecutionType.OnStateUpdate)
|
||||
{
|
||||
if (_overlayPlaying && Time.time >= _overlayStopAtTime) StopOverlayWithFade();
|
||||
}
|
||||
}
|
||||
|
||||
private void OnEnter(vIFSMBehaviourController fsm)
|
||||
@@ -58,7 +78,14 @@ namespace DemonBoss.Magic
|
||||
|
||||
if (enableDebug) Debug.Log($"[SA_CallMeteor] Boss: {_boss.name}, Target: {_target.name}");
|
||||
|
||||
SpawnMeteor();
|
||||
// Fire overlay clip (no Animator params)
|
||||
PlayOverlayOnce(_boss);
|
||||
|
||||
// Optional: wait for castDelay before spawning (simple timer via Invoke)
|
||||
if (castDelay > 0f)
|
||||
_boss.gameObject.AddComponent<DelayedInvoker>().Init(castDelay, SpawnMeteor);
|
||||
else
|
||||
SpawnMeteor();
|
||||
}
|
||||
|
||||
private void SpawnMeteor()
|
||||
@@ -101,5 +128,79 @@ namespace DemonBoss.Magic
|
||||
if (enableDebug) Debug.LogError("[SA_CallMeteor] Meteor prefab missing MeteorProjectile component!");
|
||||
}
|
||||
}
|
||||
|
||||
// -------- Playables helpers (no Animator params) --------
|
||||
private void PlayOverlayOnce(Transform owner)
|
||||
{
|
||||
if (overlayClip == null) return;
|
||||
|
||||
var animator = owner.GetComponent<Animator>();
|
||||
if (animator == null) return;
|
||||
|
||||
StopOverlayImmediate();
|
||||
|
||||
_overlayGraph = PlayableGraph.Create("ActionOverlay(CallMeteor)");
|
||||
_overlayGraph.SetTimeUpdateMode(DirectorUpdateMode.GameTime);
|
||||
|
||||
_overlayPlayable = AnimationClipPlayable.Create(_overlayGraph, overlayClip);
|
||||
_overlayPlayable.SetApplyFootIK(false);
|
||||
_overlayPlayable.SetApplyPlayableIK(false);
|
||||
_overlayPlayable.SetSpeed(Mathf.Max(0.0001f, overlaySpeed));
|
||||
|
||||
_overlayOutput = AnimationPlayableOutput.Create(_overlayGraph, "AnimOut", animator);
|
||||
_overlayOutput.SetSourcePlayable(_overlayPlayable);
|
||||
|
||||
_overlayOutput.SetWeight(1f);
|
||||
_overlayGraph.Play();
|
||||
_overlayPlaying = true;
|
||||
|
||||
float len = overlayClip.length / Mathf.Max(0.0001f, overlaySpeed);
|
||||
_overlayStopAtTime = Time.time + len;
|
||||
|
||||
if (enableDebug) Debug.Log("[SA_CallMeteor] Overlay clip started via Playables");
|
||||
}
|
||||
|
||||
private void StopOverlayImmediate()
|
||||
{
|
||||
if (_overlayGraph.IsValid())
|
||||
{
|
||||
_overlayGraph.Stop();
|
||||
_overlayGraph.Destroy();
|
||||
}
|
||||
_overlayPlaying = false;
|
||||
}
|
||||
|
||||
private void StopOverlayWithFade()
|
||||
{
|
||||
if (!_overlayPlaying) { StopOverlayImmediate(); return; }
|
||||
if (_overlayOutput.IsOutputNull() == false) _overlayOutput.SetWeight(0f);
|
||||
StopOverlayImmediate();
|
||||
if (enableDebug) Debug.Log("[SA_CallMeteor] Overlay clip stopped");
|
||||
}
|
||||
|
||||
/// <summary>
|
||||
/// Tiny helper MonoBehaviour to delay a callback without coroutines here.
|
||||
/// </summary>
|
||||
private sealed class DelayedInvoker : MonoBehaviour
|
||||
{
|
||||
private float _timeLeft;
|
||||
private System.Action _callback;
|
||||
|
||||
public void Init(float delay, System.Action callback)
|
||||
{
|
||||
_timeLeft = delay;
|
||||
_callback = callback;
|
||||
}
|
||||
|
||||
private void Update()
|
||||
{
|
||||
_timeLeft -= Time.deltaTime;
|
||||
if (_timeLeft <= 0f)
|
||||
{
|
||||
try { _callback?.Invoke(); }
|
||||
finally { Destroy(this); }
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
Reference in New Issue
Block a user