XNA学习笔记——Quake式相机

通常,在FPS游戏中,玩家可以自由地上下左右旋转观察,这些运动对应绕Up(y轴)和Right(x轴)的旋转,或更具体地说,绕(0,1,0)和(1,0,0)方向的旋转。但是绕z轴的旋转是不被允许的,这会导致玩家向左或向右弯曲脖子,在第一人称游戏中不使用,除非玩家被击中倒在地板上。矩阵的乘法顺序是很重要的,因为当你组合两个旋转时,第二个旋转轴会被第一个旋转所改变。

简单地说,需要存储两个变量:绕Up方向的旋转量和绕Right方向的旋转量。然后,当需要计算总的旋转量时,使用“在绕Up旋转之后绕Right旋转”组合两个旋转。输入方面,使用鼠标旋转相机,使用键盘移动相机,再将输入与旋转量联系起来。有了前面的基础,这里就容易多了。

先看Initialize()

   1: protected override void Initialize()
   2: {
   3:     // TODO: Add your initialization logic her
   4:     updownRot = 0.0f;//上下旋转角度
   5:     rightleftRot = 0.0f;//左右旋转角度
   6:     rotSpeed = 0.05f;//旋转速率
   7:     moveSpeed = 0.05f;//移动速率
   8:     Mouse.SetPosition(Window.ClientBounds.Width / 2, Window.ClientBounds.Height / 2);
   9:     originalMState = Mouse.GetState();
  10:    
  11:  
  12:     float fov = MathHelper.PiOver4;
  13:     float aspect = GraphicsDevice.DisplayMode.AspectRatio;
  14:     float nearClip = 0.5f;
  15:     float farClip = 100.0f;
  16:     projMat = Matrix.CreatePerspectiveFieldOfView(fov, aspect, nearClip, farClip);
  17:  
  18:     camPosition = new Vector3(0, 2, 10);//相机初始位置
  19:     originalForward = new Vector3(0, 0, -1);//初始方向
  20:     originalUp = new Vector3(0, 1, 0);
  21:    
  22:     UpadteViewMatrix();
  23:     base.Initialize();
  24: }

然后是UpdateViewMatrix()

   1: private void UpadteViewMatrix()
   2: {
   3:     cameraRotation = Matrix.CreateRotationX(updownRot) * Matrix.CreateRotationY(rightleftRot);
   4:   
   5:     rotatedForward = Vector3.Transform(originalForward, cameraRotation);
   6:     rotatedUp = Vector3.Transform(originalUp, cameraRotation);
   7:  
   8:     finalLook = camPosition + rotatedForward;
   9:     //finalUp = camPosition + rotatedUp;
  10:     finalUp = rotatedUp;
  11:  
  12:     viewMat = Matrix.CreateLookAt(camPosition, finalLook, finalUp);
  13: }

旋转矩阵设在UpdateViewMatrix中是因为updownRot和rightleftRot是经常变化的。对于finalLook,上一次记录中已经讲过了。但有没有注意到,
finalUp = rotatedUp。这是因为FPS相机中,不是任意旋转的。finalUp是一个方向,而finalLook是一个视点,rotatedForward才是方向。也就是说
finalUp和rotatedUp都是原始方向进过一次旋转变换而来,而finalLook是需要Position和rotatedForward叠加而成。有点啰嗦了。

再是Update()

   1: protected override void Update(GameTime gameTime)
   2: {
   3:     // Allows the game to exit
   4:     if (GamePad.GetState(PlayerIndex.One).Buttons.Back == ButtonState.Pressed)
   5:         this.Exit();
   6:  
   7:     // TODO: Add your update logic here
   8:     currentMState = Mouse.GetState();
   9:     if (currentMState != originalMState)
  10:     {
  11:         float xdiffence = currentMState.X - originalMState.X;
  12:         float ydiffence = currentMState.Y - originalMState.Y;
  13:  
  14:         rightleftRot -= rotSpeed * xdiffence;
  15:         updownRot -= rotSpeed * ydiffence;
  16:  
  17:         Mouse.SetPosition(Window.ClientBounds.Width/2, Window.ClientBounds.Height/2);
  18:         UpadteViewMatrix();
  19:     }
  20:  
  21:     kState = Keyboard.GetState();
  22:     if (kState.IsKeyDown(Keys.W))
  23:         MoveCameraPosition(Vector3.Forward);
  24:     else if (kState.IsKeyDown(Keys.S))
  25:         MoveCameraPosition(Vector3.Backward);
  26:     else if (kState.IsKeyDown(Keys.A))
  27:         MoveCameraPosition(Vector3.Left);
  28:     else if (kState.IsKeyDown(Keys.D))
  29:         MoveCameraPosition(Vector3.Right);
  30:  
  31:     base.Update(gameTime);
  32: }

因为旋转量由鼠标控制。鼠标往右,即人往右看,原本在屏幕中央的物体就往左移动(逆时针)。鼠标往左,即人往左看,原本在屏幕中央的物体就往右移动(顺时针)。而到底旋转多少,由偏离屏幕中央的距离决定。旋转量(updownRot和rightleftRot)变化之后,就是更新观察矩阵(调用UpdateViewMatrix)。旋转矩阵会影响观察矩阵的视点和Up方向,从而影响平移的方向。所以关于键盘的操作在调用UpdateViewMatrix之后。

接下来是MoveCameraPosition()

   1: private void MoveCameraPosition(Vector3 direction)
   2: {
   3:     //Vector3 originalForward = new Vector3(-1.7f, -1, -1);
   4:     Vector3 rotatedForward = Vector3.Transform(direction, cameraRotation);
   5:     camPosition += moveSpeed * rotatedForward;
   6:     UpadteViewMatrix();
   7:  
   8: }

和上一个记录一样。

你可能感兴趣的:(Game)