Getting started with XNA - First Person Camera

Getting started with XNA - First Person Camera

What’s a game or an interactive presentation without a way to move around? So in this tutorial, I’ll show you how to make a first person camera. As usual, this tutorial will work on the code of the previous one, available for download here.

 

Let’s start with some basic concepts: yaw, pitch and roll. Yaw is when you move your head from right to left or left to right. Pitch is when you move your head up and down, and roll is when you roll your head from one shoulder to another. The illustration below shall shed some more light.

前后左右旋转。

 

Two other concepts you need to comprehend are view and projection. The view establishes the orientation of the camera: its position, where it’s looking, and its orientation.

两个重要的概:view + projection. view指的是观察者的方位,往什么地方看,以及方向。

 

The projection establishes how the camera projects its view onto the screen: the field of view, the aspect ratio of the viewport, and the boundaries (in distance) of what the camera can see: the near plane and the far plane.

投影包括了:field of view, aspect ratio of viewport, boundaries

 

Ok, let’s start coding. Open up your project and add a class called Camera. Make sure it inherits from DrawableGameComponent.
public class Camera : DrawableGameComponent

First, we’re going to add a static variable, so we have easy access to the active camera. Most games don’t have just one camera, they have a first person camera, third person camera, … Note that there are better ways to do this, using a factory class and interfaces, but for this tutorial, it will do just fine.
private static Camera activeCamera = null;

Then add a variable for our view and projection, who represent (as explained above) the orientation of the camera and the way it’s projected to the screen.
// View and projection
private Matrix projection = Matrix.Identity;
private Matrix view = Matrix.Identity;

Then we’ll add some variables we’ll use to calculate our view and projection: the position of the camera, the angle of the camera, the speed of movement and the turn speed.
//
private Vector3 position = new Vector3(0, 0, 1000);
private Vector3 angle = new Vector3();
private float speed = 250f;
private float turnSpeed = 90f;

Next we’ll add some properties, so we can access some of these variables externally.
public static Camera ActiveCamera
{
get { return activeCamera; }
set { activeCamera = value; }
}

public Matrix Projection
{
get { return projection; }
}

public Matrix View
{
get { return view; }
}

public Vector3 Position
{
get { return position; }
set { position = value; }
}

public Vector3 Angle
{
get { return angle; }
set { angle = value; }
}

Also, in the constructor, we’ll check if there is an active camera. If not, we’ll set the active camera to this camera.
public Camera(Game game) : base(game)
{
if (ActiveCamera == null)
ActiveCamera = this;
}

When you’re in a game, you can keep turning around if u want, there is no limit to the amount of rotation. In order to achieve this, we need to keep our mouse cursor in the center of the screen. We’ll start by doing this in the Initialize method. Then we’ll calculate the movement and reset the mouse to the center of the screen each time the update method is called.
public override void Initialize()
{
int centerX = Game.Window.ClientBounds.Width / 2;
int centerY = Game.Window.ClientBounds.Height / 2;
//
Mouse.SetPosition(centerX, centerY);
//
base.Initialize();
}

Ok, we’ve set the basis. Only two more methods to implement. In the LoadGraphicsContent method we’ll calculate our projection. In the Update method, we’ll calculate our view. First the projection:
protected override void LoadGraphicsContent(bool loadAllContent)
{
float ratio = (float)GraphicsDevice.Viewport.Width / (float)GraphicsDevice.Viewport.Height;
projection = Matrix.CreatePerspectiveFieldOfView(MathHelper.PiOver4, ratio, 10, 10000);
//
base.LoadGraphicsContent(loadAllContent);
}

The projection will be a perspective field of view, with a near plane of 10 and a far plane of 10000. Below a graphic illustration.

(No pic)

 

We’re almost there. Now to calculate our view. Start by adding the update method.
public override void Update(GameTime gameTime)
{
base.Update(gameTime);
}

First, we’ll put the time that has gone past since the previous update in a variable called delta.
float delta = (float)gameTime.ElapsedGameTime.TotalSeconds;

And then we’ll capture the current state of the mouse and keyboard, so we’ll know which keys were pressed and where the mouse has moved to.
KeyboardState keyboard = Keyboard.GetState();
MouseState mouse = Mouse.GetState();

Now we have the current state, let’s just set the mouse cursor back in the center of the screen, so we don’t forget it later on.
int centerX = Game.Window.ClientBounds.Width / 2;
int centerY = Game.Window.ClientBounds.Height / 2;

Mouse.SetPosition(centerX, centerY);

Let’s adjust our angle variable according to the mouse movement.
angle.X += MathHelper.ToRadians((mouse.Y - centerY) * turnSpeed * 0.01f); // pitch
angle.Y += MathHelper.ToRadians((mouse.X - centerX) * turnSpeed * 0.01f); // yaw

Now that we have our angle, we can easily calculate our pitch and yaw vector (relative movement). I have to warn you, you’ll need your basic trigonometry, if you’re a bit rusty, fresh it up ;-). We’ll need this so we can move in the direction we’re looking at.
Vector3 forward = Vector3.Normalize(new Vector3((float)Math.Sin(-angle.Y), (float)Math.Sin(angle.X), (float)Math.Cos(-angle.Y)));
Vector3 left = Vector3.Normalize(new Vector3((float)Math.Cos(angle.Y), 0f, (float)Math.Sin(angle.Y)));

Ok, so let’s update our position according to the keys pressed.
if (keyboard.IsKeyDown(Keys.Up))
position -= forward * speed * delta;

if (keyboard.IsKeyDown(Keys.Down))
position += forward * speed * delta;

if (keyboard.IsKeyDown(Keys.Right))
position -= left * speed * delta;

if (keyboard.IsKeyDown(Keys.Left))
position += left * speed * delta;

if (keyboard.IsKeyDown(Keys.PageUp))
position += Vector3.Down * speed * delta;

if (keyboard.IsKeyDown(Keys.PageDown))
position += Vector3.Up * speed * delta;

So, that’s it, we have all we need to calculate our view. We’ll translate to our position and multiply that by our rotations, just that simple.
view = Matrix.Identity;
view *= Matrix.CreateTranslation(-position);
view *= Matrix.CreateRotationZ(angle.Z);
view *= Matrix.CreateRotationY(angle.Y);
view *= Matrix.CreateRotationX(angle.X);

There, that’s it, our camera class is finished. All we need to do now is add a camera to the components of our game class and tell our forklift to use the view and the projection of our camera. So put this in the Initialize method of our Game1 class.
this.Components.Add(new Camera(this));

Finally, update the view and projection in the draw code of our forklift.
effect.View = Camera.ActiveCamera.View;
effect.Projection = Camera.ActiveCamera.Projection;

So, when you press F5 know, you’ll be able to move and look around. You can download the full source of this tutorial of course.

  • 1
    点赞
  • 0
    收藏
    觉得还不错? 一键收藏
  • 0
    评论
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值