Moving a Rigidbody with MovePosition: Sometimes, it drifts

Hello,

I’m making a quite simple Brick Breaker game (= Arkanoid/Breakout Clone) and I move the object, that I use as a paddle, left and right on the X axis with the arrow keys.
The code is below.
It works fine … most of the time.
But sometimes, almost randomly, the paddle drifts. What I mean by this is that even though no key is pressed, it slowly moves to the left (or right).
Let’s say it moves to the left: even If I then press the right arrow key to move it to the right, as soon as I let the right arrow key go, it drifts to the left again.

If I then simply restart the game, it’s gone and often, I can play “forever” without it happening. But every so often, it happens again and only restarting the game (or loading the next level, which causes the paddle to get destroyed and reinstanciated in the next level) helps.

I suspected that maybe sometimes, depending on the angle the paddle is hit, the ball’s impact gives the rigidbody a force that causes it to move. But I don’t know how to counteract this. I tried giving the paddle a massive mass while the ball only has a mass of 1 but the problem remains. Also, shouldn’t it be gone then when I use the right arrow and change the direction?

Both the ball and the paddle have rigidbodies.
The ball is not kinematic and it’s frozen on the Z position. Mass is 1. Gravity is off, Interpolate is on and Collision Detection is Discrete.
The paddle’s rigidbody has the same properties but is also frozen on all the rotations and on the Y position and it has a mass of 1000000.

But maybe there’s an issue with my code and it has nothing to do with the ball’s impact?
I don’t really know, that’y why I’m here asking for your advice. Maybe someone knows what’s up? :slight_smile:

Oh, another detail: the paddle is a plane, with a child GO (a cylinder) on top of it. Both have colliders, although the ball only collides with the cylinder. The paddle is a plane because of the sprite I wanted to display and the cylinder is there so that the collider is convex. Both colliders don’t touch each other.

Code:

Movement of the paddle:

    void Update()
    {
        Vector3 moveInput = new Vector3(Input.GetAxisRaw("Horizontal"), 0, 0);
        moveVelocity = moveInput.normalized * speed;
    }

    private void FixedUpdate()
    {
       
        paddle_rigidbody.MovePosition(paddle_rigidbody.position + moveVelocity * Time.fixedDeltaTime);



    }

Reflecting the ball on impact:

 private void FixedUpdate()
    {
       
        // as collisions might absorb the velocity of the ball, we will want to force the speed to always be the defined speed of our variable, because we don't want the ball to become slower.

        ball_rigidbody.velocity = ball_rigidbody.velocity.normalized * speed;
        velocity = ball_rigidbody.velocity;

  private void OnCollisionEnter(Collision collision)
    {
        if (collision.collider.tag == "Death") // if ball collides with death wall, destroy it
        {
            GameManager.Instance.Balls--; // also, before destroying it, we want to remove one ball (life) from the ballcount (lives)
            Destroy(gameObject);
            GameManager.Instance.ballLostSFX.Play();
        }


        //**
        // when the gameobject hits another collider, we want it to be reflected and change its direction accordingly, depending at which angle it hits the collision object
        // Vector3.Reflect reflects a vector of the plane defined by a normal (the perpendicular angle of the impact)
        // As the normal, we use the first value of the collision.contacts array, as we only care for the very first impact
        //**



        ball_rigidbody.velocity = Vector3.Reflect(velocity, collision.contacts[0].normal);

       
    }

Many thanks in advance for any advice :slight_smile:

Might be controller drift: put Debug.Log() statements in to print out the value you’re using to move. If that’s so, don’t move if your input is below a certain absolute amount, like perhaps 0.1f or so.

Might be the Rigidbody having velocity: set the velocity to zero or mark it as isKinematic if you’re just going to be moving it yourself.

Hi! I doubt that it’s the controller as I had it on two different machines.

This, however, seems so obvious as a solution! :sweat_smile: I’ll try and see how it goes. It’s hard to reproduce the issue as I doesn’t know what makes it happen, but if I set it to Kinematic and don’t encounter it anymore in the dozends of playtesting hours I still have before me, I’ll be pretty convinced that this fixed it.

If it does come back though, I’ll try logging the inputs to see if something crazy is going on there. But as I said before, I doubt that it is the keyboards.

Thank you for your input :slight_smile:

ah, unfortunately, this is not a solution. While it might help with the drift, when the paddle is set to isKinematic, it won’t collide with my border walls anymore, which I use to keep the paddle inside the playing field.

Wouldn’t it take less time to add a Debug.Log() statement than to type the above? Then you wouldn’t DOUBT it, you would KNOW it. That’s how engineering works.

I offered two solutions there: set the velocity to zero OR set it to kinematic… you’ve ruled out the kinematic because you need the collisions (fair enough)… does setting the velocity to zero work?

“I doubt this rocket will blow up, it didn’t yesterday.” - said no aerospace engineer ever.

Its’s obvious the paddles are picking up some velocity. Kinematic is the way to go.

Just use a couple of fixed empty GameObject positions on either end of the paddles to control the limits of where it can move to, instead of collisions. Then you can Vector3.MoveTowards between them to move your paddle.

1 Like