232 lines
7.0 KiB
C#
232 lines
7.0 KiB
C#
![]() |
// PlatformSpinController.cs
|
||
|
using System.Collections;
|
||
|
using System.Collections.Generic;
|
||
|
using UnityEngine;
|
||
|
using DG.Tweening;
|
||
|
|
||
|
/// <summary>
|
||
|
/// Controls a DOTweenAnimation-based spinning platform via per-tween timeScale.
|
||
|
/// - Keep your existing DOTweenAnimation component (like in your screenshot):
|
||
|
/// * Target: this GameObject
|
||
|
/// * Type: LocalRotate
|
||
|
/// * Duration: e.g., 20
|
||
|
/// * Ease: Linear
|
||
|
/// * Loops: -1 (Incremental)
|
||
|
/// * RotationMode: FastBeyond360
|
||
|
/// * (SpeedBased on/off is fine; we use timeScale)
|
||
|
///
|
||
|
/// Call ApplyTurbo/ApplySlow/ApplyFreeze to change spin temporarily.
|
||
|
/// Works with stacked effects (e.g., Turbo + Slow overlapping).
|
||
|
/// </summary>
|
||
|
[RequireComponent(typeof(DOTweenAnimation))]
|
||
|
public class PlatformSpinController : MonoBehaviour
|
||
|
{
|
||
|
[Header("Base Spin")]
|
||
|
[Tooltip("Base timeScale for the spin tween (1 = authoring speed).")]
|
||
|
public float baseTimeScale = 1f;
|
||
|
|
||
|
[Header("Effect Multipliers")]
|
||
|
[Tooltip("Multiplier applied during Turbo (e.g., 1.75 makes it ~75% faster).")]
|
||
|
public float turboMultiplier = 1.75f;
|
||
|
[Tooltip("Multiplier applied during Slow (e.g., 0.5 makes it half speed).")]
|
||
|
public float slowMultiplier = 0.5f;
|
||
|
|
||
|
private DOTweenAnimation spinAnim;
|
||
|
private Tween spinTween;
|
||
|
|
||
|
// Active scalar modifiers (we multiply them together with baseTimeScale)
|
||
|
private readonly List<float> activeScalars = new List<float>();
|
||
|
|
||
|
// Freeze nesting counter (supports stacked freezes)
|
||
|
private int freezeCount = 0;
|
||
|
[Header("Time Frenzy")]
|
||
|
public bool frenzyEnabled = false;
|
||
|
public float frenzyInterval = 15f; // seconds
|
||
|
public float frenzyStep = 1.15f; // +15% each step
|
||
|
|
||
|
private float permanentScalar = 1f;
|
||
|
private Coroutine frenzyCo;
|
||
|
|
||
|
void Awake()
|
||
|
{
|
||
|
spinAnim = GetComponent<DOTweenAnimation>();
|
||
|
}
|
||
|
|
||
|
void Start()
|
||
|
{
|
||
|
EnsureTween();
|
||
|
ApplyEffectiveTimeScale(); // set initial scale
|
||
|
}
|
||
|
|
||
|
void OnEnable()
|
||
|
{
|
||
|
EnsureTween();
|
||
|
// If we were paused due to disable, resume
|
||
|
if (spinTween != null && !spinTween.IsPlaying() && freezeCount == 0)
|
||
|
spinTween.Play();
|
||
|
}
|
||
|
public void ApplyReverse(float duration)
|
||
|
{
|
||
|
Debug.Log("ApplyReverse");
|
||
|
|
||
|
if (spinTween == null || !spinTween.IsActive()) return;
|
||
|
StartCoroutine(ReverseRoutine(duration));
|
||
|
}
|
||
|
private IEnumerator ReverseRoutine(float duration)
|
||
|
{
|
||
|
// Play backwards for 'duration', then forward again
|
||
|
float prevScale = spinTween.timeScale;
|
||
|
// keep current speed but reverse direction by playing backwards
|
||
|
spinTween.timeScale = Mathf.Abs(prevScale); // ensure positive scale
|
||
|
spinTween.PlayBackwards();
|
||
|
yield return new WaitForSeconds(duration);
|
||
|
spinTween.PlayForward();
|
||
|
spinTween.timeScale = prevScale;
|
||
|
}
|
||
|
public void StartFrenzy()
|
||
|
{
|
||
|
Debug.Log("StartFrenzy");
|
||
|
if (frenzyCo != null) StopCoroutine(frenzyCo);
|
||
|
frenzyEnabled = true;
|
||
|
frenzyCo = StartCoroutine(FrenzyLoop());
|
||
|
}
|
||
|
public void StopFrenzy()
|
||
|
{
|
||
|
frenzyEnabled = false;
|
||
|
if (frenzyCo != null) StopCoroutine(frenzyCo);
|
||
|
frenzyCo = null;
|
||
|
}
|
||
|
|
||
|
private IEnumerator FrenzyLoop()
|
||
|
{
|
||
|
while (frenzyEnabled)
|
||
|
{
|
||
|
yield return new WaitForSeconds(frenzyInterval);
|
||
|
permanentScalar *= frenzyStep; // accumulate permanently during the round
|
||
|
ApplyEffectiveTimeScale();
|
||
|
}
|
||
|
}
|
||
|
|
||
|
void OnDisable()
|
||
|
{
|
||
|
// leave DOTween to manage tween lifecycle; no hard kill here
|
||
|
}
|
||
|
|
||
|
/// <summary>
|
||
|
/// Temporarily increases spin speed for 'duration' seconds.
|
||
|
/// </summary>
|
||
|
public void ApplyTurbo(float duration)
|
||
|
{
|
||
|
Debug.Log("ApplyTurbo");
|
||
|
if (duration <= 0f) return;
|
||
|
StartCoroutine(ApplyScalarForDuration(turboMultiplier, duration));
|
||
|
}
|
||
|
|
||
|
/// <summary>
|
||
|
/// Temporarily slows spin for 'duration' seconds.
|
||
|
/// </summary>
|
||
|
public void ApplySlow(float duration)
|
||
|
{
|
||
|
Debug.Log("ApplySlow");
|
||
|
if (duration <= 0f) return;
|
||
|
StartCoroutine(ApplyScalarForDuration(slowMultiplier, duration));
|
||
|
}
|
||
|
|
||
|
/// <summary>
|
||
|
/// Fully freezes spin (pauses tween) for 'duration' seconds.
|
||
|
/// Supports stacking (nested freezes).
|
||
|
/// </summary>
|
||
|
public void ApplyFreeze(float duration)
|
||
|
{
|
||
|
Debug.Log("ApplyFreeze");
|
||
|
if (duration <= 0f) return;
|
||
|
StartCoroutine(FreezeRoutine(duration));
|
||
|
}
|
||
|
|
||
|
// ---------- Internals ----------
|
||
|
|
||
|
private void EnsureTween()
|
||
|
{
|
||
|
if (spinAnim == null) spinAnim = GetComponent<DOTweenAnimation>();
|
||
|
|
||
|
// Ensure the DOTweenAnimation has created its tween
|
||
|
// If your DOTweenAnimation is set to AutoPlay, it will have created the tween by now.
|
||
|
// If not, we force it to play to get the tween instance.
|
||
|
if (spinAnim != null)
|
||
|
{
|
||
|
// Try to fetch the tween reference the component manages
|
||
|
spinTween = spinAnim.tween;
|
||
|
|
||
|
if (spinTween == null || !spinTween.active)
|
||
|
{
|
||
|
// Kick it so it creates the tween and starts it
|
||
|
spinAnim.DORestart();
|
||
|
spinTween = spinAnim.tween;
|
||
|
}
|
||
|
}
|
||
|
|
||
|
if (spinTween == null)
|
||
|
{
|
||
|
Debug.LogWarning("[PlatformSpinController] Could not find/create tween on DOTweenAnimation.");
|
||
|
}
|
||
|
}
|
||
|
|
||
|
private IEnumerator ApplyScalarForDuration(float scalar, float duration)
|
||
|
{
|
||
|
activeScalars.Add(scalar);
|
||
|
ApplyEffectiveTimeScale();
|
||
|
|
||
|
yield return new WaitForSeconds(duration);
|
||
|
|
||
|
// Remove one instance of this scalar (handles overlapping same-effect)
|
||
|
int idx = activeScalars.IndexOf(scalar);
|
||
|
if (idx >= 0) activeScalars.RemoveAt(idx);
|
||
|
|
||
|
ApplyEffectiveTimeScale();
|
||
|
}
|
||
|
|
||
|
private IEnumerator FreezeRoutine(float duration)
|
||
|
{
|
||
|
freezeCount++;
|
||
|
PauseTween();
|
||
|
|
||
|
yield return new WaitForSeconds(duration);
|
||
|
|
||
|
freezeCount = Mathf.Max(0, freezeCount - 1);
|
||
|
if (freezeCount == 0) ResumeTween();
|
||
|
}
|
||
|
|
||
|
private void PauseTween()
|
||
|
{
|
||
|
Debug.Log("PauseTween");
|
||
|
if (spinTween != null && spinTween.IsActive()) spinTween.Pause();
|
||
|
}
|
||
|
|
||
|
private void ResumeTween()
|
||
|
{
|
||
|
Debug.Log("ResumeTween");
|
||
|
if (spinTween == null || !spinTween.IsActive()) return;
|
||
|
ApplyEffectiveTimeScale(); // ensure correct scale on resume
|
||
|
spinTween.Play();
|
||
|
}
|
||
|
[ContextMenu("ApplyEffectiveTimeScale")]
|
||
|
private void ApplyEffectiveTimeScale()
|
||
|
{
|
||
|
if (spinTween == null || !spinTween.IsActive()) return;
|
||
|
|
||
|
// Multiply all active scalars on top of baseTimeScale
|
||
|
float scale = baseTimeScale * permanentScalar;
|
||
|
for (int i = 0; i < activeScalars.Count; i++) scale *= activeScalars[i];
|
||
|
|
||
|
|
||
|
// Clamp to avoid zero/negative timeScale issues
|
||
|
scale = Mathf.Max(0.01f, scale);
|
||
|
|
||
|
spinTween.timeScale = scale;
|
||
|
|
||
|
// If frozen, keep paused even after timescale change
|
||
|
if (freezeCount > 0 && spinTween.IsPlaying())
|
||
|
spinTween.Pause();
|
||
|
}
|
||
|
}
|