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; | |
} | |
} | |
} |
@nicotroia - thanks! Nice one.
Great camera shakes, this is just what I am looking for.
I am still a noob in programming.
Is there a way to enable this script on collision?
Does somebody already have a script to do this?
I am using a fps.
Any help is welcome.
Thanks.
create camerashake.cs file in your project and add the below code in the script then after you can attach this script to the camera object.
using System.Collections;
using System.Collections.Generic;
using UnityEngine;
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;
public bool shaketrue= false;
Vector3 originalPos;
void Awake()
{
if (camTransform == null)
{
camTransform = GetComponent(typeof(Transform)) as Transform;
}
}
void OnEnable()
{
originalPos = camTransform.localPosition;
}
void Update()
{
if (shaketrue)
{
if (shakeDuration > 0) {
camTransform.localPosition = originalPos + Random.insideUnitSphere * shakeAmount;
shakeDuration -= Time.deltaTime * decreaseFactor;
} else {
shakeDuration = 1f;
camTransform.localPosition = originalPos;
shaketrue = false;
}
}
}
public void shakecamera()
{
shaketrue = true;
}
}
after that you can create button and on button click event you can call the shakecamera() public function so camera is shaking on button click you simply call this function ontriggerenter also to shake the camera.
i hope that it is helpful for developers.
For a smooth movement, change
camTransform.localPosition = originalPos + Random.insideUnitSphere * shakeAmount;
with
camTransform.localPosition = Vector3.Lerp(camTransform.localPosition,originalPos + Random.insideUnitSphere * shakeAmount,Time.deltaTime * 3);
but... if you use this line:
shakeDuration = 1f;
to reset the shake duration, after the first shake, it return always to 1.
public float shakeDuration = 0f;
becomes useless.
You have to save the original shakeDuration:
`
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;
public bool shaketrue = false;
Vector3 originalPos;
float originalShakeDuration; //<--add this
void Awake()
{
if (camTransform == null)
{
camTransform = GetComponent(typeof(Transform)) as Transform;
}
}
void OnEnable()
{
originalPos = camTransform.localPosition;
originalShakeDuration = shakeDuration; //<--add this
}
void Update()
{
if (shaketrue)
{
if (shakeDuration > 0)
{
camTransform.localPosition = Vector3.Lerp(camTransform.localPosition,originalPos + Random.insideUnitSphere * shakeAmount,Time.deltaTime * 3);
shakeDuration -= Time.deltaTime * decreaseFactor;
}
else
{
shakeDuration = originalShakeDuration; //<--add this
camTransform.localPosition = originalPos;
shaketrue = false;
}
}
}
public void shakecamera()
{
shaketrue = true;
}
}
`
and, if you want call a shake with different parameters, add this function:
public void shakecamera(float _shakeDuration, float _shakeAmount)
{
shaketrue = true;
shakeDuration = _shakeDuration;
shakeAmount = _shakeAmount;
}
Thank you man. It was exactly what I was looking for :)
Thanks man, this helped me a lot. Thanks again.
Thank you , It helped a lot.
But I wonder why this is necessary
camTransform = GetComponent(typeof(Transform)) as Transform;
can you answer me ?
Good starter code! I modified this and was off to the races in about 15 minutes
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?
Nice! Now how can I control the speed of the shake?
Amazing thanks!
Thanks for this!
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?
Thanks !
doesnot work at all
thanks,.. so simple
Good stuff!
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);
Thanks :)
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?
Thanks man!
really freaking cool! modified it to run whenever an in-game explosion happens. Added tonnes of feeling to my project!
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;
}
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;
}
}
thanks it helps me too thumbs up for .cs