Search Unity

The proper way for smooth 2D movement.

Discussion in '2D' started by TheWrightDev, Jan 11, 2014.

  1. TheWrightDev

    TheWrightDev

    Joined:
    Nov 25, 2013
    Posts:
    7
    So I was following the fantastic 2D tutorial made by pixelnest, but I noticed that it was kind of choppy. Every 2 seconds or so everything would seem to jump backwards one frame then go forwards again. i.e. it actually looks like it goes the wrong way for one frame then keeps going.

    I remade the project, stripped out everything and the issue still happens.

    The objects that move have a Box Collider 2d and a RigidBody 2d. But gravity is set to 0 and no forces are being applied.

    The movement is done like this:
    Code (csharp):
    1.    
    2. void Update()
    3. {
    4.     // 2 - Movement
    5.     Vector3 movement = new Vector3(
    6.         speed.x * direction.x,
    7.         speed.y * direction.y,
    8.         0);
    9.    
    10.     movement *= Time.deltaTime;
    11.     transform.Translate(movement);
    12. }
    13.  
    I have tried, FixedUpdate and LateUpdate. FixedUpdate makes it quite a bit worse and Late is about the same as just update.

    I've deployed to Android, Web, and Desktop and they all have the same little jump.

    I have the FPS script from the wiki, and the game runs solid at 60.3. If set it to "don't sync" it runs at about 411, and the choppyness is almost gone, but still visibile.

    Is there a better way I can use to move these objects for a simpler side scroller like this that doesn't have this choppyness.

    Thanks,
    Wright
     
  2. unitylover

    unitylover

    Joined:
    Jul 6, 2013
    Posts:
    346
    Rule of thumb when dealing with movement of rigidbody enabled objects: never use translate.

    Instead, set the velocity directly or use rigidbody2D.AddForce() to move around.
     
    robbiemaldrich likes this.
  3. TheWrightDev

    TheWrightDev

    Joined:
    Nov 25, 2013
    Posts:
    7
    Thanks for the response unitylover, I tried setting the velocity directly in Start() but that actually seemed to produce a even slightly jumpier result. Using the translate gave a much smoother gliding motion with jumps only every 2 seconds or so.

    I'm not having any issues with the collisions themselves...just the actual moving of the sprite.

    :(
     
  4. unitylover

    unitylover

    Joined:
    Jul 6, 2013
    Posts:
    346
    It would be nice to see a video demonstrating this behavior because I can't visualize the problem you're experiencing. Is the moving objects moving along the ground? Maybe a screenshot of your game view would help me help you.
     
  5. TheWrightDev

    TheWrightDev

    Joined:
    Nov 25, 2013
    Posts:
    7
    Here's a webplayer version of it: http://thewrightdev.com/Test/Build_Test.html

    Just track the ship with your eye and you will see it "jump" every so often.
     
  6. unitylover

    unitylover

    Joined:
    Jul 6, 2013
    Posts:
    346
    Wow, now that's funny! At first I didn't notice the issue but you're right, if you follow the sh ip with your eye it seems to lag back every so often. Are you using any kind of interpolation on the object? Can you post your inspector settings for the ship?
     
  7. zombiegorilla

    zombiegorilla

    Moderator

    Joined:
    May 8, 2012
    Posts:
    9,052
    Have you checked the profiler to see if there is anything else that may be causing it?
     
  8. TheWrightDev

    TheWrightDev

    Joined:
    Nov 25, 2013
    Posts:
    7
    @zombiegorilla - Unfortunately I don't have the pro version so I don't think I can look at that. But looking at the system resources there's no sort of spike or anything, pretty much dead flat.

    @unitylover - Hm, I tried turning on interpolate but it didn't really make any change at all? Here's the inspector: (I left the interpolate option on, but it was off originally).
    $6iCIq.png

    The move script itself:
    $6iCXd.png
     
  9. unitylover

    unitylover

    Joined:
    Jul 6, 2013
    Posts:
    346
    As an experiment remove the Time.deltaTime multiplication and increase your movement vector to compensate. I'm curious if the issue is something to do with frame speed.

    edit: And put the movement code inside a fixed update.
     
  10. negative_zero

    negative_zero

    Joined:
    Nov 14, 2013
    Posts:
    24
    I'm running into this too a bit, curious to know if it gets resolved.
     
    Ali_V_Quest likes this.
  11. bryantdrewjones

    bryantdrewjones

    Joined:
    Aug 29, 2011
    Posts:
    147
    This is a really complicated issue that you would run into with just about any game engine, and unfortunately there isn't a clear solution with Unity (unless you buy all of your customers those fancy G-Sync monitors). The core issue is that the update/render rate of your game isn't perfectly synced with your monitor's refresh rate. When the two fall out of sync, you'll notice the jitter.

    You might find this Unity Answers page helpful: http://answers.unity3d.com/questions/275016/updatefixedupdate-motion-stutter-not-another-novic.html.

    And this followup thread with a sample project: http://forum.unity3d.com/threads/162694-SmoothMovementTest-should-help-eliminate-Hiccup-sources.

    Here's another informative thread that touches on this issue: http://forums.tigsource.com/index.php?topic=32714.0.

    I remember there being a few other posts on TIGSource related to jittery movement, but that's the only link I had bookmarked. Sorry :(
     
    Last edited: Jan 15, 2014
    fadden likes this.
  12. TheWrightDev

    TheWrightDev

    Joined:
    Nov 25, 2013
    Posts:
    7
    @bryantdrewjones - Holy crap. Thanks for all the info...I guess I'll just have to make due for now.
     
  13. imaginaryhuman

    imaginaryhuman

    Joined:
    Mar 21, 2010
    Posts:
    5,834
    Is it possibly because of a floating point inaccuracy, like the delta time etc doesn't always exactly add up to 1.0 every second, and so it is very slightly out of sync with the exact 60hz refresh, and so once in a while when all those inaccuracies add up, a frame slightly misses the vertical blank because it's slightly too short or long, causes a 1-frame stall, and then resumes? Does it happen with vsync off? Is it possible to do something everyone few frames or something to re-sync it to 60hz to compensate? Like, if over the course of 1/2 a second, you add up all the delta times, and find out if it's exactly 0.5 seconds, and if not add/subtract the difference to the position?
     
    Last edited: Jan 16, 2014
  14. Damien-Mayance

    Damien-Mayance

    Joined:
    Sep 17, 2013
    Posts:
    11
    Hello, tutorial co-writer here.

    Thanks to some feedbacks we updated the scripts so we are now using rigidbody in the right way.
    The feeling is different but it's definitely less glitchy.

    The purpose of using Translate was to be more beginner friendly but it was a bad idea to show some bad practice :).

    Here's the new script, from http://pixelnest.io/tutorials/2d-game-unity/player-and-enemies/.

    Code (csharp):
    1.  
    2. using UnityEngine;
    3.  
    4. /// <summary>
    5. /// Player controller and behavior
    6. /// </summary>
    7. public class PlayerScript : MonoBehaviour
    8. {
    9.   /// <summary>
    10.   /// 1 - The speed of the ship
    11.   /// </summary>
    12.   public Vector2 speed = new Vector2(50, 50);
    13.  
    14.   // 2 - Store the movement
    15.   private Vector2 movement;
    16.  
    17.   void Update()
    18.   {
    19.     // 3 - Retrieve axis information
    20.     float inputX = Input.GetAxis("Horizontal");
    21.     float inputY = Input.GetAxis("Vertical");
    22.  
    23.     // 4 - Movement per direction
    24.     movement = new Vector2(
    25.       speed.x * inputX,
    26.       speed.y * inputY);
    27.  
    28.   }
    29.  
    30.   void FixedUpdate()
    31.   {
    32.     // 5 - Move the game object
    33.     rigidbody2D.velocity = movement;
    34.   }
    35. }
     
    Daedolon, AdmiralThrawn and awplays49 like this.
  15. MyLiaison

    MyLiaison

    Joined:
    Nov 18, 2016
    Posts:
    3
    Hello I am having similar problems here. I have a ball game and I gave velocity to my ball object at the start and let it find its own way with hitting objects in 2D space. Its vector is (6,6) for example. After hitting some objects it changes its velocity to (8.1, 2.7) for example. But if I start with (2,2) velocity I never faced with this problem. Issued vectors are 3,6,7,8,9 and with vector of (2,2) (2.5,2.5) (4,4) (5,5) (10,10) object move correctly. But if I start with (2,2) for example and increase the speed during the game to a working speed like (4,4) it again lost his way.

    private float ballSpeed = 3f;

    void Start ()
    {
    GameManager = GameObject.Find("GameManager");
    rb = GetComponent<Rigidbody2D> ();
    rb.velocity = new Vector3(ballSpeed,ballSpeed,0);
    Debug.Log(rb.velocity);
    }
    In the inspector of ball object Mass is 0.1, Gravity is 0, Interpolate=Interpolate, Collision Detection = Continuous, Linear and Angular Drag are 0.
    As I understand problem occur because of frames or frame rate something. Any idea would be nice and I will keep seaching the issue and for the solution.
     
  16. Chintan-Kansagara

    Chintan-Kansagara

    Joined:
    Jul 16, 2016
    Posts:
    19
    hello friends
    i am raycast to hit check and hit point to character movement in update but character not smoothly working
    plz help me.
    my Code :-
    void FixedUpdate ()
    {
    if (Input.touchCount > 0 && Input.GetTouch(0).phase == TouchPhase.Moved)
    {
    RaycastCheck();
    }
    void RaycastCheck()
    {
    Vector3 mousePos = Input.mousePosition;
    mousePos.z = 10;
    Vector3 screenPos = Camera.main.ScreenToWorldPoint(mousePos);



    RaycastHit2D[] hits;
    hits = Physics2D.GetRayIntersectionAll(Camera.main.ScreenPointToRay(Input.mousePosition),100);

    for(int i = 0; i < hits.Length ; i++)
    {

    if (hits != null /*&& hits != null && hits.collider != null && hits.collider.name.Contains(balloontype.name)*/)
    {
    if(hits.collider.tag == "Hero")
    {
    PlayerHit = true;
    }
    if(hits.collider.tag == "Wall")
    {
    WallHit = true;
    }
    else
    {
    WallHit = false;
    }
    }
    if(WallHit && PlayerHit == true)
    {

    gameObjectTodrag.transform.position = Vector3.MoveTowards(gameObjectTodrag.transform.position,hits.point,Time.deltaTime * 50f);

    }
    }
    }
     
  17. NikH

    NikH

    Joined:
    Dec 24, 2013
    Posts:
    14
    Four and a half years later and the solution still hasn't surfaced. Are there any Unity Store Assets that have projects with smooth object scrolling? That would be really handy..
     
  18. Wolk

    Wolk

    Joined:
    Jul 12, 2014
    Posts:
    59
    There's ufo asset tutorial, it's relatively smooth over small velocities.
     
  19. dharrison2010

    dharrison2010

    Joined:
    Apr 14, 2015
    Posts:
    3
    Not sure of everything you are doing, but you should not check for input in FixedUpdate() check for input in Update().
     
  20. Tonyhall3

    Tonyhall3

    Joined:
    Dec 17, 2012
    Posts:
    7
    As the script is controlling the movement of the object directly I would be inclined to say that the object should be set to kinematic.

    If you don't wish to set the object as kinematic then i'd suggest using the AddForce() method of the rigidbody to modify the objects position. You can also modify the rigidbody's velocity property but the docs do state to avoid using this if possible.

    I follow the above principles and can't say I've ever had a problem with smooth movement.