Skip to content

Instantly share code, notes, and snippets.

@Donnotron666
Created October 29, 2023 18:29
Show Gist options
  • Save Donnotron666/d02d2b5392833c048faaf5ef87348bee to your computer and use it in GitHub Desktop.
Save Donnotron666/d02d2b5392833c048faaf5ef87348bee to your computer and use it in GitHub Desktop.
Shake Controller
using Core.Utils;
using System;
using System.Collections.Generic;
using UnityEngine;
namespace Core.Movement
{
public class ShakeController
{
private List<Shake> ActiveShakes = new List<Shake>();
public bool Empty => ActiveShakes.Count == 0;
private float Accum = 0f;
public float ReadSpeed {
get {
return Tuning.CameraShakeReadSpeed;
}
}
public PrototypeTuning Tuning {
get {
return PrototypeTuning.Instance;
}
}
public void Add(float transAmt, float rotAmt, float maxDistance = .5f)
{
Add(new Shake(transAmt, rotAmt, 2f, maxDistance));
}
public void Add(Shake shake)
{
ActiveShakes.Add(shake);
}
float RotationAccum;
public Vector3 TransAccum = Vector3.zero;
Queue<Shake> RemoveBuffer = new Queue<Shake>();
public void Update(float dt)
{
Accum += dt;
foreach( var shake in ActiveShakes)
{
shake.Consume(dt, Accum, out float thisRot, out Vector3 thisTrans);
RotationAccum += thisRot;
TransAccum += thisTrans;
if (shake.IsComplete)
{
RemoveBuffer.Enqueue(shake);
}
}
while( RemoveBuffer.Count > 0)
{
ActiveShakes.Remove(RemoveBuffer.Dequeue());
}
}
public void Reset()
{
ClearBuffer();
ClearShakes();
}
private Vector3 LastApplied = Vector3.zero;
public void ClearBuffer()
{
RotationAccum = 0f;
LastApplied = TransAccum;
TransAccum = Vector3.zero;
}
public void ClearShakes()
{
ActiveShakes.Clear();
}
public Vector3 FlushToBuffer(Vector3 buffer)
{
var aux = TransAccum;
var ret = buffer + aux;// - LastApplied;
ClearBuffer();
return ret;
}
public void FlushShakeToTransform(Transform tfm, float dt) => FlushShakeToTransform(tfm, dt, Quaternion.identity);
public void FlushShakeToTransform(Transform tfm, float dt, Quaternion restingRotation)
{
//Application and recovery
if (RotationAccum != 0)
{
tfm.localRotation = restingRotation * Quaternion.AngleAxis(RotationAccum, Vector3.forward);
}
else
{
tfm.localRotation = Quaternion.SlerpUnclamped(tfm.localRotation, restingRotation, dt * Tuning.ShakeReturnSpeed);
}
tfm.localPosition = tfm.localPosition + TransAccum;//(tfm.localPosition + (TransAccum - LastApplied));
ClearBuffer();
}
}
[Serializable]
public class Shake
{
public float TransIntensity;
public float RotIntensity;
public float Duration;
public float MaxAngle = 5f;
//[HideInInspector]
public float Speed = 30f;
[HideInInspector]
public float Scalar = 1f;
[HideInInspector]
public float Accum = 0f;
[HideInInspector]
public float seedAccum = 0f;
public float MaxDistance = .5f;
public Shake()
{
Scalar = 1f;
Speed = 30f;
}
public Shake(float amt, float rotAmt, float duration, float maxDistance)
{
this.TransIntensity = amt;
this.RotIntensity = rotAmt;
this.Duration = duration;
this.MaxDistance = maxDistance;
}
public Shake(float amt, float rotAmt, float duration, float speed, float maxDistance)
{
this.TransIntensity = amt;
this.RotIntensity = rotAmt;
this.Duration = duration;
this.Speed = speed;
this.MaxDistance = maxDistance;
}
public Shake Clone() => new Shake(TransIntensity, RotIntensity, Duration, MaxDistance);
protected PrototypeTuning Tuning {
get {
return PrototypeTuning.Instance;
}
}
public float RandomFloat(float seed)
{
var alpha = Mathf.PerlinNoise(seed, seedAccum);
return Mathf.Lerp(-1f, 1f, alpha);
}
public virtual void Consume(float dt, float seedOffset, out float rotation, out Vector3 trans)
{
Accum += dt;
if (RotIntensity > 0)
{
seedAccum += dt * Mathf.Pow(RotIntensity, Tuning.ShakeFrequencyDecay) * this.Speed;
var angle = MaxAngle * RandomFloat(seedOffset + Tuning.ShakeRotSeed);
RotIntensity = (RotIntensity - Mathf.Clamp01(dt * Tuning.ShakeIntensityDecay * (RotIntensity + Tuning.ShakeDurationDecay))) * Scalar;
rotation = angle;
} else
{
rotation = 0f;
}
if (TransIntensity > 0)
{
var accumScalar = Mathf.Pow(TransIntensity, Tuning.ShakeFrequencyDecay) * this.Speed;
seedAccum += dt * accumScalar;
var x = TransIntensity * MaxDistance * RandomFloat(seedOffset + Tuning.ShakeTransSeedX);
var y = TransIntensity * MaxDistance * RandomFloat(seedOffset + Tuning.ShakeTransSeedY);
trans = new Vector3(x, y);
TransIntensity = Mathf.Clamp01(TransIntensity - (dt * Tuning.ShakeIntensityDecay * (TransIntensity + Tuning.ShakeDurationDecay))) * Scalar;
} else
{
trans = Vector3.zero;
}
}
public bool IsComplete => Accum >= Duration;
public void Kill()
{
this.Duration = 0f;
}
public Shake Scale(float alpha)
{
this.Scalar = alpha;
return this;
}
}
[Serializable]
public class ConstantShake : Shake
{
public ConstantShake()
{
Scalar = 1f;
Speed = 30f;
}
new public ConstantShake Clone() => new ConstantShake(this);
public ConstantShake(Shake other) : this(other.TransIntensity, other.RotIntensity, other.Duration, other.Speed, other.MaxDistance)
{
}
public ConstantShake(float amt, float rotAmt, float duration, float maxDistance) : base(amt, rotAmt, duration, maxDistance)
{
}
public ConstantShake(float amt, float rotAmt, float duration, float shakeSpeed, float maxDistance) : base(amt, rotAmt, duration, shakeSpeed, maxDistance)
{
}
public void Copy(Shake other)
{
this.TransIntensity = other.TransIntensity;
this.RotIntensity = other.RotIntensity;
this.Scalar = other.Scalar;
this.Duration = other.Duration;
this.Speed = other.Speed;
}
public override void Consume(float dt, float offset, out float rotation, out Vector3 trans)
{
this.Duration -= dt;
if (IsComplete)
{
trans = Vector3.zero;
rotation = 0f;
return;
}
if (RotIntensity > 0)
{
seedAccum += dt * Mathf.Pow(RotIntensity, Tuning.ShakeFrequencyDecay) * this.Speed;
var angle = this.MaxAngle * RandomFloat(offset + 100);
rotation = angle * Scalar;
}
else
{
rotation = 0f;
}
if (TransIntensity > 0)
{
var accumScalar = Mathf.Pow(TransIntensity, Tuning.ShakeFrequencyDecay) * this.Speed;
seedAccum += dt * accumScalar;
var x = MaxDistance * RandomFloat(offset + Tuning.ShakeTransSeedX) * Scalar;
var y = MaxDistance * RandomFloat(offset + Tuning.ShakeTransSeedY) * Scalar;
trans = new Vector3(x, y);
}
else
{
trans = Vector3.zero;
}
}
}
}
Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment