using System.Collections; using System.Collections.Generic; using UnityEngine; namespace MirzaBeig { namespace ParticleSystems { namespace Demos { public enum CameraShakeTarget { Position, Rotation } public enum CameraShakeAmplitudeCurve { Constant, // Fade in fully at 25%, 50%, and 75% of lifetime. FadeInOut25, FadeInOut50, FadeInOut75, } public enum CameraShakeAmplitudeOverDistanceCurve { Constant, LinearFadeIn, LinearFadeOut } public class CameraShake : MonoBehaviour { [System.Serializable] public class Shake { public float amplitude = 1.0f; public float frequency = 1.0f; public float duration; [HideInInspector] public CameraShakeTarget target; float timeRemaining; Vector2 perlinNoiseX; Vector2 perlinNoiseY; Vector2 perlinNoiseZ; [HideInInspector] public Vector3 noise; public AnimationCurve amplitudeOverLifetimeCurve = new AnimationCurve(new Keyframe(0.0f, 1.0f), new Keyframe(1.0f, 0.0f)); public void Init() { timeRemaining = duration; ApplyRandomSeed(); } void Init(float amplitude, float frequency, float duration, CameraShakeTarget target) { this.amplitude = amplitude; this.frequency = frequency; this.duration = duration; timeRemaining = duration; this.target = target; ApplyRandomSeed(); } public void ApplyRandomSeed() { float randomRange = 32.0f; perlinNoiseX.x = Random.Range(-randomRange, randomRange); perlinNoiseX.y = Random.Range(-randomRange, randomRange); perlinNoiseY.x = Random.Range(-randomRange, randomRange); perlinNoiseY.y = Random.Range(-randomRange, randomRange); perlinNoiseZ.x = Random.Range(-randomRange, randomRange); perlinNoiseZ.y = Random.Range(-randomRange, randomRange); } public Shake(float amplitude, float frequency, float duration, CameraShakeTarget target, AnimationCurve amplitudeOverLifetimeCurve) { Init(amplitude, frequency, duration, target); this.amplitudeOverLifetimeCurve = amplitudeOverLifetimeCurve; } public Shake(float amplitude, float frequency, float duration, CameraShakeTarget target, CameraShakeAmplitudeCurve amplitudeOverLifetimeCurve) { Init(amplitude, frequency, duration, target); switch (amplitudeOverLifetimeCurve) { case CameraShakeAmplitudeCurve.Constant: { this.amplitudeOverLifetimeCurve = AnimationCurve.Linear(0.0f, 1.0f, 1.0f, 1.0f); break; } case CameraShakeAmplitudeCurve.FadeInOut25: { this.amplitudeOverLifetimeCurve = new AnimationCurve(new Keyframe(0.0f, 0.0f), new Keyframe(0.25f, 1.0f), new Keyframe(1.0f, 0.0f)); break; } case CameraShakeAmplitudeCurve.FadeInOut50: { this.amplitudeOverLifetimeCurve = new AnimationCurve(new Keyframe(0.0f, 0.0f), new Keyframe(0.50f, 1.0f), new Keyframe(1.0f, 0.0f)); break; } case CameraShakeAmplitudeCurve.FadeInOut75: { this.amplitudeOverLifetimeCurve = new AnimationCurve(new Keyframe(0.0f, 0.0f), new Keyframe(0.75f, 1.0f), new Keyframe(1.0f, 0.0f)); break; } default: { throw new System.Exception("Unknown enum."); } } } public bool IsAlive() { return timeRemaining > 0.0f; } public void Update() { if (timeRemaining < 0.0f) { return; } Vector2 frequencyVector = Time.deltaTime * new Vector2(frequency, frequency); perlinNoiseX += frequencyVector; perlinNoiseY += frequencyVector; perlinNoiseZ += frequencyVector; noise.x = Mathf.PerlinNoise(perlinNoiseX.x, perlinNoiseX.y) - 0.5f; noise.y = Mathf.PerlinNoise(perlinNoiseY.x, perlinNoiseY.y) - 0.5f; noise.z = Mathf.PerlinNoise(perlinNoiseZ.x, perlinNoiseZ.y) - 0.5f; float amplitudeOverLifetime = amplitudeOverLifetimeCurve.Evaluate(1.0f - (timeRemaining / duration)); noise *= amplitude * amplitudeOverLifetime; timeRemaining -= Time.deltaTime; } } // ... public float smoothDampTime = 0.025f; Vector3 smoothDampPositionVelocity; float smoothDampRotationVelocityX; float smoothDampRotationVelocityY; float smoothDampRotationVelocityZ; List shakes = new List(); // ... void Start() { } // ... public void Add(float amplitude, float frequency, float duration, CameraShakeTarget target, AnimationCurve amplitudeOverLifetimeCurve) { shakes.Add(new Shake(amplitude, frequency, duration, target, amplitudeOverLifetimeCurve)); } public void Add(float amplitude, float frequency, float duration, CameraShakeTarget target, CameraShakeAmplitudeCurve amplitudeOverLifetimeCurve) { shakes.Add(new Shake(amplitude, frequency, duration, target, amplitudeOverLifetimeCurve)); } // ... void Update() { if (Input.GetKeyDown(KeyCode.F)) { Add(0.25f, 1.0f, 2.0f, CameraShakeTarget.Position, CameraShakeAmplitudeCurve.FadeInOut25); } if (Input.GetKeyDown(KeyCode.G)) { Add(15.0f, 1.0f, 2.0f, CameraShakeTarget.Rotation, CameraShakeAmplitudeCurve.FadeInOut25); } if (Input.GetKey(KeyCode.H)) { } Vector3 positionOffset = Vector3.zero; Vector3 rotationOffset = Vector3.zero; for (int i = 0; i < shakes.Count; i++) { shakes[i].Update(); if (shakes[i].target == CameraShakeTarget.Position) { positionOffset += shakes[i].noise; } else { rotationOffset += shakes[i].noise; } } shakes.RemoveAll(x => !x.IsAlive()); transform.localPosition = Vector3.SmoothDamp(transform.localPosition, positionOffset, ref smoothDampPositionVelocity, smoothDampTime); Vector3 eulerAngles = transform.localEulerAngles; eulerAngles.x = Mathf.SmoothDampAngle(eulerAngles.x, rotationOffset.x, ref smoothDampRotationVelocityX, smoothDampTime); eulerAngles.y = Mathf.SmoothDampAngle(eulerAngles.y, rotationOffset.y, ref smoothDampRotationVelocityY, smoothDampTime); eulerAngles.z = Mathf.SmoothDampAngle(eulerAngles.z, rotationOffset.z, ref smoothDampRotationVelocityZ, smoothDampTime); transform.localEulerAngles = eulerAngles; } } } } }