Need help with shuttering movement on platforms

Hey guys,

I have this problem where the character doesn’t move exactly like he should on moving platforms. Its jerky and slow. here take a look:
http://tinypic.com/player.php?v=2mo57yh>&s=9#.V0yopZMrLdQ

movement portion of the player script is:

 float h = (Input.GetAxisRaw("Horizontal"));

            //movement
           _rb2d.AddForce((Vector2.right * speed) * h);
            //limiting the speed of the player
            if(_rb2d.velocity.x > maxSpeed)
                _rb2d.velocity = new Vector2(maxSpeed, _rb2d.velocity.y);
            if(_rb2d.velocity.x < -maxSpeed)
                _rb2d.velocity = new Vector2(-maxSpeed, _rb2d.velocity.y);
           
            //calls animation
            _isWalking = Mathf.Abs(h) > 0;
            _anim.SetBool("IsRunning", _isWalking);

            //make the character face the right direction
            if(h < 0 && !_isFacingRight)
                Flip();
            else if (h > 0 && _isFacingRight)
                Flip();

and the platform script is:

    void Start ()
    {
        current = GetComponent<Transform>();

        if(aniType == AnimationType.MoveToPos)
            MoveToPos();
    }

    void MoveToPos()
    {
        current.DOMove(endPosition.position, duration, false).SetEase(Ease.Linear).SetLoops(-1, LoopType.Yoyo);
    }

    void OnTriggerStay2D (Collider2D col)
    {
        col.transform.parent = this.transform;
    }
    void OnTriggerExit2D (Collider2D col)
    {
            col.transform.parent = null;
    }

Are you using any physic materials on the platforms? or it could be a performance thing, have you profiled your game?

Thanks for responding. Yea I already tried different physics material and its not the performance thing.

Try Enter instead of Stay. Also debug the collision events. It shouldn’t be showing these messages while walking.

    void OnTriggerEnter2D (Collider2D col)
    {
        col.transform.parent = this.transform;
        Debug.Log("Enter trigger");
    }
    void OnTriggerExit2D (Collider2D col)
    {
            col.transform.parent = null;
            Debug.Log("Exit trigger");
    }

Hi,

I see that you are using DOTween to move your platform:

 current.DOMove(endPosition.position, duration, false).SetEase(Ease.Linear).SetLoops(-1, LoopType.Yoyo);

The problem is likely that DOTween interpolates on Update and not on FixedUpdate (any physics related computation should be done in FixedUpdate). I could not found this in the documentation, so I’ve made the following test to figure it out:

using UnityEngine;
using DG.Tweening;

public class DOTweenTest : MonoBehaviour
{

    void Start()
    {
        this.transform.DOMove(Vector3.forward, 100.0f ).OnUpdate( DOTweenUpdate );
    }

    void DOTweenUpdate()
    {
        Debug.Log(string.Format("D t={0:00.000} dt={1:0.000}", Time.time, Time.deltaTime));
    }

    void Update ()
    {
        Debug.Log(string.Format("U t={0:00.000} dt={1:0.000}", Time.time, Time.deltaTime));
    }

    void FixedUpdate()
    {
        Debug.Log(string.Format("F t={0:00.000} dt={1:0.000}", Time.time, Time.deltaTime));
    }
}

Maybe there is a way to tell DOTween to interpolate on FixedUpdate, but I could not find anything in the documentation about that (I did a quick search though, I could have missed it).

I’ve posted a message on the DOTween thread in that regard:
http://forum.unity3d.com/threads/dotween-hotween-v2-a-unity-tween-engine.260692/page-46#post-2656702

Edit:
Also:

  current.DOMove(...)

Changes the position on the transform, which is ignored my the physics engine. Instead, use Rigidbody.MovePosition (or the eventual DOTween equivalent).

Meanwhile,

You might be interested to use Panda BT to handle your platforms (or other game elements, it’s an AI tool). You can choose to update the logics on FixedUpdate. There is an option (“Tick On”) for that on the PandaBehaviour component.

With Panda BT, you could easily design more complex movements: like having the platform following a path or being activated by a switch or only when the character is on it…

For instance the yoyo platform BT script would be:

tree("Root")
    sequence
        MoveForward
        MoveBackward

and here are the implementations of the tasks: MoveForward and MoveBackward:

using UnityEngine;
using Panda;

public class YoyoPlatform : MonoBehaviour
{
    public float duration;
    public Transform end;

    new Rigidbody rigidbody;

    Vector3 startPosition;
    float t;
    void Start()
    {
        startPosition = this.transform.position;
        rigidbody = GetComponent<Rigidbody>();
    }

    [Task]
    void MoveForward()
    {

        if (Task.current.isStarting)
            t = 0.0f;

        t += Time.deltaTime;
        rigidbody.MovePosition( Vector3.Lerp(startPosition, end.position, Smooth()) );

        if (t > duration)
            Task.current.Succeed();
    }

    [Task]
    void MoveBackward()
    {
        if (Task.current.isStarting)
            t = 0.0f;

        t += Time.deltaTime;
        rigidbody.MovePosition( Vector3.Lerp(end.position, startPosition, Smooth()) );

        if (t > duration)
            Task.current.Succeed();
    }

    float Smooth()
    {
        return Mathf.SmoothStep(0.0f, 1.0f,t / duration);
    }
}

More info on Panda BT here:
http://www.pandabehaviour.com/

Let me know whether you want to explore this solution further.

Really awesome. Thanks again Eric I have tried changing the platform to use FixedUpdate with moveposition and fixed the problem. I’ll research a bit to see if Dotween can use FixedUpdate or not.

I think another option is to use character controller so the character won’t be using rigidbody i think.

It is possible (it is documented). It can be done with SetUpdate( UpdateType.Fixed ).

The character controller would be a good alternative. It does not simulate physics indeed (but it has a rigidbody for collission detection). Though, I don’t know how that would work with moving platforms, the character might glide over the platform. If that happen you can always add the platform displacement to the character position so that the character move with the platform while the character is on the platform.

Great. Thanks for the info on Dotween. I did try it out but I’m still getting the stuttering effect.
This is the change I did

        _current.DOMove(endPosition.position, duration, false).SetEase(Ease.Linear).SetLoops(-1, LoopType.Yoyo).SetUpdate(UpdateType.Fixed);

Its funny because Rigidbody.MovePosition worked perfectly how I wanted it but this doesn’t work. I also tried the test script that you provided to see if theres any difference between DOtweens Fixed and the default FixedUpdate and its the same result.

So I messed around some more and tried using just the plug in. Oddly it works perfectly with the same exact settings I’m using.
2660191--187545--upload_2016-6-1_23-3-59.png

The update code is this:

_current.DOMove(endPosition.position, duration, true).SetEase(Ease.Linear).SetLoops(-1, LoopType.Yoyo).SetDelay(0f);

It looks the same but it doesn’t behave the same way. The code version is still stuttering.

I would like to PM you, but it seems you’ve toggled this option off.

I’ve also noticed a perceivable difference between Update and FixedUpdate. But this is not related to DOTween.
By default, the fixed time step (deltaTime) is 0.02 second, which is 50 fps. Update runs at a higher (for me about 90 fps) and with a variable deltaTime around ~0.011 seconds. That difference can be perceived.

Maybe you can just try to decrease the fixed time step (Edit > Project Settings > Time), which will make FixedUpdate to run more often.

Thanks and I just tried it. ts definitely better but still stuttering. I might just change my character to not use rigidbody. That seems like the easiest solution for me.

Hi all :slight_smile:

First of all, @ericbegue is totally right about using SetUpdate for fixed timesteps, but the main issue is that you’re using DOMove on a transform instead than on a rigidbody, so you’re changing the transform’s position rather than going through rigidbody’s MovePosition.

Just use your rigidbody as the target and it will be solved, since in that case the shortcut applies a MovePosition in the background.

rigidbodyReference.DOMove(endPosition.position, duration, false)
   .SetEase(Ease.Linear).SetLoops(-1, LoopType.Yoyo).SetUpdate(UpdateType.Fixed);

Cheers.

P.S. With the Pro it worked because in that case the component makes an automatic check before runtime to see if your target has a rigidbody, which doesn’t happen when creating the tween via code (because it would be bad for performance)

OK awesome. Thanks for the response Izitmee. I’ll try it out after work and will let you know.

It worked! I played around with a bit but theres a bit of a problem where the character slightly shifts back and forth when the platform is moving so when he’s standing on the edge he can fall off even though he’s not moving at all.
http://tinypic.com/player.php?v=ehgqs5>&s=9#.V1Dhbb4rIo8

Great! The slight shift back/forth should be due to the platform’s physics influencing the motion of your character. I guess your character is not being tweened in your video, and that’s just the platform pushing him around?

yep thats right. Is there anyway to make the character not move?

I assume you mean: not moving relative to the platform.

I see two approaches to solve this problem, depending on whether you use physics or not.

With physics:
Increase the friction of both the character and the platform to overcome/counterbalance the momentum of the character.

With kinematics:
Add the displacement of the the platform to the position of the character (similar effect as parenting the character to the platform).

1 Like

Great. Thanks Eric. I did increase the friction before but I guess it was too little. I increased it again even more and it fixed the problem.