2
\$\begingroup\$

I am making a Top-Down shooter in Godot 3.0 on Linux.

I would like to have my character rotate to face the mouse-pointer at a constant speed, and have rotation speed power-ups that allow the player turn faster.

So far, this is done by having a Position2D object called "Center" share the same position (but not be a child of) the player (below just called "Sprite"). The center always looks to the mouse, and the Sprite rotates with linear interpolation to eventually reach the same rotation as the "Center".

The weight of linear interpolation is calculated by dividing the difference in rotation (in radians) by an arbitrary constant speed.

Problem: The speed of rotation increases as rotation occurs, or more specifically, the time it takes to reach the same rotation (a rotational difference of zero) becomes shorter over time.

I have the following code:

extends Sprite

onready var center = get_parent().get_node("Center")

var current_time = 0
var total_time = 0
var start_rot = 0
var end_rot = 0


func _process(delta):
    center.look_at(get_global_mouse_position())
    var amt = 0
    var theta = abs(self.rotation - center.rotation)
    var speed = 0.05

    total_time = theta/speed

    start_rot = get_rotation()
    end_rot = center.rotation

    if not total_time == 0:
        amt = current_time/total_time

    current_time += delta
    amt = clamp(amt,0,1)
    var rot = lerp(start_rot,end_rot,amt)
    center.rotation = fmod(rot,(PI*2))
    set_rotation(fmod(rot,(PI*2)))

    get_parent().get_node("Control/rotation").text = str(int(self.rotation_degrees))
    get_parent().get_node("Control/theta").text = str(theta)
    get_parent().get_node("Control/time").text = str(total_time)

What am I doing wrong?

\$\endgroup\$
1
  • 1
    \$\begingroup\$ I have no way to test this now as I'm on my phone (and I'm not familiar with Godot), but wouldn't you need to use only something like set_rotation(get_rotation()+min(theta, speed)), assuming speed is the maximum angle you can turn per frame? \$\endgroup\$
    – Vaillancourt
    Commented Sep 20, 2018 at 2:34

3 Answers 3

1
\$\begingroup\$

A simple solution would be to get the angle to the target and then just rotate counter-clockwise if the angle is negative and clockwise if it's positive:

func _physics_process(delta):
    var angle = get_local_mouse_position().angle()
    if angle < 0:
        rotate(-angular_speed*delta)
    elif angle > 0:
        rotate(angular_speed*delta)

You also have to decrease the angular speed when the angle gets close to 0, otherwise it would jitter:

    if abs(angle) < .3:
        angular_speed = abs(angle / .3)
    else:
        angular_speed = 1
\$\endgroup\$
1
\$\begingroup\$

@skrx "+1" Thanks!

I wasn't able to make get_local_mouse_position().angle_to_point(position) work as intended, but using your method of angular speed, I was able to rework it to suit my purposes:

func _physics_process(delta):
    center.look_at(get_global_mouse_position())

    var angular_speed = 2
    var angle = rotation - center.rotation
    angle = fmod(angle,PI*2)
    center.rotation = fmod(center.rotation,PI*2)

    rotation = fmod(rotation,PI*2)
    if abs(angle) > PI :
        angle = -angle
    if abs(angle) > .05:
        if angle > 0:
            rotate(-angular_speed*delta)
        elif angle < 0:
            rotate(angular_speed*delta)
\$\endgroup\$
1
  • 1
    \$\begingroup\$ Great that you've found a solution! There was a mistake in my answer (you just need the get_local_mouse_position().angle()). Please check out if the edited version works. \$\endgroup\$
    – skrx
    Commented Sep 20, 2018 at 20:01
0
\$\begingroup\$

@skrx Not only does this work, this actually shortens the code!

This allows removing the fmod adjustments, and the if statement used to change the rotational direction past its half-way point, only rotating the shortest distance, and removes the use of Center entirely!

I did have to change the &gt and &lt symbols back to your original orientation (I had to switch them for my rotation difference method to work)

The new code is as follows, and works exactly as intended, thanks again!

func _process(delta):
    var angular_speed = 2
    var angle = get_local_mouse_position().angle()
    if abs(angle) > .05:
        if angle < 0:
            rotate(-angular_speed*delta)
        elif angle > 0:
            rotate(angular_speed*delta)
\$\endgroup\$

You must log in to answer this question.

Not the answer you're looking for? Browse other questions tagged .