'move an object towards a target but in a sine wave

unity2d and by ship I mean spaceship. so I have my ship which I want to move to a specific target, but I want it to be in a sin wave so it bounces up and down, I've watched plenty of youtube tutorials but I still do not understand how to integrate it into my code.

transform.position = Vector2.MoveTowards(transform.position, shipTarget, Time.deltaTime * shipSpeed) ;


Solution 1:[1]

Assuming the spaceship is moving towards the direction transform.position - shipTarget and the oscillation in the direction perpendicular to the straight motion which takes the path of a sine wave, the position of the spaceship has to update in both the directions.

Let's have some variables for the speed of the spaceship that translates into a straight line, the amplitude and frequency of the sine wave, and finally the direction of the spaceship.

private float speed = 1f;
private float amplitude = 1f;
private float frequency = 1f;
private Vector2 straightDirection = (transform.position - shipTarget).normalized; // magnitude = 1
private Vector2 perpendicularDirection = GetPerpendicularDirection(straightDirection);

Vector2 GetPerpendicularDirection(Vector2 direction) {
    return new Vector2(-direction.y, direction.x);
}

Player movement towards the target:

Vector2 horizontal = straightDirection * speed * Time.deltaTime;

Player movement in perpendicular direction:

Vector2 vertical = perpendicularDirection * Mathf.Sin(frequency * Time.time) * amplitude;

Explaining it a bit, Mathf.Sin(float) takes in a floating-point value (which in this case is the total time elapsed since the start of the script, i.e. Time.time) in radians. Multiplying it with a frequency affects the sine wave's distance between two consecutive crests or troughs. More the frequency, less the distance between two consecutive crests and troughs. Mathf.Sin(float) reaches a maximum value of 1. Likewise, Mathf.Sin(float) * amplitude reaches a maximum value of amplitude.


Summing up, update the transform of the spaceship every frame by calling it in the Update() function.

private void Update() {
    transform.position = horizontal + vertical;
}

Solution 2:[2]

This script solves the problem. The Mathf.Sin function rotates a variable with angular motion in the period 0 to 2 * pi between -1 to 1. Adding this method to the original location is the key. Just Add this to your object and select target in the inspector. you can move target and see result.

public class SinusMove : MonoBehaviour
{
    private float cycle; // This variable increases with time and allows the sine to produce numbers between -1 and 1.
    private Vector3 basePosition; // This variable maintains the location of the object without applying sine changes

    public Transform target;
    
    public float waveSpeed = 1f; // Higher make the wave faster
    public float bonusHeight = 1f; // Set higher if you want more wave intensity
    public float speed = 1f; // more value going faster to target
   
    public void Start() => basePosition = transform.position;

    void Update()
    {
        cycle += Time.deltaTime*waveSpeed;
    
        transform.position = basePosition + (Vector3.up*bonusHeight) * Mathf.Sin(cycle);
    
        if (target) basePosition = Vector3.MoveTowards(basePosition, target.position, Time.deltaTime * speed);
    }
}

Remember that the script name and the file match, and also comment if there is a problem.

enter image description here

Sources

This article follows the attribution requirements of Stack Overflow and is licensed under CC BY-SA 3.0.

Source: Stack Overflow

Solution Source
Solution 1
Solution 2