Game NPC "Guide" Movement (Much like Navi from Zelda)

What I’d like to accomplish is a fluid, seemingly (or maybe actually) random movement from the guide object around the the height of the player’s head. Something very similar to Ocarina of Time’s Navi. Her flight patterns seem very procedural, something I would like to do as well.

I can think of a couple of ways to tackle this, but none of which seem elegant:

  • Animation based “up and down” and lerp between points (creating the bobbing effect while moving)
  • Basing waypoint distance values at ‘x’ amount from the player, and making the movement lerp both towards the waypoint and up and down

So, what would be a good way to approach this? I feel that there is a good formula out there that could accomplish a float-y up and down movement.

For the random distance movement, I’m leaning towards randomly choosing a point within a certain distance of the player and at a certain range away from the previous position. All points being relative to the player, of course.

So the solution to this is very very simple, and is broken down into the parts I’ve outlined above. The one thing I tend to neglect is utilizing trig functions!

For this particular effect, a sine wave works perfectly:
alt text

This is the curve in which the bobbing up and down will work. We’ll be working in one plane - zy.
Here’s an example of that (with the no clear flag turned off on the camera so you can see the path):

So here’s some variables we’ll need to define:

/// <summary>
/// Average value, offset from zero. 
/// This is the point at which the object will float around (on the y - axis)
/// </summary>
public float z = 0;

/// <summary>
/// Amplitude, this is how high and low the curve will go
/// </summary>
public float a = 1;

/// <summary>
/// Angular Frequency, this is how fast it will traverse the curve
/// </summary>
public float b = 3f;

/// <summary>
/// Phase Angle, check back for more details *I still don't really know myself*
/// </summary>
public float c = .5f;

/// <summary>
/// this is how far the curve has been traversed
/// </summary>
public float x = .01f;

These will all work in our sine wave function: y = z+ a * sin(bx + c)
Which we will apply in code:

	/// <summary>
	/// Late Update to smooth out our movement. This is very rough.
    /// The first step is move to the target, and then to bob up and down
    /// The last step to to move forward on the wave by increasing the x
	/// </summary>
	void LateUpdate () 
    {

        MoveToPoint();
        //y = z+ a * sin(bx + c)
        this.transform.localPosition = new Vector3(this.transform.localPosition.x, 
                                    (z + a * Mathf.Sin(b*x + c)),
                                    this.transform.localPosition.z);
        x += Time.smoothDeltaTime;
    }

It is VERY IMPORTANT TO NOTE that the way this script works is to be on an sub object. So the hierarchy would be like this:

And the movement code would be as follows:

public void MoveToPoint ()
    {
        if (target == null)
            return;
        transform.parent.position = Vector3.Slerp(transform.parent.position, target.position+Vector3.up*2, speed);
    }

This script will work, but are some important improvements to make - combining the sine wave formula with the follow formula. This is a good base, so good luck!