Make combine animations and smacks ground Pulve
This commit is contained in:
40
Assets/Scripts/Movement/FollowerAnimationEventBridge.cs
Normal file
40
Assets/Scripts/Movement/FollowerAnimationEventBridge.cs
Normal file
@@ -0,0 +1,40 @@
|
||||
using UnityEngine;
|
||||
|
||||
namespace Movement
|
||||
{
|
||||
/// <summary>
|
||||
/// Bridge script that forwards Animation Events from the character art child object
|
||||
/// to the FollowerController on the parent GameObject.
|
||||
/// Attach this to the same GameObject that has the Animator component.
|
||||
/// </summary>
|
||||
public class FollowerAnimationEventBridge : MonoBehaviour
|
||||
{
|
||||
[SerializeField] private FollowerController followerController;
|
||||
|
||||
void Awake()
|
||||
{
|
||||
// Find the FollowerController on the parent
|
||||
if (followerController == null)
|
||||
{
|
||||
followerController = GetComponentInParent<FollowerController>();
|
||||
}
|
||||
|
||||
if (followerController == null)
|
||||
{
|
||||
Debug.LogError("[FollowerAnimationEventBridge] Could not find FollowerController in parent. This script must be on a child of the FollowerController.");
|
||||
}
|
||||
}
|
||||
|
||||
/// <summary>
|
||||
/// Called by Animation Events. Forwards to the parent FollowerController.
|
||||
/// </summary>
|
||||
public void OnStationaryAnimationComplete()
|
||||
{
|
||||
if (followerController != null)
|
||||
{
|
||||
followerController.OnStationaryAnimationComplete();
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
@@ -0,0 +1,3 @@
|
||||
fileFormatVersion: 2
|
||||
guid: 39f2e64420884f11a9022fea7b3be5d0
|
||||
timeCreated: 1761571513
|
||||
@@ -11,6 +11,8 @@ using Core;
|
||||
/// </summary>
|
||||
public class FollowerController: MonoBehaviour
|
||||
{
|
||||
private static readonly int CombineTrigger = Animator.StringToHash("Combine");
|
||||
|
||||
[Header("Follower Settings")]
|
||||
public bool debugDrawTarget = true;
|
||||
/// <summary>
|
||||
@@ -52,6 +54,11 @@ public class FollowerController: MonoBehaviour
|
||||
/// </summary>
|
||||
public SpriteRenderer heldObjectRenderer;
|
||||
|
||||
// Stationary animation state
|
||||
private bool _isPlayingStationaryAnimation = false;
|
||||
private Coroutine _stationaryAnimationCoroutine;
|
||||
private System.Action _stationaryAnimationCallback;
|
||||
|
||||
private bool _isReturningToPlayer = false;
|
||||
private float _playerMaxSpeed = 5f;
|
||||
private float _followerMaxSpeed = 6f;
|
||||
@@ -117,6 +124,19 @@ public class FollowerController: MonoBehaviour
|
||||
return;
|
||||
}
|
||||
|
||||
// Skip all movement logic when playing a stationary animation
|
||||
if (_isPlayingStationaryAnimation)
|
||||
{
|
||||
// Still update animator with zero speed to maintain idle state
|
||||
if (_animator != null)
|
||||
{
|
||||
_animator.SetFloat("Speed", 0f);
|
||||
_animator.SetFloat("DirX", _lastDirX);
|
||||
_animator.SetFloat("DirY", _lastDirY);
|
||||
}
|
||||
return;
|
||||
}
|
||||
|
||||
_timer += Time.deltaTime;
|
||||
if (_timer >= _settings.FollowUpdateInterval)
|
||||
{
|
||||
@@ -420,6 +440,100 @@ public class FollowerController: MonoBehaviour
|
||||
}
|
||||
#endregion Movement
|
||||
|
||||
#region StationaryAnimations
|
||||
/// <summary>
|
||||
/// Pauses all movement. Can be called directly from Timeline, Animation Events, or code.
|
||||
/// Call ResumeMovement() to resume.
|
||||
/// </summary>
|
||||
public void PauseMovement()
|
||||
{
|
||||
_isPlayingStationaryAnimation = true;
|
||||
_currentSpeed = 0f;
|
||||
Logging.Debug("[FollowerController] Movement paused");
|
||||
}
|
||||
|
||||
/// <summary>
|
||||
/// Resumes movement after being paused. Can be called from Timeline, Animation Events, or code.
|
||||
/// </summary>
|
||||
public void ResumeMovement()
|
||||
{
|
||||
_isPlayingStationaryAnimation = false;
|
||||
Logging.Debug("[FollowerController] Movement resumed");
|
||||
}
|
||||
|
||||
/// <summary>
|
||||
/// Plays an animation while pausing all movement. Resumes movement when animation completes.
|
||||
/// Uses a hybrid approach: Animation Events (if set up) OR timeout fallback (if not).
|
||||
/// To use Animation Events: Add an event at the end of your animation that calls OnStationaryAnimationComplete().
|
||||
/// </summary>
|
||||
/// <param name="triggerName">The animator trigger name to activate</param>
|
||||
/// <param name="maxDuration">Maximum time to wait before auto-resuming (fallback if no Animation Event)</param>
|
||||
/// <param name="onComplete">Optional callback to invoke when animation completes</param>
|
||||
public void PlayAnimationStationary(string triggerName, float maxDuration = 2f, System.Action onComplete = null)
|
||||
{
|
||||
if (_animator == null)
|
||||
{
|
||||
Logging.Warning("[FollowerController] Cannot play stationary animation - no Animator found");
|
||||
onComplete?.Invoke();
|
||||
return;
|
||||
}
|
||||
|
||||
// Stop any existing stationary animation
|
||||
if (_stationaryAnimationCoroutine != null)
|
||||
{
|
||||
StopCoroutine(_stationaryAnimationCoroutine);
|
||||
}
|
||||
|
||||
_isPlayingStationaryAnimation = true;
|
||||
_stationaryAnimationCallback = onComplete;
|
||||
_currentSpeed = 0f; // Immediately stop movement
|
||||
|
||||
// Trigger the animation
|
||||
_animator.SetTrigger(triggerName);
|
||||
|
||||
// Start timeout coroutine (will be stopped early if Animation Event fires)
|
||||
_stationaryAnimationCoroutine = StartCoroutine(StationaryAnimationTimeoutCoroutine(maxDuration));
|
||||
}
|
||||
|
||||
private System.Collections.IEnumerator StationaryAnimationTimeoutCoroutine(float maxDuration)
|
||||
{
|
||||
yield return new WaitForSeconds(maxDuration);
|
||||
|
||||
// If we reach here, the Animation Event didn't fire - use fallback
|
||||
Logging.Debug($"[FollowerController] Stationary animation timeout reached ({maxDuration}s) - resuming movement");
|
||||
ResumeMovementAfterAnimation();
|
||||
}
|
||||
|
||||
/// <summary>
|
||||
/// Public method to be called by Animation Events at the end of stationary animations.
|
||||
/// Add this as an Animation Event in your animation clip for frame-perfect timing.
|
||||
/// </summary>
|
||||
public void OnStationaryAnimationComplete()
|
||||
{
|
||||
Logging.Debug("[FollowerController] Stationary animation completed via Animation Event");
|
||||
ResumeMovementAfterAnimation();
|
||||
}
|
||||
|
||||
private void ResumeMovementAfterAnimation()
|
||||
{
|
||||
if (!_isPlayingStationaryAnimation) return; // Already resumed
|
||||
|
||||
// Stop the timeout coroutine if it's still running
|
||||
if (_stationaryAnimationCoroutine != null)
|
||||
{
|
||||
StopCoroutine(_stationaryAnimationCoroutine);
|
||||
_stationaryAnimationCoroutine = null;
|
||||
}
|
||||
|
||||
_isPlayingStationaryAnimation = false;
|
||||
|
||||
// Invoke callback if provided
|
||||
var callback = _stationaryAnimationCallback;
|
||||
_stationaryAnimationCallback = null;
|
||||
callback?.Invoke();
|
||||
}
|
||||
#endregion StationaryAnimations
|
||||
|
||||
#region ItemInteractions
|
||||
public void TryPickupItem(GameObject itemObject, PickupItemData itemData, bool dropItem = true)
|
||||
{
|
||||
@@ -445,7 +559,7 @@ public class FollowerController: MonoBehaviour
|
||||
|
||||
public CombinationResult TryCombineItems(Pickup pickupA, out GameObject newItem)
|
||||
{
|
||||
_animator.ResetTrigger("Combine");
|
||||
_animator.ResetTrigger(CombineTrigger);
|
||||
newItem = null;
|
||||
if (_cachedPickupObject == null)
|
||||
{
|
||||
@@ -468,7 +582,7 @@ public class FollowerController: MonoBehaviour
|
||||
Destroy(pickupA.gameObject);
|
||||
Destroy(pickupB.gameObject);
|
||||
TryPickupItem(newItem, itemData);
|
||||
_animator.SetTrigger("Combine");
|
||||
PlayAnimationStationary("Combine", 10.0f);
|
||||
return CombinationResult.Successful;
|
||||
}
|
||||
|
||||
|
||||
Reference in New Issue
Block a user