How To: Script the Camera to Follow a Curve

This example demonstrates how to use the Curve and CurveKey classes to script the movement of the camera.

Using Curves allows a path to be defined by a small number of control points with the Curves calculating the points on the path between the control points.

The Complete Sample

The code in this tutorial illustrates the technique described in the text. A complete code sample for this tutorial is available for you to download, including full source code and any additional supporting files required by the sample.

To script camera movement

  1. Create an instance of the Curve class for each component being scripted. In this case, two sets of three curves will be needed, one for each of the x, y, and z components of the camera's position and of the position the camera is looking at (the "look-at" position).

    class Curve3D
        public Curve curveX = new Curve();
        public Curve curveY = new Curve();
        public Curve curveZ = new Curve();
    Curve3D cameraCurvePosition = new Curve3D();
    Curve3D cameraCurveLookat = new Curve3D();
  2. Set the PreLoop and PostLoop type of each Curve. The PreLoop and PostLoop types determine how the curve will interpret positions before the first key or after the last key. In this case, the values will be set to CurveLoopType.Oscillate. Values past the ends of the curve will change direction and head toward the opposite side of the curve.

    curveX.PostLoop = CurveLoopType.Oscillate;
    curveY.PostLoop = CurveLoopType.Oscillate;
    curveZ.PostLoop = CurveLoopType.Oscillate;
    curveX.PreLoop = CurveLoopType.Oscillate;
    curveY.PreLoop = CurveLoopType.Oscillate;
    curveZ.PreLoop = CurveLoopType.Oscillate;
  3. Add CurveKeys to the Curves. Specify the time each CurveKey should be reached and the camera position when the CurveKey is reached. In this case, each point in time will have three CurveKeys associated with it, one for each of the x, y, and z coordinates of the point on the Curve.

    public void AddPoint(Vector3 point, float time)
        curveX.Keys.Add(new CurveKey(time, point.X));
        curveY.Keys.Add(new CurveKey(time, point.Y));
        curveZ.Keys.Add(new CurveKey(time, point.Z));
    void InitCurve()
        float time = 0;
        cameraCurvePosition.AddPoint(new Vector3(7.5f, 0, -45), time);
        cameraCurveLookat.AddPoint(new Vector3(9, 0, 9), time);
        time += 2000;
        cameraCurvePosition.AddPoint(new Vector3(3f, 0, -36), time);
        time += 2000;
        cameraCurvePosition.AddPoint(new Vector3(12f, 0, -30), time);
        time += 2000;
        cameraCurvePosition.AddPoint(new Vector3(3f, 0, -24), time);
        time += 2000;
        cameraCurvePosition.AddPoint(new Vector3(12f, 0, -18), time);
        time += 2000;
  4. Loop through each Curve setting the TangentIn and TangentOut of each CurveKey. The tangents of the CurveKeys control the shape of the Curve. Setting the tangents of the CurveKeys to the slope between the previous and next CurveKey will give a curve that moves smoothly through each point on the curve.

    public void SetTangents()
        CurveKey prev;
        CurveKey current;
        CurveKey next;
        int prevIndex;
        int nextIndex;
        for (int i = 0; i < curveX.Keys.Count; i++)
            prevIndex = i - 1;
            if (prevIndex < 0) prevIndex = i;
            nextIndex = i + 1;
            if (nextIndex == curveX.Keys.Count) nextIndex = i;
            prev = curveX.Keys[prevIndex];
            next = curveX.Keys[nextIndex];
            current = curveX.Keys[i];
            SetCurveKeyTangent(ref prev, ref current, ref next);
            curveX.Keys[i] = current;
            prev = curveY.Keys[prevIndex];
            next = curveY.Keys[nextIndex];
            current = curveY.Keys[i];
            SetCurveKeyTangent(ref prev, ref current, ref next);
            curveY.Keys[i] = current;
            prev = curveZ.Keys[prevIndex];
            next = curveZ.Keys[nextIndex];
            current = curveZ.Keys[i];
            SetCurveKeyTangent(ref prev, ref current, ref next);
            curveZ.Keys[i] = current;
    static void SetCurveKeyTangent(ref CurveKey prev, ref CurveKey cur, ref CurveKey next)
        float dt = next.Position - prev.Position;
        float dv = next.Value - prev.Value;
        if (Math.Abs(dv) < float.Epsilon)
            cur.TangentIn = 0;
            cur.TangentOut = 0;
            // The in and out tangents should be equal to the slope between the adjacent keys.
            cur.TangentIn = dv * (cur.Position - prev.Position) / dt;
            cur.TangentOut = dv * (next.Position - cur.Position) / dt;
  5. Add code to evaluate the x, y, and z coordinates of the Curves at any given time by passing the elapsed time to the Evaluate method of each of the Curves.

    public Vector3 GetPointOnCurve(float time)
        Vector3 point = new Vector3();
        point.X = curveX.Evaluate(time);
        point.Y = curveY.Evaluate(time);
        point.Z = curveZ.Evaluate(time);
        return point;
  6. Create a variable to track the amount of time that has passed since the camera started moving.

    double time;
  7. In Game.Update, set the camera's position and look-at position based on the elapsed time since the camera started moving. Set the camera's view and projection matrices as in How To: Rotate and Move a Camera.

    // Calculate the camera's current position.
    Vector3 cameraPosition = cameraCurvePosition.GetPointOnCurve((float)time);
    Vector3 cameraLookat = cameraCurveLookat.GetPointOnCurve((float)time);
  8. In Game.Update, increment the time since the camera started moving by gameTime.ElapsedGameTime.TotalMilliseconds.

    time += gameTime.ElapsedGameTime.TotalMilliseconds;

Community Additions