Skip to content

Instantly share code, notes, and snippets.

@ftvs
Last active January 19, 2024 11:57
Star You must be signed in to star a gist
Save ftvs/5822103 to your computer and use it in GitHub Desktop.
Simple camera shake effect for Unity3d, written in C#. Attach to your camera GameObject. To shake the camera, set shakeDuration to the number of seconds it should shake for. It will start shaking if it is enabled.
using UnityEngine;
using System.Collections;
public class CameraShake : MonoBehaviour
{
// Transform of the camera to shake. Grabs the gameObject's transform
// if null.
public Transform camTransform;
// How long the object should shake for.
public float shakeDuration = 0f;
// Amplitude of the shake. A larger value shakes the camera harder.
public float shakeAmount = 0.7f;
public float decreaseFactor = 1.0f;
Vector3 originalPos;
void Awake()
{
if (camTransform == null)
{
camTransform = GetComponent(typeof(Transform)) as Transform;
}
}
void OnEnable()
{
originalPos = camTransform.localPosition;
}
void Update()
{
if (shakeDuration > 0)
{
camTransform.localPosition = originalPos + Random.insideUnitSphere * shakeAmount;
shakeDuration -= Time.deltaTime * decreaseFactor;
}
else
{
shakeDuration = 0f;
camTransform.localPosition = originalPos;
}
}
}
@Totoual
Copy link

Totoual commented Nov 9, 2017

Thank you man. It was exactly what I was looking for :)

@RishabhRyber
Copy link

Thanks man, this helped me a lot. Thanks again.

@Jaemins
Copy link

Jaemins commented Mar 11, 2018

Thank you , It helped a lot.
But I wonder why this is necessary

camTransform = GetComponent(typeof(Transform)) as Transform;

can you answer me ?

@Tanz0rz
Copy link

Tanz0rz commented Apr 1, 2018

Good starter code! I modified this and was off to the races in about 15 minutes

@victor-guillermo
Copy link

Dear User FTVS,

I am currently working with a team of college students to make a video game for our senior thesis. We intend to ship this project onto steam and there is a possibility it will be released onto Xbox One.

For this project, we need a camera shake script and the script you made is perfect for our game.

Would it be possible for us to use your script for our game?

@GustavoBernardi
Copy link

Nice! Now how can I control the speed of the shake?

@AndySum
Copy link

AndySum commented Jul 4, 2018

Amazing thanks!

@Ztuu
Copy link

Ztuu commented Feb 24, 2019

Thanks for this!

@rootste000
Copy link

This worked great for a stationary camera. The only issue that I have is that I made an on-rails shooter and my camera is keyframed to a timeline so the shake will not override that. Any idea how to make it work with the camera being on a timeline?

@rivax95
Copy link

rivax95 commented Apr 17, 2019

Thanks !

@stickylabdev
Copy link

doesnot work at all

@krupasknr
Copy link

thanks,.. so simple

@hergaiety
Copy link

Good stuff!

@sauravrao637
Copy link

sauravrao637 commented Jun 6, 2020

Thanks @ixikos. I expanded on your script to calculate a delta time so the shake duration is retained even when the game gets paused (and Time.deltaTime stops).

using UnityEngine;
using System.Collections;

public class CameraShake : MonoBehaviour {
    public static CameraShake instance;

    private Vector3 _originalPos;
    private float _timeAtCurrentFrame;
    private float _timeAtLastFrame;
    private float _fakeDelta;

    void Awake() {
        instance = this;
    }

    void Update() {
        // Calculate a fake delta time, so we can Shake while game is paused.
        _timeAtCurrentFrame = Time.realtimeSinceStartup;
        _fakeDelta = _timeAtCurrentFrame - _timeAtLastFrame;
        _timeAtLastFrame = _timeAtCurrentFrame; 
    }

    public static void Shake (float duration, float amount) {
        instance._originalPos = instance.gameObject.transform.localPosition;
        instance.StopAllCoroutines();
        instance.StartCoroutine(instance.cShake(duration, amount));
    }

    public IEnumerator cShake (float duration, float amount) {
        float endTime = Time.time + duration;

        while (duration > 0) {
            transform.localPosition = _originalPos + Random.insideUnitSphere * amount;

            duration -= _fakeDelta;

            yield return null;
        }

        transform.localPosition = _originalPos;
    }
}

And of course, call it from anywhere by
CameraShake.Shake(0.25f, 4f);

@sauravrao637
Copy link

Thanks :)

@Ultroman
Copy link

Ultroman commented Feb 17, 2021

Thanks @ixikos. I expanded on your script to calculate a delta time so the shake duration is retained even when the game gets paused (and Time.deltaTime stops).

Couldn't you just have replaced Time.deltaTime with Time.unscaledDeltaTime and had the same functionality?

@krlosrokr
Copy link

Thanks man!

@stewheart123
Copy link

really freaking cool! modified it to run whenever an in-game explosion happens. Added tonnes of feeling to my project!

@hasselmann-click
Copy link

Thank you! I put your script in a small Coroutine. Makes my prototypes instantly more fun!

    // used fields
    private Camera mainCamera;
    [SerializeField] private float cameraShakeDuration = 0.5f;
    [SerializeField] private float cameraShakeDecreaseFactor = 1f;
    [SerializeField] private float cameraShakeAmount = 1f;
    // coroutine
    IEnumerator ShakeCamera()
    {
        var originalPos = mainCamera.transform.localPosition;
        var duration = cameraShakeDuration;
        while(duration > 0)
        {
            mainCamera.transform.localPosition = originalPos + Random.insideUnitSphere * cameraShakeAmount;
            duration -= Time.deltaTime * cameraShakeDecreaseFactor;
            yield return null;
        }
        mainCamera.transform.localPosition = originalPos;
    }

@XaviSmith
Copy link

XaviSmith commented Jan 5, 2023

Nice script!

For anyone that wants it I made a version that allows you to skip frames to control how jerky the camera shake is, works on any gameObject, and lets you choose whether or not to run it whenever the script is enabled.

public class ObjectShaker : MonoBehaviour {

bool startOnEnable = true;
float shakeDuration = 1f;
float framesToSkip = 0f; //How many frames to we skip in order to slow down the jerkiness of the animation
public float shakeAmount = 1f;

void OnEnable()
{
    if(startOnEnable)
    {
        Shake();
    }
}

//Parameters are optional. Defaults to object variables.
public void Shake(float _duration = -1f, float _skip = -1f, float _amount = -1f)
{
    if(_duration < 0)
    {
        _duration = shakeDuration;
    }

    if(_skip < 0)
    {
        _skip = framesToSkip;
    }

    if(_amount < 0)
    {
        _amount = shakeAmount;
    }

    StartCoroutine(ShakeCoroutine(_duration, _skip, _amount));
}



IEnumerator ShakeCoroutine(float _duration, float _framesToSkip, float _amount)
{
  //For if you need special logic for Main Cameras (e.g. you have a script that follows the player around that you need to disable temporarily)
    if(gameObject.tag == "MainCamera")
    {
        //Disable here
    }

    Vector3 originalPos = transform.position;

    float currFramesSkipped = 0f;
    bool locked = true;

    while (_duration > 0)
    {
        if(currFramesSkipped <= _framesToSkip)
        {
            locked = true;
            currFramesSkipped += 1;
        } else
        {
            locked = false;
            currFramesSkipped = 0f;
        }

        if(!locked)
        {
            transform.position = originalPos + Random.insideUnitSphere * _amount;
        }
        
        _duration -= Time.deltaTime;
        yield return null;
    }

    //reenable your camera
    if (gameObject.tag == "MainCamera")
    {
        //reenable camera logic here
    }
    transform.position = originalPos;
}

}

@AnKlagges92
Copy link

AnKlagges92 commented Sep 9, 2023

Here's my script to shake, feel free to use and modify.

using UnityEngine;
#if ODIN_INSPECTOR
using Sirenix.OdinInspector;
#endif

namespace AKGaming
{
    public class ShakeComponent : MonoBehaviour
    {
        [SerializeField] private Transform target_;
        [SerializeField] private float defaultDuration_ = 0.5f;
        [SerializeField] private float defaultAmplitude_ = 0.75f;
        [SerializeField] private float defaultFinalAmplitude_ = 0.25f;
        [SerializeField] private AnimationCurve defaultAmplitudeCurve_ = AnimationCurve.Linear(0, 0, 1, 1);

        private float duration_;
        private float remainingTime_;
        private float amplitude_;
        private float finalAmplitude_;
        private AnimationCurve amplitudeCurve_;
        private Vector3 initialPosition_;

        private void Awake()
        {
            if (target_ == null)
            {
                target_ = GetComponent<Transform>();
            }
            initialPosition_ = target_.localPosition;
        }

        public void Shake(float duration = -1, float amplitude = -1, float finalAmplitude = -1, AnimationCurve amplitudeCurve = null)
        {
            duration_ = duration > 0 ? duration : defaultDuration_;
            amplitude_ = amplitude >= 0 ? amplitude : defaultAmplitude_;
            finalAmplitude_ = finalAmplitude >= 0 ? finalAmplitude : defaultFinalAmplitude_;
            amplitudeCurve_ = amplitudeCurve != null ? amplitudeCurve : defaultAmplitudeCurve_;

            remainingTime_ = duration_;
            enabled = true;
        }

        private void Update()
        {
            if (remainingTime_ > 0)
            {
                float curveValue = amplitudeCurve_.Evaluate(1 - (remainingTime_ / duration_));
                float amplitude = (1 - curveValue) * amplitude_ + curveValue * finalAmplitude_;
                transform.localPosition = initialPosition_ + Random.insideUnitSphere * amplitude;
                remainingTime_ -= Time.deltaTime;
            }
            else
            {
                remainingTime_ = 0f;
                transform.localPosition = initialPosition_;
                enabled = false;
            }
        }

#if UNITY_EDITOR
#if ODIN_INSPECTOR
        [Button("Test Shake")]
#endif
        [ContextMenu("Test Shake")]
        private void EDITOR_TestShake()
        {
            Shake();
        }
#endif
    }
}

Here's the amplitude curve i'm using right now.
Please notice that the curve value is not the actual amplitude value so I recommend that it always goes from 0 to 1.

@PazoGames
Copy link

Thanks! It worked well. The only thing I added to the script was a line that turns CinemachineBrain false because camera shaker didn't work with cinemachine.

Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment