Created
April 1, 2014 15:04
-
-
Save Bocom/9916005 to your computer and use it in GitHub Desktop.
This file contains hidden or bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
| using System.Collections; | |
| using UnityEngine; | |
| // Shakes the camera if placed on the camera's GameObject or a parent of the camera's GameObject. | |
| // (Putting it on a parent of the camera stops it potentially interfering with other camera scripts). | |
| public class CameraShake : MonoBehaviour { | |
| // How fast the shaking magnitude reduces - this much per second | |
| const float shakeFalloffSpeed = 2.0f; | |
| // How quickly the camera shakes around | |
| const float shakeSpeed = 20.0f; | |
| // If a shake is called when the camera is already shaking, its additional intensity will be | |
| // reduced proportionately to how much the camera is shaking already. Eventually the addition will be almost zero; | |
| // so a hundred things causing shake at once won't have insanely huge camera shake. | |
| // Lower values = FASTER falloff. | |
| const float addFalloff = 0.1f; | |
| // Minimum multiplier | |
| // Means we stop bothering to add shakes when there is already a lot of shaking | |
| const float minMultiplierToAdd = 0.15f; | |
| Transform tr; // Cached reference | |
| float curMagnitude; | |
| bool coroutineIsRunning = false; | |
| public static bool Exists { | |
| get { return instance != null; } | |
| } | |
| // Note that this isn't a self-creating singleton - instance will be null if this script isn't in the scene, so scripts need to do a null check. | |
| // Can use Exists for that, or null check after GetInstance | |
| static CameraShake instance; | |
| public static CameraShake GetInstance { | |
| get { | |
| if (instance == null) { | |
| Debug.LogWarning("A script tried to get the CameraShake script but there's none in the scene. Will return null."); | |
| } | |
| return instance; | |
| } | |
| } | |
| // #### UNITY INTERNAL METHODS #### | |
| void Awake() { | |
| tr = transform; | |
| instance = this; | |
| } | |
| // #### PUBLIC METHODS #### | |
| public void ShakeCamera(float magnitude) { | |
| magnitude *= 0.01f; // We divide by 100 here just so nicer values can be set for the input. Otherwise they end up very small | |
| float multiplier = Mathf.Min(1.0f, Mathf.Pow(addFalloff, curMagnitude)); | |
| // Avoid going forever with ridiculously small values if lots of shakes are called at once | |
| if (multiplier < minMultiplierToAdd) { | |
| return; | |
| } | |
| // NOTE: The multiplier system avoids the shakes getting too big, but it has sort of an archilles' heel. | |
| // It sort of normalises the shakes so e.g. several large shake calls will end up closer to several small shake calls than they should be. | |
| // I can't think of a better way to handle it right now without a lot of extra data to remember the details of previous shakes. | |
| // Adds magnitude instead of setting it, so multiple shake commands can add together | |
| curMagnitude += magnitude * multiplier; | |
| // If a shake is already being performed, we can just increase the magnitude (above) and it'll pick up the change and run for longer. | |
| // Start the shake coroutine if there isn't any shaking already | |
| if (!coroutineIsRunning) { | |
| coroutineIsRunning = true; | |
| StartCoroutine(Shake()); | |
| } | |
| } | |
| // #### PRIVATE METHODS #### | |
| IEnumerator Shake() { | |
| ShakeCamera(); | |
| yield return null; // Will continue next frame | |
| while (curMagnitude > (shakeFalloffSpeed * Time.deltaTime)) { | |
| ShakeCamera(); | |
| yield return null; | |
| } | |
| tr.position = Vector3.zero; // Finish the shake definitively | |
| curMagnitude = 0; | |
| coroutineIsRunning = false; | |
| } | |
| void ShakeCamera() { | |
| float val = Time.time * shakeSpeed; | |
| float xOffset = curMagnitude * Mathf.PerlinNoise(val, 0); | |
| float yOffset = curMagnitude * Mathf.PerlinNoise(0, val); | |
| float zOffset = curMagnitude * Mathf.PerlinNoise(val, val); | |
| tr.position = new Vector3(xOffset, yOffset, zOffset); | |
| curMagnitude -= (shakeFalloffSpeed * Time.deltaTime); | |
| } | |
| } | |
| //Called like this: | |
| if (CameraShake.Exists) CameraShake.GetInstance.ShakeCamera(w.CameraShakeAmount); |
Sign up for free
to join this conversation on GitHub.
Already have an account?
Sign in to comment