├── LICENSE ├── README.md ├── ShakeTransform.cs └── ShakeTransformEventData.cs /LICENSE: -------------------------------------------------------------------------------- 1 | MIT License 2 | 3 | Copyright (c) 2018 MirzaBeig 4 | 5 | Permission is hereby granted, free of charge, to any person obtaining a copy 6 | of this software and associated documentation files (the "Software"), to deal 7 | in the Software without restriction, including without limitation the rights 8 | to use, copy, modify, merge, publish, distribute, sublicense, and/or sell 9 | copies of the Software, and to permit persons to whom the Software is 10 | furnished to do so, subject to the following conditions: 11 | 12 | The above copyright notice and this permission notice shall be included in all 13 | copies or substantial portions of the Software. 14 | 15 | THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR 16 | IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, 17 | FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE 18 | AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER 19 | LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, 20 | OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE 21 | SOFTWARE. 22 | -------------------------------------------------------------------------------- /README.md: -------------------------------------------------------------------------------- 1 | # Camera Shake Tutorial 2 | Scripts created during the procedural animation camera shake tutorial (https://youtu.be/qFDCz_QW7WY). 3 | -------------------------------------------------------------------------------- /ShakeTransform.cs: -------------------------------------------------------------------------------- 1 | using System.Collections; 2 | using System.Collections.Generic; 3 | using UnityEngine; 4 | 5 | public class ShakeTransform : MonoBehaviour 6 | { 7 | [System.Serializable] 8 | public class ShakeEvent 9 | { 10 | float duration; 11 | float timeRemaining; 12 | 13 | ShakeTransformEventData data; 14 | 15 | public ShakeTransformEventData.Target target 16 | { 17 | get 18 | { 19 | return data.target; 20 | } 21 | } 22 | 23 | Vector3 noiseOffset; 24 | public Vector3 noise; 25 | 26 | public ShakeEvent(ShakeTransformEventData data) 27 | { 28 | this.data = data; 29 | 30 | duration = data.duration; 31 | timeRemaining = duration; 32 | 33 | float rand = 32.0f; 34 | 35 | noiseOffset.x = Random.Range(0.0f, rand); 36 | noiseOffset.y = Random.Range(0.0f, rand); 37 | noiseOffset.z = Random.Range(0.0f, rand); 38 | } 39 | 40 | public void Update() 41 | { 42 | float deltaTime = Time.deltaTime; 43 | 44 | timeRemaining -= deltaTime; 45 | 46 | float noiseOffsetDelta = deltaTime * data.frequency; 47 | 48 | noiseOffset.x += noiseOffsetDelta; 49 | noiseOffset.y += noiseOffsetDelta; 50 | noiseOffset.z += noiseOffsetDelta; 51 | 52 | noise.x = Mathf.PerlinNoise(noiseOffset.x, 0.0f); 53 | noise.y = Mathf.PerlinNoise(noiseOffset.y, 1.0f); 54 | noise.z = Mathf.PerlinNoise(noiseOffset.z, 2.0f); 55 | 56 | noise -= Vector3.one * 0.5f; 57 | 58 | noise *= data.amplitude; 59 | 60 | float agePercent = 1.0f - (timeRemaining / duration); 61 | noise *= data.blendOverLifetime.Evaluate(agePercent); 62 | } 63 | public bool IsAlive() 64 | { 65 | return timeRemaining > 0.0f; 66 | } 67 | } 68 | 69 | // ... 70 | 71 | List shakeEvents = new List(); 72 | 73 | // ... 74 | 75 | public void AddShakeEvent(ShakeTransformEventData data) 76 | { 77 | shakeEvents.Add(new ShakeEvent(data)); 78 | } 79 | public void AddShakeEvent(float amplitude, float frequency, float duration, AnimationCurve blendOverLifetime, ShakeTransformEventData.Target target) 80 | { 81 | ShakeTransformEventData data = ShakeTransformEventData.CreateInstance(); 82 | data.Init(amplitude, frequency, duration, blendOverLifetime, target); 83 | 84 | AddShakeEvent(data); 85 | } 86 | 87 | void LateUpdate() 88 | { 89 | Vector3 positionOffset = Vector3.zero; 90 | Vector3 rotationOffset = Vector3.zero; 91 | 92 | for (int i = shakeEvents.Count - 1; i != -1; i--) 93 | { 94 | ShakeEvent se = shakeEvents[i]; se.Update(); 95 | 96 | if (se.target == ShakeTransformEventData.Target.Position) 97 | { 98 | positionOffset += se.noise; 99 | } 100 | else 101 | { 102 | rotationOffset += se.noise; 103 | } 104 | 105 | if (!se.IsAlive()) 106 | { 107 | shakeEvents.RemoveAt(i); 108 | } 109 | } 110 | 111 | transform.localPosition = positionOffset; 112 | transform.localEulerAngles = rotationOffset; 113 | } 114 | } 115 | -------------------------------------------------------------------------------- /ShakeTransformEventData.cs: -------------------------------------------------------------------------------- 1 | using System.Collections; 2 | using System.Collections.Generic; 3 | using UnityEngine; 4 | 5 | [CreateAssetMenu(fileName = "Shake Transform Event", menuName = "Custom/Shake Transform Event", order = 1)] 6 | public class ShakeTransformEventData : ScriptableObject 7 | { 8 | public enum Target 9 | { 10 | Position, 11 | Rotation 12 | } 13 | 14 | public Target target = Target.Position; 15 | 16 | public float amplitude = 1.0f; 17 | public float frequency = 1.0f; 18 | 19 | public float duration = 1.0f; 20 | 21 | public AnimationCurve blendOverLifetime = new AnimationCurve( 22 | 23 | new Keyframe(0.0f, 0.0f, Mathf.Deg2Rad * 0.0f, Mathf.Deg2Rad * 720.0f), 24 | new Keyframe(0.2f, 1.0f), 25 | new Keyframe(1.0f, 0.0f)); 26 | 27 | public void Init(float amplitude, float frequency, float duration, AnimationCurve blendOverLifetime, Target target) 28 | { 29 | this.target = target; 30 | 31 | this.amplitude = amplitude; 32 | this.frequency = frequency; 33 | 34 | this.duration = duration; 35 | 36 | this.blendOverLifetime = blendOverLifetime; 37 | } 38 | } 39 | --------------------------------------------------------------------------------