Search Unity

  1. Welcome to the Unity Forums! Please take the time to read our Code of Conduct to familiarize yourself with the forum rules and how to post constructively.
  2. Dismiss Notice

Best way to camera shake

Discussion in 'Scripting' started by MikeyJY, Feb 12, 2021.

  1. MikeyJY

    MikeyJY

    Joined:
    Mar 2, 2018
    Posts:
    530
    I need a camera shake to fit an chopping tree action, the shake should start when the axe collides with the tree and I want the best way, the best ratio between the easiness of doing and the result's fanciness.
     
  2. Kurt-Dekker

    Kurt-Dekker

    Joined:
    Mar 16, 2013
    Posts:
    36,711
    Definitely start with tutorials on this. Camera shaking is tricky because even tiny amounts look massive, since it's your head and eyes effectively. Try a few ways, see what works. Usually you just make a shake offset transform and make it go through some displacement over a short period of time and return to normal.
     
  3. MikeyJY

    MikeyJY

    Joined:
    Mar 2, 2018
    Posts:
    530
    I think the most basic way is with animation clips, but I would like to use something based on physics. I forgot where I saw this way but I taught it has to be cool. To make an empty GameObject where Camera usually is and to create add a joint component and join the camera and the gameobject and then force the camera to move the camera slightly from the object, then the camera will try to reach gameobject's position, but the momentum of that force will push the camera further than the gameobject in the other direction and the camera will bouce around the fixed GameObject until it will eventually stabilize. I tried it and it looked horrible. However I will say that is my fault, not that the idea was bad.
     
  4. adamgolden

    adamgolden

    Joined:
    Jun 17, 2019
    Posts:
    1,494
    You could multiply a motion vector (like rigidBody.velocity) by Sine of time elapsed since the hit with whatever amplitude and period you want (and whatever time offset to get the right feel to the start of it..), multiplying that over a given duration by 1 through 0 for amplitude falloff, and add the resulting Vector3 to the position your camera should be at each frame. This will shake the camera back and forth in the direction of force while the shaking eases back to nothing. You could also make the falloff slow over time (increasing duration slows a lerp), so the shaking also slows down while it weakens. If you're shaking for a tree chop, you might also want to add something like an eased offset to camera rotation around transform.right (i.e. looking slightly downward a bit more during shake falloff), or Vector3.right if using local space.
     
  5. seejayjames

    seejayjames

    Joined:
    Jan 28, 2013
    Posts:
    685
    Cool problem to solve. (Oh how I love game design)

    Just tried this and it works great...totally customizable, should do everything you need.

    --Make a hollow cube out of 6 cubes, stretched to make thin walls. Put a frictionless, fully bouncy Physic material on them. Disable the renderers so they're invisible, only the colliders are needed. No Rigidbodies.
    --Put a sphere in it, making sure there's some bounce room...how much room makes a big difference in the result. Use the same frictionless material. Add a Rigidbody, no gravity. Continuous collision detection so it won't break free of the box with high forces.
    --Child the camera to the center of the sphere.
    --Add force to the sphere so it bounces around in the box!

    Tweak the Drag level to control how long it bounces for. Tweak how much force is applied in each axis, decide whether it's random or not, etc. You might try freezing one or more position axes depending on how much movement you want, like only use X if you want left/right. Probably want to freeze all 3 rotation axes so the end view angle stays the same, but up to you.

    The other cube and plane in the screenshot are just for camera shake reference.

    screenshot_camera_shake1.PNG
     
    Last edited: Feb 13, 2021
    MikeyJY likes this.
  6. angelonit

    angelonit

    Joined:
    Mar 5, 2013
    Posts:
    40
    I made this, feel free to use it
    Code (CSharp):
    1. using System.Collections.Generic;
    2. using UnityEngine;
    3. [System.Serializable]
    4. public class Shake
    5. {
    6.     public float DurationInit;
    7.     public float Duration;
    8.     public float Strength;
    9.     public Vector3 Direction;
    10.     public Shake(float duration, float strength, Vector3 direction)
    11.     {
    12.         this.DurationInit = duration;
    13.         this.Duration = duration;
    14.         this.Strength = strength;
    15.         this.Direction = direction.normalized;
    16.     }
    17. }
    18. public class CameraShake : MonoBehaviour
    19. {
    20.     GameObject _camera;
    21.     Vector3 _posInit;
    22.     //Vector3 _rotInit;
    23.     List<Shake> _shakes = new List<Shake>();
    24.     public float DurationByStrengthMultiplier;//.05f
    25.     public float MultStrength;//.05f
    26.     public float SinePeriod;//60f
    27.     void Start()
    28.     {
    29.         _camera = Camera.main.gameObject;
    30.         _posInit = _camera.transform.position;
    31.         //_rotInit = _camera.transform.rotation.eulerAngles;
    32.     }
    33.  
    34.     public void ShakeAdd(float strength, Vector3 direction)
    35.     {
    36.         _shakes.Add(new Shake(DurationByStrengthMultiplier * Mathf.Log10(strength), Mathf.Log(strength, 3), direction));
    37.     }
    38.     void Update()
    39.     {
    40.         int count = _shakes.Count;
    41.         if (count > 0)
    42.         {
    43.             Vector3 offset = Vector3.zero;
    44.             for (int i = count - 1; i >= 0; i--)
    45.             {
    46.                 _shakes[i].Duration -= Time.deltaTime;
    47.                 if (_shakes[i].Duration > 0)
    48.                 {
    49.                     offset += (Mathf.Sin(SinePeriod * _shakes[i].Duration) * MultStrength * (_shakes[i].Duration / _shakes[i].DurationInit) * _shakes[i].Strength * _shakes[i].Direction);
    50.                 }
    51.                 else
    52.                 {
    53.                     _shakes.RemoveAt(i);
    54.                     if (_shakes.Count == 0)
    55.                     {
    56.                         offset = Vector3.zero;
    57.                         _camera.transform.position = _posInit;
    58.                     }
    59.                 }
    60.             }
    61.             if (offset != Vector3.zero)
    62.             {
    63.                 _camera.transform.position = _posInit + offset;
    64.             }
    65.         }
    66.     }
    67. }
    68.