Take the 2-minute tour ×
Game Development Stack Exchange is a question and answer site for professional and independent game developers. It's 100% free, no registration required.

I'm trying to create a third person camera in my XNA game. I'm able to move the model I have and the camera at the same time, although the camera is not "following" the model. The model moves faster than the camera. Ultimately, I want the camera to rotate with the model with the left and right keys, and move the model with forward and back.

This is in my update method

    if (keyState.IsKeyDown(Keys.D))
        {
            camera.Rotation = MathHelper.WrapAngle(camera.Rotation - (rotateScale * elapsed));
        }

        if (keyState.IsKeyDown(Keys.A))
        {
            camera.Rotation = MathHelper.WrapAngle(camera.Rotation + (rotateScale * elapsed));
        }

        if (keyState.IsKeyDown(Keys.W))
        {
            camera.MoveForward(moveScale * elapsed);
            player.Position += new Vector3(0.1f, 0f, 0f);
        }

        if (keyState.IsKeyDown(Keys.S))
        {
            camera.MoveForward(-moveScale * elapsed);
            player.Position += new Vector3(-0.1f, 0f, 0f);
        }

player is the model I'm using. Currently the A and D keys don't do anything with the model.

    public class Camera
{
    private Vector3 position = Vector3.Zero;
    private Vector3 lookAt;
    private Vector3 baseCameraReference = new Vector3(0, 0, 1);

    private bool needViewResync = true;

    private float rotation;

    public Matrix Projection { get; protected set; }
    private Matrix cachedViewMatrix;

    public Vector3 Position
    {
        get
        {
            return position;
        }

        set
        {
            position = value;
            UpdateLookAt();
        }
    }

    public float Rotation
    {
        get
        {
            return rotation;
        }

        set
        {
            rotation = value;
            UpdateLookAt();
        }
    }

    public Matrix View
    {
        get
        {
            if (needViewResync)
                cachedViewMatrix = Matrix.CreateLookAt(Position, lookAt, Vector3.Up);

            return cachedViewMatrix;
        }
    }

    public Camera(Vector3 position, float rotation, float aspectRatio, float nearClip, float farClip)
    {
        Projection = Matrix.CreatePerspectiveFieldOfView(MathHelper.PiOver4, aspectRatio, nearClip, farClip);
        MoveTo(position, rotation);


    }

    private void UpdateLookAt()
    {
        Matrix rotationMatrix = Matrix.CreateRotationY(rotation);

        Vector3 lookAtOffset = Vector3.Transform(baseCameraReference, rotationMatrix);
        lookAt = position + lookAtOffset;
        needViewResync = true;
    }

    private void MoveTo(Vector3 position, float rotation)
    {
        this.position = position;
        this.rotation = rotation;
        UpdateLookAt();
    }

    public Vector3 PreviewMove(float scale)
    {
        Matrix rotate = Matrix.CreateRotationY(rotation);
        Vector3 forward = new Vector3(0, 0, scale);
        forward = Vector3.Transform(forward, rotate);
        return (position + forward);
    }

    public void MoveForward(float scale)
    {
        MoveTo(PreviewMove(scale), rotation);
    }
}

I also want to offset the camera for obvious reason, but changing the values in the variable baseCameraReference doesn't change what I want it to

share|improve this question
add comment

2 Answers 2

up vote 1 down vote accepted

If I understand your requirements, you want your camera to always be behind your player (but maybe offset slightly) and move and rotate with the player. The camera should stay in the same location and orientation (rotation) relative to the player.

Then all the rotation and movement code for updating your camera can be eliminated, it is just doing the same movement and rotation as you want the player to do anyway. Why do it twice? Spend all your coding effort moving and rotating the player only.

After that, simply send the updated players matrix to the camera update method after the player is moved and rotated and use the positional and rotational info from that player's matrix to build the camera.

Public void CameraUpdate(Matrix playerMatrix)
{
  camPosition = playerMatrix.Translation + (playerMatrix.Backward * trailingDistance);
  camTarget = playerMatrix.Translation;

  view = Matrix.CreateLookAt(camPosition, camTarget, Vector3.Up); 
}

That's all you need to update the camera. If you want to offset the camera's position (say, to position it over the player's shoulder or something), you can add more offsets when setting the position, like this:

camPosition = playerMatrix.Translation +
                (playerMatrix.Backward * trailingDistance) +
                (playerMatrix.Up  * verticalOffset) +
                (playerMatrix.Left * lateralOffset);

same with the target if you want it to seem as if it's looking past the player instead of at him:

camTarget = playerMatrix.Translation + (playerMatrix.Up * someOffset);
share|improve this answer
    
How would I implement this into my update method and by using the keys? –  Christian Frantz Jun 8 '13 at 22:46
    
I also don't have a player matrix, just a player.Position which is a Vector3 –  Christian Frantz Jun 8 '13 at 22:53
    
You must have a matrix for the player. When you draw the player, you set the effect.World to a matrix that represents the player's current position and rotation. that is the matrix I am referring to. Sequence of events: 1.) update player by responding to the input (gamepad or keyboard). 2.) set the player's matrix at this time (same as you would if drawing player). 3.)pass this matrix to the camera and use it to build view matrix in a manner similar to what I've suggested. 4.) pass this same matrix to the effect.World later when drawing the player (don't need to calculate it again). –  Steve H Jun 8 '13 at 23:10
add comment

This is the part of my player class that I'm looking at

    public void Render(Matrix view, Matrix projection)
        {
            foreach (ModelMesh mesh in mymodel.Meshes)
            {
                foreach (BasicEffect effect in mesh.Effects)
                {
                    //effect.EnableDefaultLighting();
                    effect.World = transforms[mesh.ParentBone.Index]
                        * Matrix.CreateScale(Scale)
                        * Matrix.CreateRotationY(MathHelper.ToRadians(RotationY))
                        * Matrix.CreateRotationX(MathHelper.ToRadians(RotationX))
                        * Matrix.CreateTranslation(Position);

                    effect.View = view;
                    effect.Projection = projection;
                }
                mesh.Draw();
            }
        }

What you're saying is to use the matrix "transforms[]" while passing in the camera method?

    camera.CameraUpdate(player.transforms)

and then update that matrix based on input?

share|improve this answer
    
here is a basic working example of the 3 classes and how they interact: game class: pastebin.com/juZFmef9 player class: pastebin.com/avwSA2ec camera class: pastebin.com/NFduExyw –  Steve H Jun 9 '13 at 1:16
    
the hard coded offset values were appropriate to the model I was using at the time, your values would most likely be different. set to taste. –  Steve H Jun 9 '13 at 1:24
    
Everthing compiles fine but the input doesn't change anything –  Christian Frantz Jun 9 '13 at 1:59
    
it sounds like you may need 1 on 1 help. feel free to email me. see my profile for address. –  Steve H Jun 9 '13 at 2:03
    
Alright I sent you my project –  Christian Frantz Jun 9 '13 at 2:30
show 2 more comments

Your Answer

 
discard

By posting your answer, you agree to the privacy policy and terms of service.

Not the answer you're looking for? Browse other questions tagged or ask your own question.