Smoothly rotating CharacterBody2D relative to mouse cursor

Godot Version

v4.5.stable.mono.official [876b29033]

Question

This is in context of 2D top-down game, where player sees everything from above. This is somewhat extension of topic I’ve made earlier, but I think snapping to it instantly using LookAt doesn’t look as good as I’ve expected.

I want player character to face the mouse cursor, but not snap to it instantly, just smoothly slowly rotate to proper position.

This is what I’ve managed to come up with:

Vector2 direction = GetGlobalMousePosition() - GlobalPosition;
float targetRotation = direction.Angle();
Rotation = Mathf.MoveToward(Rotation, targetRotation, Mathf.Pi / 32);

It partially works, but has two problems:

  • Player character doesn’t face the cursor from the front, but from the right side.
  • Sometimes player instead of rotating just a little, does 360 degrees spin.

The first issue comes from the fact that engine considers front of the character to be x = 1 y = 0. For me front of the character is x = 0 y = -1. I don’t know how to compensate for it.

The second issue comes from the fact that at very specific radian value is some kind of deadzone that engine doesn’t like, and instead of going past that point, it just goes around. Again, I don’t know how to solve it.

I’ve made a sketch to show the issue. Left is expected behavior, right is real behavior, and image how player character (the triangle thingy) looks like on Godot 2D axes:

If you want a smooth approach you can use the lerp()-method.

to get the correct angle you can just call:

GlobalPosition.angle_to(GetGlobalMousePosition) - Pathf.Pi/2 # - pi/2 to consider the front of the camera

# either move_toward or lerp
Rotation = Mathf.Lerp(Rotation, targetRotation, 0.1);
1 Like

You can also use Node2D built-in function look_at() directly, if you don’t need the smoothing of rotation. It’s pretty simple in that case.

I don’t know what to do with the first line, it looks like a mix of GDScript and C#, and Pathf doesn’t even exist (was it supposed to be Mathf?)

I’ve used your second line to replace Mathf.MoveToward and behavior is exactly the same (except it might be a little more smooth).

Yes it was a typo, its supposed to be Math.Pi

is it still offset by 90 degrees?

About the problem with going around the wrong way: the issue is that you are setting the rotation, instead you should add/subtract the difference in angles

1 Like

I’ve changed my code to this based on your suggestions:

Vector2 direction = GetGlobalMousePosition() - GlobalPosition;
float targetRotation = direction.Angle();
Rotation = Mathf.LerpAngle(Rotation, targetRotation, 0.1f);

And it works. But still off by 90 degrees. Every attempt at compensation leads to infinite spinning.

Edit

I’ve added + Mathf.DegToRad(90); to 2nd line and all of it just works.

Rotate the visual representation you have under character body manually by 90 deg.

This topic was automatically closed 30 days after the last reply. New replies are no longer allowed.