#Homing projectile that moves at a constant speed in 2D.

10 messages · Page 1 of 1 (latest)

merry terrace
#

I looked this up and found a promising video on creating a homing missile. The problem is that this projectile will slow down or stop to reroute itself. For example, if the projectile is shot to the right, but its target is to the left, instead of the projectile turning in a wide arc at a constant speed to navigate to its target, it'll instead come to a stop and turn around in place.

I provided a .GIF of what I'm looking to accomplish. Imagine the player is the green square. The projectile is the white pixels and its target is the red X. In order for it to reach its target at a constant speed, it must turn in a wide arc to get there. I want this, but I don't know how to achieve it.

Here's the current code I have:


var current_velocity = Vector2.ZERO
var turn_radius: float = 0.15

func _ready():
    current_velocity = proj_speed * Vector2.RIGHT.rotated(rotation)

func _physics_process(delta):
    if get_tree().get_nodes_in_group("Enemy").size() > 0 and target != null:
        dir = global_position.direction_to(target.global_position)
    else:
        dir = Vector2.RIGHT.rotated(rotation).normalized()
    
    var desired_velocity = dir * proj_speed
    var change = (desired_velocity - current_velocity) * turn_radius
    
    current_velocity += change
    
    position += current_velocity * delta
    look_at(global_position + current_velocity)```

So again, this *does* work. It *does* home into the target. However, it will not do so at a constant speed, and will allow itself to slow down and stop to turn instantly. I don't want the homing projectile to slow down or be able to turn on a dime.

Playing with the `turn_radius` doesn't seem to help, because once the projectile reaches its target, it stops. I want the projectile to be able to reach its target and be able to keep traveling and then reroute back to its target, like shown in the .GIF.
fiery cove
#

I have a turn to target function that turns something to a vector2 at a constant speed. Combine that with constant movement speed and I guess you have what you want?

mild remnant
#

The way I do this is to set an angle velocity in radians (actually set via export that is in degrees and convert to radians in code - easier to understand). Then with the angle velocity, I multiply this by delta, giving me that max change for the frame. Then figure out the angle difference between where the target is and what direction the projectile is traveling. Then turn the velocity vector in that direction, making sure only to do it by the max angle change previously calculated.

The important part is the use of lerp_angle(). Lerp angle handles the -180/180 degree boundary. If you don't use something like this function, the projectile will turn the wrong way to get back to the target sometimes and it will look weird.

I did a video on this a long time ago. It was for turrets, but I've used it for projectiles I think. Could be useful. https://youtu.be/jMk8Zm-F3jw?si=eAMJ6nU-9h9HEmTK

Hi guys! In this video I go over aiming a projectile from a turret. The code can be applied to ships or anything else that needs for spawn projectiles in your 2D Godot game.

This video is a continuation of my smooth look at video.
https://youtu.be/ciT_jDol9G8

This video uses the following sounds from freesound:
"Inside the Box Factory" by kj...

▶ Play video
fiery cove
mild remnant
#

Yep. that was me. Glad people are getting something out of it!

fiery cove
merry terrace
#

Wow, this is a lot more help than I was expecting checking back on this. I'll dive in and see what I can find out. Thank you both so much.

vocal shadow
#

You could just try normalizing the velocity vector (might not work though):

var current_velocity = Vector2.ZERO
var turn_radius: float = 0.15

func _ready():
    current_velocity = proj_speed * Vector2.RIGHT.rotated(rotation)

func _physics_process(delta):
    if get_tree().get_nodes_in_group("Enemy").size() > 0 and target != null:
        dir = global_position.direction_to(target.global_position)
    else:
        dir = Vector2.RIGHT.rotated(rotation).normalized()
    
    var desired_velocity = dir * proj_speed
    var change = (desired_velocity - current_velocity) * turn_radius
    
    current_velocity += change
    current_velocity = current_velocity.normalized()
    
    position += current_velocity * delta
    look_at(global_position + current_velocity)
merry terrace
#

Thank you for the advice.