Search Unity

  1. Unity 6 Preview is now available. To find out what's new, have a look at our Unity 6 Preview blog post.
    Dismiss Notice
  2. Unity is excited to announce that we will be collaborating with TheXPlace for a summer game jam from June 13 - June 19. Learn more.
    Dismiss Notice

[Question] 2D Camera Follow Shake

Discussion in '2D' started by Eziekieal, Nov 5, 2016.

Thread Status:
Not open for further replies.
  1. Eziekieal

    Eziekieal

    Joined:
    Mar 12, 2015
    Posts:
    28
    Hey guys, so I'm working on a 2D platformer. I'm having a problem that is giving me a headache to solve.

    When my camera moves after the player it moves exactly how I want it to, but all the sprites on screen seem to have a random slight shaking issue as if they were being moved slightly back and forth.

    When setting the camera just as a child of the player it doesn't seem to be a problem. But when I use my script I just can't get it to stop. I am using Pixel Perfect Camera (https://www.assetstore.unity3d.com/en/#!/content/64563) which has helped immensely in a 2D environment. Though regardless of it being enabled or disabled I still have the shaking issue.

    Originally my camera follow script was in update and it created a huge shaking problem on the player icon along with all the other icons. So I moved it to FixedUpdate. Which stopped the shaking on the player but left it on the rest of the terrain.

    All of my imported graphics are using PPU: 16, Point (no filter), Truecolor, and Generate Mip Maps is unchecked.

    Any help would be appreciated. I'm still really new at this.

    Code (CSharp):
    1.     void FixedUpdate()
    2.     {
    3.         if (followTarget == true)
    4.         {
    5.             targetPosition = new Vector3(target.transform.position.x, target.transform.position.y, transform.position.z);
    6.  
    7.             if (target.transform.localScale.x > 0.0f)
    8.             {
    9.                 targetPosition = new Vector3(targetPosition.x + followAhead, targetPosition.y + followAbove, targetPosition.z);
    10.             }
    11.             else
    12.             {
    13.                 targetPosition = new Vector3(targetPosition.x - followAhead, targetPosition.y + followAbove, targetPosition.z);
    14.             }
    15.  
    16.             transform.position = Vector3.Lerp(transform.position, targetPosition, Time.deltaTime * Smoothing);
    17.  
    18.         }
    19.     }
    Edit: I've noticed the shake seems to get a little worse as the camera slows down and centers on the player.
     
    Last edited: Nov 5, 2016
  2. SpookyMo

    SpookyMo

    Joined:
    Nov 4, 2016
    Posts:
    3
    how about you just put the code"camera.transform.localposition = player.transform.localposition" instead of your main code,and then have a look.
     
  3. Eziekieal

    Eziekieal

    Joined:
    Mar 12, 2015
    Posts:
    28
    That would essentially be the same as setting the camera as the child of the player, I believe. Which, like I stated above, doesn't seem to have the shaking issue I'm talking about, but then it doesn't have the camera smoothly following after the player.

    Any other thoughts?
     
    Last edited: Nov 6, 2016
  4. SpookyMo

    SpookyMo

    Joined:
    Nov 4, 2016
    Posts:
    3
    Oh I see.You like the camera follow the character slowly and smoothly than its move.How about maker a something like timer event ,run maybe 0.1second after input triggered.I think why shaking happen may becase of if keep pressing keyboard,something will mess up between update () and fixupdate() ,their works too quick.
     
  5. LiterallyJeff

    LiterallyJeff

    Joined:
    Jan 21, 2015
    Posts:
    2,807
    Try this:
    Code (CSharp):
    1. private void LateUpdate() {
    2.     if(followTarget && target != null) {
    3.         Vector3 offset = Vector3.zero;
    4.         offset.x = followAhead * Mathf.Sign(target.transform.localScale.x);
    5.         offset.y = followAbove;
    6.  
    7.         targetPosition = target.position + offset;
    8.  
    9.         transform.position = Vector3.MoveTowards(transform.position, targetPosition, Time.deltaTime * Smoothing);
    10.     }
    11. }
    FixedUpdate is a physics update, and steps at a fixed interval. Time.deltaTime is the time between Updates, which is not relevant in FixedUpdate.

    Depending on framerate, FixedUpdate can be called more than once, or not at all between Updates.

    Here I use LateUpdate so that the target can move during Update, and then the camera moves afterwards in LateUpdate.
     
    HerGiz likes this.
  6. Eziekieal

    Eziekieal

    Joined:
    Mar 12, 2015
    Posts:
    28
    So normally this is what my game looks like. It's kind of hard to see the shake with this quality gif, but look at the grass at the bottom when I stop moving.

    ~~~~~~~~~~~~~~~
    And using the script you provided the grass stops its little shaking, but the player starts to shake somewhat violently(My gif tool is too low of a quality to show it properly) when they walk. Similar to when I use my script in the normal Update function.
     
  7. LiterallyJeff

    LiterallyJeff

    Joined:
    Jan 21, 2015
    Posts:
    2,807
    Are you using any kind of pixel-perfect positioning code?

    I suppose you could try clamping the camera's position to a pixel coordinate to prevent sub-pixel positioning which may be causing that pixel-crawl problem.

    Code (CSharp):
    1. private void LateUpdate(){
    2.     // do camera movement, then...
    3.  
    4.    Vector3 roundedToPixel = camera.transform.position;
    5.  
    6.     roundedToPixel.x = (int)(roundedToPixel.x * PixelsPerUnit) / PixelsPerUnit;
    7.     roundedToPixel.y = (int)(roundedToPixel.y * PixelsPerUnit) / PixelsPerUnit;
    8.     roundedToPixel.z = (int)(roundedToPixel.z * PixelsPerUnit) / PixelsPerUnit;
    9.  
    10.     camera.transform.position = roundedToPixel;
    11. }
    You could also try this type of smoothing:
    Code (CSharp):
    1. private Vector3 vel; // put this variable at the class-level
    2. camera.transform.position = Vector3.SmoothDamp(camera.transform.position, targetPosition, ref vel, smoothing);
     
  8. Eziekieal

    Eziekieal

    Joined:
    Mar 12, 2015
    Posts:
    28
    I am using a pixel perfect code, I linked it in my first post (https://www.assetstore.unity3d.com/en/#!/content/64563).

    Sorry, I'm still a noob with this. Your first clip of code moves my camera at too large of intervals(The camera moves from A to B instantly and in large distances). Can't seem to change that.

    The second clip still has the shaking issue, sadly.
     
  9. LiterallyJeff

    LiterallyJeff

    Joined:
    Jan 21, 2015
    Posts:
    2,807
    I'm sorry my code snippet did not work for you, unfortunately I didnt have the opportunity to test it before I replied.

    You may have to do this:
    Code (CSharp):
    1. private void LateUpdate() {
    2.     // do camera movement, then...
    3.  
    4.     Vector3 roundedToPixel = camera.transform.position;
    5.  
    6.     roundedToPixel.x = ((int)(roundedToPixel.x * PixelsPerUnit)) / PixelsPerUnit;
    7.     roundedToPixel.y = ((int)(roundedToPixel.y * PixelsPerUnit)) / PixelsPerUnit;
    8.     roundedToPixel.z = ((int)(roundedToPixel.z * PixelsPerUnit)) / PixelsPerUnit;
    9.  
    10.     camera.transform.position = roundedToPixel;
    11. }
    All that is supposed to do is round the camera's position to the nearest pixel. If you have a PixelsPerUnit of 1, you just have to cast to an int, no math needed. This math should convert the position to pixels, round to an int, then convert back to Unity units to set the position.

    Apologies, I'm not very familiar with pixel-perfect stuff, but I know that shifting has a lot to do with sub-pixel positioning or using the wrong functions when updating camera position.
     
    Last edited: Nov 7, 2016
  10. Eziekieal

    Eziekieal

    Joined:
    Mar 12, 2015
    Posts:
    28
    Sorry for the delay.

    After messing with your code for a little while I was able to make it run without skipping large areas... but the shaking refuses to stop as the camera slows. Even while moving there's still a shake going on. This is turning into such a headache. Thank you for your help so far.

     
  11. LiterallyJeff

    LiterallyJeff

    Joined:
    Jan 21, 2015
    Posts:
    2,807
  12. Eziekieal

    Eziekieal

    Joined:
    Mar 12, 2015
    Posts:
    28
    Well this only sets the camera up to follow the player in a similar fashion of just setting the camera as the child of the player. It doesn't have the shaking issue, but the camera doesn't smoothly follow the player like I was wanting.
     
  13. LiterallyJeff

    LiterallyJeff

    Joined:
    Jan 21, 2015
    Posts:
    2,807
    You can try this with added smoothing, but I have a feeling it's the sub-pixel smoothed movement that causes the shaking. Verify that all your environment assets are at pixel-perfect positions, and try this modified version of that post.

    Code (CSharp):
    1. public GameObject player;
    2. public Camera main_camera;
    3. public float pixelToUnits = 40f;
    4. public float smoothTime = 2f; // approximate time it will take to reach the target
    5. private Vector3 velocity;
    6.  
    7. void Update() {
    8.     if(player != null) {
    9.         float player_x = player.transform.position.x;
    10.         float player_y = player.transform.position.y;
    11.  
    12.         float rounded_x = RoundToNearestPixel(player_x);
    13.         float rounded_y = RoundToNearestPixel(player_y);
    14.  
    15.         Vector3 new_pos = new Vector3(rounded_x, rounded_y, -10.0f); // this is 2d, so my camera is that far from the screen.
    16.         main_camera.transform.position = Vector3.SmoothDamp(main_camera.transform.position,new_pos, ref velocity, smoothTime);
    17.     }
    18. }
    19.  
    20. public float RoundToNearestPixel(float unityUnits) {
    21.     float valueInPixels = unityUnits * pixelToUnits;
    22.     valueInPixels = Mathf.Round(valueInPixels);
    23.     float roundedUnityUnits = valueInPixels * (1 / pixelToUnits);
    24.     return roundedUnityUnits;
    25. }
     
    ZiroSFR and davidcojo123 like this.
  14. davidcojo123

    davidcojo123

    Joined:
    Sep 8, 2021
    Posts:
    1
    I signed in just to thank you. Was having a similar problem to the guy above and your code solved it impeccably. Felt kinda sad when I saw that he didn't respond though, so I took it as a chance to thank you myself, thanks alot bro!!
     
    LiterallyJeff likes this.
  15. ZiroSFR

    ZiroSFR

    Joined:
    Nov 16, 2023
    Posts:
    1

    You are my hero, thanks a lot
     
    LiterallyJeff likes this.
  16. MelvMay

    MelvMay

    Unity Technologies

    Joined:
    May 24, 2013
    Posts:
    11,612
    Please don't necro threads, use the Like button to show appreciation.

    Thanks.
     
Thread Status:
Not open for further replies.