How to make a rigid body 2D move to the cursor on command (and have it accelerate/deceleate and turn gradually)

:information_source: Attention Topic was automatically imported from the old Question2Answer platform.
:bust_in_silhouette: Asked By RTSmike

Hello! Im a beginner here, and trying to make a stellaris-like rts as my first game. Making spaceships a kinematic body didn’t quite satisfy me (bcuz acceleration and decelration have to be handled manually, and even then arent perfect), so I want to learn to use rigid bodies. So far I`ve been trying to get it to move to the cursor, and left its rotation (and turning) for later:

func move(delta):
if Input.is_action_pressed("follow"):
	target = get_global_mouse_position()
velocity = position.direction_to(target) * speed
apply_central_impulse(velocity * delta)

But it doesn’t work too well, either. The ship (from a standstill) doesn’t move straight to the target (though it accelerates smoothly, at least), but takes sort of a curved path, and then orbits around the target, oscillating back and forth. I also want it to decelerate before it arrives at the target, so that it wouldn’t overshoot, and I would usually try to do that by inverting velocity or applying negative impulse, but seeing how curved the path is… As well as that, I want it to make smooth turns, but when I tried applying torque impulse, it turned into quite a mess, so I chose to ask for help instead. Any help appreciated :slight_smile:

I would actually recommend not using rigid bodies as it is actually easier to control kinematic bodies. Implementing acceleration and deacceleration is not difficult.

Anyway, moving the node is easy. If you can’t do that, look up some youtube tutorials.

But as far as moving to a target, you might considering something like this:

Note that I haven’t tested this so there might be bugs, but hopefully it’ll give you an idea or two!

extends KinematicBody2D

# when we are 1 pixel away from the target. depends how large your bodies are.
const ACCEL = 10 # add this to velocity every second.
const MAX_VELOCITY = 100 # clamp velocity to this to prevent accelerating indefinately
var velocity := Vector2()
var is_following := false
var target_node = null
func set_follow_target(node:Node):
    target_node = node
    is_following = true

func _process(delta:float):
    if is_following:
        var dist_to_target = global_position.distance_to(target_node.global_position)
        if dist_to_target <= TARGET_REACHED_THRESHOLD:
            is_following = false
            var direction = global_position.direction_to(target_node.global_position)
            velocity += direction * ACCEL * delta

func _physics_process(delta):
    if velocity.length() > MAX_VELOCITY:
        velocity = velocity.normalized * MAX_VELOCITY

creativeape | 2022-08-27 23:49

Hmm, this looks promising. I’ve done smth similar, but your seems better - the turns are gradual, and all left to to do is to add deceleration and rotation. I’ll tinker with it and update later. Thx for the reply

RTSmike | 2022-08-29 05:12

:bust_in_silhouette: Reply From: zenbobilly

You can easily do this with tween and parallel () functions. There’s a YouTube video about it somewhere with code like the following:

`var tween := create_tween ().set_trans (Tween.TRANS_QUINT).set_ease (Tween.EASE_IN_OUT)
tween.tween_property (self, “global_position”, get_global_mouse_position (), 1.0)

var target_rotation := global_position.direction_to (get_global_mouse_position()).angle () + PI / 2.0
tween.parallel ().tween_property (self, “rotation”, target_rotation, 0.5)`

That code was ripped from the video, so if it doesn’t work…

Thx for the reply, Ill look into tweens. Gonna try and find the vid u mention

RTSmike | 2022-08-29 05:09