Camera shake

Hey guys how can i make a simlpe camera shake that returns 2 its original position after shaking

function Update() {
 
    if(Shake < 0){
    
     Shake =  0;
      
       } 

  if (Shake > 0) {
    
       cam.transform.localPosition = Random.insideUnitSphere * shakeAmount; 
    
            Shake -= Time.deltaTime * decreaseFactor;


  } else {
    shake = 0.0;
  }
}

I know this question is bit old, but I thought I’d share my answer for posterity’s sake. I also ran into the problem of returning to the original position/rotation after finished shaking, and came up with this solution.

Here is a demo of the camera shake script.

Using two variables shake_intensity, and shake_decay the script generates a new random position and rotation within the range (defined by shake_intensity). With each Update(), shake_intensity decays until the position and rotation are at their original position.

var originPosition:Vector3;
var originRotation:Quaternion;

var shake_decay: float;
var shake_intensity: float;;

function OnGUI () {
    if (GUI.Button (Rect (20,40,80,20), "Shake")) {
        Shake();
    }
} 

function Update(){
    if(shake_intensity > 0){
        transform.position = originPosition + Random.insideUnitSphere * shake_intensity;
        transform.rotation =  Quaternion(
                        originRotation.x + Random.Range(-shake_intensity,shake_intensity)*.2,
                        originRotation.y + Random.Range(-shake_intensity,shake_intensity)*.2,
                        originRotation.z + Random.Range(-shake_intensity,shake_intensity)*.2,
                        originRotation.w + Random.Range(-shake_intensity,shake_intensity)*.2);
        shake_intensity -= shake_decay;
    }
}

function Shake(){
    originPosition = transform.position;
    originRotation = transform.rotation;
    shake_intensity = .3;
    shake_decay = 0.002;
}

The solutions on this page work but randomized movement is very poor.

Substituting with noise will improve it dramatically. See here:

Perlin Noise is already built-in to Unity of course…

Thanks, this works perfectly!

For testing I added a test button which calls the DoShake function:

using UnityEngine;
using System.Collections;

public class CameraShake : MonoBehaviour {
	

public bool Shaking; 
private float ShakeDecay;
private float ShakeIntensity;	
private Vector3 OriginalPos;
private Quaternion OriginalRot;

void Start()
{
    Shaking = false;   
}


// Update is called once per frame
void Update () 
{
    if(ShakeIntensity > 0)
    {
        transform.position = OriginalPos + Random.insideUnitSphere * ShakeIntensity;
        transform.rotation = new Quaternion(OriginalRot.x + Random.Range(-ShakeIntensity, ShakeIntensity)*.2f,
                                  OriginalRot.y + Random.Range(-ShakeIntensity, ShakeIntensity)*.2f,
                                  OriginalRot.z + Random.Range(-ShakeIntensity, ShakeIntensity)*.2f,
                                  OriginalRot.w + Random.Range(-ShakeIntensity, ShakeIntensity)*.2f);

       ShakeIntensity -= ShakeDecay;
    }
    else if (Shaking)
    {
       Shaking = false;  
    }
}
	
	
void OnGUI() {

	if (GUI.Button(new Rect(10, 200, 50, 30), "Shake"))
		DoShake();
		Debug.Log("Shake");

}		
		

        
    	
	

public void DoShake()
{
    OriginalPos = transform.position;
    OriginalRot = transform.rotation;

    ShakeIntensity = 0.3f;
    ShakeDecay = 0.02f;
    Shaking = true;
}	
	
	
}

EDIT: mdjasper, thanks for coming up with the original solution!

I really liked this solution for what I’m working on so I thought I’d share the modifications I made. I added the ability to select from the inspector whether you just want to shake position, rotation or both. I also made the intensity and decay values public so they can be set from the inspector as well. And most importantly took the bulk of the code out of the update method and made it a coroutine. This keeps it from checking the shakeIntensity on every single frame whether shaking or not. Cheers!

using UnityEngine; 
using System.Collections;

public class ShakeCamera : MonoBehaviour { 

	public bool shakePosition;
	public bool shakeRotation;

	public float shakeIntensity = 0.5f; 
	public float shakeDecay = 0.02f;
	
	private Vector3 OriginalPos;
	private Quaternion OriginalRot;

	private bool isShakeRunning = false;

	
	public void DoShake()
	{
		OriginalPos = transform.position;
		OriginalRot = transform.rotation;

		StartCoroutine ("ProcessShake");
	}

	IEnumerator ProcessShake()
	{
		if (!isShakeRunning) {
			isShakeRunning = true;
			float currentShakeIntensity = shakeIntensity;

			while (currentShakeIntensity > 0) {
				if (shakePosition) {
					transform.position = OriginalPos + Random.insideUnitSphere * currentShakeIntensity;
				}
				if (shakeRotation) {
					transform.rotation = new Quaternion (OriginalRot.x + Random.Range (-currentShakeIntensity, currentShakeIntensity) * .2f,
					                                    OriginalRot.y + Random.Range (-currentShakeIntensity, currentShakeIntensity) * .2f,
					                                    OriginalRot.z + Random.Range (-currentShakeIntensity, currentShakeIntensity) * .2f,
					                                    OriginalRot.w + Random.Range (-currentShakeIntensity, currentShakeIntensity) * .2f);
				}
				currentShakeIntensity -= shakeDecay;
				yield return null;
			}

			isShakeRunning = false;
		}
	}
}

Hi @squareorb Thanks so much for the solution. It works like a charm!

I thought I’d never find a fix for getting a good Camera Shake. Just a quick one though.

Do you know of a method to somehow make only the X Y or Z Axis shake when you shake the position. I’ve tried converting everything to floats by using the .x/.y/.z parameters on the vector3’s but it doesn’t seem to work.

Any Suggestions?
Thanks again!

Kind Regards,

Have a look at this thread

I’ve used this one, and it works perfectly :slight_smile:
bool flip;

	float yPos;
	float shakeAmount = 1;

	public Transform myCam;

	void Update()
	{
		if(Input.GetKeyDown(KeyCode.Space)) StartCoroutine ("CamShake");
	}

	IEnumerator CamShake ()
	{
		yPos = shakeAmount;

		while (Mathf.Abs(yPos) > 0.01f ) 
		{
			yPos = Mathf.Abs (yPos) - 0.1f;

			if (flip) yPos *= -1;

			flip = !flip;

			//Tripple setup thingo!
			Vector3 tempPos = myCam.localPosition;
			tempPos.y = yPos;
			myCam.localPosition = tempPos;

			yield return null;
		}
	}

To anyone still trying to find an answer. Or someone who might want to improve my code here it goes.

This works if you put your camera GameObject as a child of another Transform (this parent Transform holds the true position of the camera while we shake the camera by changing the childs transform position rotation and fov).

First let’s define a class for our shake….

public class CameraShake
{
    public struct ElementShake
    {
        public float amplitude,
                     frequency;

        public ElementShake(float amplitude, float frequency)
        {
            this.amplitude = amplitude;
            this.frequency = frequency;
        }
    }

    public float duration,
                 blendInTime,
                 blendOutTime;
    public ElementShake[] rotationShake = new ElementShake[3];
    public ElementShake[] positionShake = new ElementShake[3];
    public ElementShake fieldOfViewShake;

    public CameraShake()
        : this(1f, 0.1f, 0.2f)
    {
    }

    public CameraShake(float duration, float blendInTime, float blendOutTime)
    {
        this.duration = duration;
        this.blendInTime = blendInTime;
        this.blendOutTime = blendOutTime;


        for (int i = 0; i < rotationShake.Length; i++)
            rotationShake *= new ElementShake(0f, 0f);*

for (int i = 0; i < positionShake.Length; i++)
rotationShake = new ElementShake(0f, 0f);

fieldOfViewShake = new ElementShake(0f, 0f);
}
}
Now lets define our player controller :
using System.Collections;
using System.Collections.Generic;
using UnityEngine;

public class PlayaController : MonoBehaviour
{
internal struct CameraShakeSettings
{
public Vector3 pos,
initialPosition;
public Vector3 rot,
initialRotation;
public float fov,
initialFieldOfView;
public Coroutine shakeCoroutine;
}

public Camera mainCamera;
static PlayaController controller;
private CameraShakeSettings cameraShakeSettings = new CameraShakeSettings();

private void Awake()
{
controller = this;
}

private void Start()
{
cameraShakeSettings.initialPosition = mainCamera.transform.localPosition;
cameraShakeSettings.initialRotation = mainCamera.transform.localRotation.eulerAngles;
cameraShakeSettings.initialFieldOfView = mainCamera.fieldOfView;
}

public static void PlayCameraShake(CameraShake cameraShake, float scale = 1f)
{
if (controller == null)
return;

if (controller.cameraShakeSettings.shakeCoroutine != null)
controller.StopCoroutine(controller.cameraShakeSettings.shakeCoroutine);

controller.cameraShakeSettings.shakeCoroutine = controller.StartCoroutine(controller.ShakeCamera(cameraShake, scale));
}

private IEnumerator ShakeCamera(CameraShake cameraShake, float scale)
{
float blendScale = 0f;
float blendInTimer = cameraShake.duration * Mathf.Min(cameraShake.blendInTime, 1f);
float blendOutTimer = cameraShake.duration * Mathf.Min(cameraShake.blendOutTime, 1f);
float timer = 0f;

Camera cam = mainCamera;
Transform t = cam.transform;

while (timer <= cameraShake.duration)
{
float blendInScale = Mathf.Clamp01(timer / blendInTimer);
float blendOutScale = Mathf.Clamp01((cameraShake.duration - timer) / blendOutTimer);

blendScale = scale * blendInScale * blendOutScale;

float blendTime = timer / cameraShake.duration;

cameraShakeSettings.rot.x = (Mathf.Cos(blendTime * cameraShake.rotationShake[0].frequency * Mathf.Rad2Deg) * cameraShake.rotationShake[0].amplitude) * blendScale;
cameraShakeSettings.rot.y = (Mathf.Cos(blendTime * cameraShake.rotationShake[1].frequency * Mathf.Rad2Deg) * cameraShake.rotationShake[1].amplitude) * blendScale;
cameraShakeSettings.rot.z = (Mathf.Cos(blendTime * cameraShake.rotationShake[2].frequency * Mathf.Rad2Deg) * cameraShake.rotationShake[2].amplitude) * blendScale;

t.localRotation = Quaternion.Euler(cameraShakeSettings.initialRotation.x + cameraShakeSettings.rot.x,
cameraShakeSettings.initialRotation.y + cameraShakeSettings.rot.y,
cameraShakeSettings.initialRotation.z + cameraShakeSettings.rot.z);

cameraShakeSettings.pos.x = (Mathf.Cos(blendTime * cameraShake.positionShake[0].frequency * Mathf.Rad2Deg) * cameraShake.positionShake[0].amplitude);
cameraShakeSettings.pos.y = (Mathf.Cos(blendTime * cameraShake.positionShake[1].frequency * Mathf.Rad2Deg) * cameraShake.positionShake[1].amplitude);
cameraShakeSettings.pos.z = (Mathf.Cos(blendTime * cameraShake.positionShake[2].frequency * Mathf.Rad2Deg) * cameraShake.positionShake[2].amplitude);

t.localPosition = cameraShakeSettings.initialPosition + cameraShakeSettings.pos * blendScale;

cameraShakeSettings.fov = (Mathf.Cos(blendTime * cameraShake.fieldOfViewShake.frequency * Mathf.Deg2Rad) * cameraShake.fieldOfViewShake.amplitude) * blendScale;

cam.fieldOfView = cameraShakeSettings.initialFieldOfView + cameraShakeSettings.fov;

timer += Time.deltaTime;
yield return null;
}

t.localRotation = Quaternion.Euler(cameraShakeSettings.initialRotation);
t.localPosition = cameraShakeSettings.initialPosition;
cam.fieldOfView = cameraShakeSettings.initialFieldOfView;
}

private void Update()
{
if (Input.GetKeyDown(KeyCode.S))
{
CameraShake shake = new CameraShake(1f, 0.5f, 0.5f);
//Rotation shake On X axis
shake.rotationShake[0].amplitude = 0.1f;
shake.rotationShake[0].frequency = 10000;

//Rotation shake ON Y axis
shake.rotationShake[1].amplitude = 0.1f;
shake.rotationShake[1].frequency = 10000;

//Rotation shake On Z axis
shake.rotationShake[2].amplitude = 0.1f;
shake.rotationShake[2].frequency = 10000;

//Position shake On X axis
shake.positionShake[0].amplitude = 0.1f;
shake.positionShake[0].frequency = 10000;

//Position shake On Y axis
shake.positionShake[1].amplitude = 0.1f;
shake.positionShake[1].frequency = 10000;

//Position shake On Z axis
shake.positionShake[2].amplitude = 0.1f;
shake.positionShake[2].frequency = 10000;

//Field of view shake
shake.fieldOfViewShake.amplitude = 1f;
shake.fieldOfViewShake.frequency = 100000;

PlayCameraShake(shake, 0.4f);
}
}
}
You should now be able to Press S and see the camera shake.
With this code you can just play the shake from any script by calling the player controller method like this :
PlayaController.PlayCameraShake(cameraShake);

If anybody finds this useful just comment or if you find a bug let me know I’ll correct it.
if you can find me a solution to play 2 camera shakes at the same time let me know.
Cheers everybody. Hope this helps.

The snippet in this post works perfectly for me: Basic 2D “Screen Shake” in Unity. Like this post? You might like… | by Matt Buckley | Nice Things | iOS + Android Development | Medium

If you put your object under a parent that sets the world position, you can offset the localPosition to give it shake and when your offset goes to zero your object will return to the neutral position.

Please don’t use random values to cause camera shake! Use a continuous function like perlin noise or sine to get smooth movement.

Here’s a script ShakeIn2D that can shake objects or camera as shown in these videos.

using UnityEngine;
using System.Collections;

public class ShakeCamera : MonoBehaviour 
{
public bool Shaking;
private float ShakeDecay;
private float ShakeIntensity;

private Vector3 OriginalPos;
private Quaternion OriginalRot;

void Start()
{
	Shaking = false;	
}


// Update is called once per frame
void Update () 
{
	if(ShakeIntensity > 0)
	{
    	transform.position = OriginalPos + Random.insideUnitSphere * ShakeIntensity;
    	transform.rotation = new Quaternion(OriginalRot.x + Random.Range(-ShakeIntensity, ShakeIntensity)*.2f,
                    					OriginalRot.y + Random.Range(-ShakeIntensity, ShakeIntensity)*.2f,
                    					OriginalRot.z + Random.Range(-ShakeIntensity, ShakeIntensity)*.2f,
                    					OriginalRot.w + Random.Range(-ShakeIntensity, ShakeIntensity)*.2f);
    	
		ShakeIntensity -= ShakeDecay;
	}
	else if (Shaking)
	{
		Shaking = false;	
	}
}

public void DoShake()
{
	OriginalPos = transform.position;
	OriginalRot = transform.rotation;
	
	ShakeIntensity = 0.3f;
	ShakeDecay = 0.02f;
	Shaking = true;
}

}