How to implement variation in movement along a vector?

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

I have a flying enemy with very simple behavior. When the player is within range, it flies along the vector to the player.

The code looks like this

if state == "chase":
	vel = vector_to_player.normalized() * speed

The behavior looks like this:

enter image description here

I would like to introduce some variation into this movement so that it looks move like this:

enter image description here

Suggestions of how to do this?

It doesn’t have to be sinusoidal along the vector to the player. Eventually, I’d like to be able to handle curves of arbitrary complexity.

You could rotate the ship back and forth between, say, -20 and 20 degrees and then move it in that direction. Also look into tweens, that might work.

Joleeee | 2018-07-15 21:04

@Jolee that’s a good idea.

Instead, I thought you could use an angle to the target’s position and sum/subtract it by a quantity over time, but you’d have to recalculate the direction to the target to avoid going in the wrong direction.
It seems a bit cumbersome to me, but maybe it helps you.

DodoIta | 2018-07-16 08:43

I would like to help in the case, but I can’t see a simple solution. If the flying enemy must arrive at the position of the player, then there is a defined path to the player. To add variation to the movement of the flying enemy, the path has to be broken down, and the individual points (or the points of the vectors) have to be manually changed. Once they are manually changed, then the flying enemy has to follow that path to the player. So it could be broken down like this:

  1. Define a path to the player such that it is a finite number of points from the flying enemy to the player.
  2. In-between the start and end points, move the points up or down (depending on your requirements for the look of the movement).
  3. Draw a path between these points (maybe with a Curve2D).
  4. Move/Animate the flying enemy along this path.

If you believe I’m mistaken in my assessment, please point out the faults.

Ertain | 2018-07-16 23:42

:bust_in_silhouette: Reply From: Ertain

This may be too late, but I may as well post it here anyway.

The code I’ve written may be messy, but at least it demonstrates the point I made in my comment to Diet Estus’ original post:

  1. Define a path to the player such that it is a finite number of points from the flying enemy to the player.
  2. In-between the start and end points, move the points up or down (depending on your requirements for the look of the movement).
  3. Draw a path between these points (maybe with a Curve2D).
  4. Move/Animate the flying enemy along this path.

So in the code, you have these two functions, make_curvy_line_of_vectors() and move_along_path(). In the _process() function, I have these two functions used when the player gets near the flying enemy.

extends Node2D

var array_of_vectors = []
var curvy_line = Curve2D.new()
var curvy_vector_pool = []

func make_curvy_line_of_vectors(enemy, player):
    var prey = enemy.get_position()
    var predator = player.get_position()
    
    for i in range(0,2):
        # Create random points between the predator and the
        # prey
        var temp = predator.linear_interpolate( prey, randf() )
        var random_y = rand_range(-100.0, 100.0)
        # Randomly translate the vectors up and down the y-axis.
        temp.y += random_y
        # Append these vectors to the array of vectors.
        array_of_vectors.append(temp)
    
    # Make the first element in the vector array the position
    # of the predator
    array_of_vectors.push_front(predator)
    # Append the position of the prey at the end.
    array_of_vectors.append(prey)
    # Sort the vectors so that they are
    # in order.
    array_of_vectors.sort()
    array_of_vectors.invert()
    
    # place the points from the array of vectors
    # in the curve.
    for g in array_of_vectors:
        curvy_line.add_point(g)
    
    # Get a PoolVector2Array from the curve.
    curvy_vector_pool = curvy_line.tessellate()

# Based upon official "navigation" demo
func move_along_path(distance, predator):
    var last_point = predator.get_position()
    for thing in range( curvy_vector_pool.size() ):
        var distance_between_points = last_point.distance_to( curvy_vector_pool[0] )
        if distance <= distance_between_points and distance >= 0.0:
            predator.position = last_point.linear_interpolate( curvy_vector_pool[0], distance / distance_between_points )
            break
        elif distance < 0.0:
            predator.position = curvy_vector_pool[0]
            # I'm iffy on this part.
            set_process(false)
            break
        distance -= distance_between_points
        last_point = curvy_vector_pool[0]
        curvy_vector_pool.remove(0)

In the _process() function:

func _process(delta):
    if pursue_player:
        if curvy_vector_pool.size() == 0:
            make_curvy_line_of_vectors($bird, $player)
        var distance = 200.0 * change_in_frame
        move_along_path(distance, $enemy)

Hope this works for you. To further demonstrate my point, here’s a complete project on the Github.