Rigidbody2D with freeze rotation stutters when manually rotated.

I have a rigidbody2D with interpolation and freeze rotation on, and I’d like to manually rotate the rigidbody. Since MoveRotation doesn’t work when the rotation is frozen, I’m using the RigidBody2D.rotation field itself. Here’s my movement code below:

private void FixedUpdate() {
    rb2D.rotation += turnSpeed * Time.fixedDeltaTime;
}

However, I’ve noticed that this causes stuttering in the latest unity versions (v2022.2) compared to older versions like (v2017). Does anyone know how to fix this?

I noticed disabling rotation freeze and using MoveRotation fixes the stuttering, but then objects are now free to rotate when they collide, which is behavior I’d like to avoid.

Have you turned on Interpolation for this rigidbody?

Yeah interpolation is on

Could you attach video? and setup of your object? I am not sure I am able to reproduce it.

I’m thinking instead of freezing the rotation, you should just super control it. And when you do want to rotate, just have that as an offset.

I’m using RigidBody2Ds to control 2D spaceships in game.

Here’s a snippet relating to ship movement code:

    protected virtual void FixedUpdate()
    {
        if (Turning)
            Turn();
        else
            Move();
    }

    protected virtual void Update()
    {
    }

    public virtual void Turn()
    {
        var turnSpeed = statContainer.GetStatValue("turnSpeed").Amount;
        if (turnSpeed > 0)
            rb2D.rotation += turnSpeed * Time.fixedDeltaTime;
    }

    public virtual void Move()
    {
        float accelerationMultiplier = 0;
        var currentSpeed = statContainer.GetStatValue("speed").Amount * currentSpeedMultiplier;
        if (currentSpeed > 0)
        {
            accelerationMultiplier = 1 - (rb2D.velocity.magnitude / currentSpeed);
            accelerationMultiplier = accelerationMultiplier < 0 ? 0 : accelerationMultiplier;
        }
        rb2D.AddRelativeForce(Vector2.up * 555 * accelerationMultiplier * Time.fixedDeltaTime);
    }

And here’s the relevant code for my camera controller which keeps all ships in view at all times. I doubt it’s a camera issue though, as I’m able to observe it in the scene view.

    private void LateUpdate()
    {
        if (followTargets && targets.Count > 0)
        {
            SmoothDampCameraToTargetsCenter();
        }
    }

    public void SetCameraToTargetsCenter()
    {
        position = TargetsCenter;
        size = TargetsOrthoSize;

        transform.position = position;
        cam.orthographicSize = size;
    }

    public float TargetsOrthoSize
    {
        get
        {
            var bounds = TargetsBounds;

            //horizontal size is based on actual screen ratio
            float minSizeX = minSize * Screen.width / Screen.height;

            //computing the size
            float camSizeX = Mathf.Max(Mathf.Abs(bounds.extents.x + buffer), minSizeX);
            return Mathf.Max(Mathf.Abs(bounds.extents.y + buffer), camSizeX * Screen.height / Screen.width, minSize);
        }
    }

    public Vector4 TargetsCenter
    {
        get
        {
            var bounds = TargetsBounds;
            return new Vector3(bounds.center.x, bounds.center.y, -10);
        }
    }

    public Bounds TargetsBounds
    {
        get
        {
            if (targets.Count == 0)
                return new Bounds();

            var bounds = new Bounds(targets[0].transform.position, Vector3.zero);
            for (int i = 1; i < targets.Count; i++)
                bounds.Encapsulate(targets[i].transform.position);

            return bounds;
        }
    }

    public void SmoothDampCameraToTargetsCenter()
    {
        position = TargetsCenter;
        size = TargetsOrthoSize;

        transform.position = Vector3.SmoothDamp(transform.position, position, ref velocity, (distanceDampingOverride ? 1 : Vector3.Distance(transform.position, position)) * movementSmoothTime);
        cam.orthographicSize = Mathf.SmoothDamp(cam.orthographicSize, size, ref velocity2, (distanceDampingOverride ? 1 : Vector3.Distance(transform.position, position)) * zoomSmoothTime);
    }

My current hacky solution is to disable freeze rotation when the player is rotating, and then use MoveRotation to apply the rotation. This means for the most part, forward movement isn’t going to be affected by rotation applied by other colliders. I guess this is, in a way, similar to what @wideeyenow_unity suggested.

Here’s a video comparison of the issue in game. Please observe the orange ship for the stuttering effect:

Original - Stuttering

Hacky Solution - No Stutter