Make combine animations and smacks ground Pulve

This commit is contained in:
Michal Pikulski
2025-10-27 14:43:24 +01:00
parent f5c1ae51cd
commit fdfddaec95
13 changed files with 788 additions and 70 deletions

View 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();
}
}
}
}

View File

@@ -0,0 +1,3 @@
fileFormatVersion: 2
guid: 39f2e64420884f11a9022fea7b3be5d0
timeCreated: 1761571513

View File

@@ -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;
}