3 Dの世界で異なるカメラモードを作成する--一人称射撃ゲーム(FPS)のカメラを作成する:Quakeスタイルのカメラ

23013 ワード

2.3一人称射撃ゲーム(FPS)のカメラを作成する:Quakeスタイルのカメラ
に質問
一人称射撃ゲームのようなカメラを作りたいです.マウスでカメラを回転させ、キーボードでカメラを移動したいです.
ソリューション
まず、チュートリアル2-2の方法を使用して、ユーザ入力が検出されるとカメラの位置と回転を更新します.カメラの回転行列はマウスの移動に応じて変化し、UpまたはDownキーを押してカメラを前後に動かし、LeftまたはRightキーを押して左右に移動します.
さぎょうげんり
通常、FPSゲームでは、UpおよびRight軸回りの回転、またはより具体的には、(0,1,0)および(1,0,0)方向回りの回転に対応して、プレイヤーは自由に上下左右に回転観察することができる.
しかし、Forwardベクトルの周りの回転は許可されず、プレイヤーが床に当たって倒れない限り、左または右に首を曲げ、一人称ゲームでは使用されません.
さらに勉強する前に、チュートリアル4-2の「行列乗算の順序」の項を見ておくと役立ちます.マトリクスの乗算順序は、2つの回転を組み合わせると、2番目の回転軸が1番目の回転によって変化するため重要です.
1番目の回転が2番目の軸に影響するのはユニバーサルジョイントロックと呼ばれます(Gimbal lock)、これは大きなトラブルですが、時にはあなたが望む結果になります.FPSカメラの例では、まずUp軸に沿って回転し、Rightベクトルの周りを回転します.最初の回転もRightベクトルを回転します.腕を立って伸ばし、体を右に向けると腕も一緒に回転します.腕の方向を回転させ、上または下に回転させることができます.
簡単に言えば、Up方向の回転量とRight方向の回転量の2つの変数を格納する必要があります.そして、全体の回転量を計算する必要がある場合は、「Up回りに回転した後、Right回りに回転する」を使用して、2つの回転を組み合わせます.総回転が分かれば、前のチュートリアルのコードに渡すことができます.
FPSカメラの後ろの原理を知っていますが、ユーザー入力とこの2つの変数を結びつける必要があります.この例では、マウス入力を指定し、更新サイクル内のマウスの位置の変更を取得し、対応する2つの変数を変更します.次の変数が必要です.
float leftrightRot;

float updownRot;

Vector3 cameraPosition;

Matrix viewMatrix;

MouseState originalMouseState;


MouseStateには、マウスの位置とbitsの一部が含まれており、マウスボタンが押されたかどうかを表しています.Initializeメソッドでは、2つの変数の初期値を指定します.
leftrightRot = 0.0f;

updownRot = 0.0f;

cameraPosition = new Vector3(1,1,10);

UpdateViewMatrix();

Mouse.SetPosition(Window.ClientBounds.Width / 2, Window.ClientBounds.Height / 2);

originalMouseState = Mouse.GetState();


まず回転値を0に設定し、カメラを選択した位置に配置します.後で、viewMatrix変数を初期化するためのUpdateViewMatrixメソッドを作成します.
次に、カーソルを画面の中心に設定します.最後の行のコードにはMouseStateが格納されており、カーソルの位置が含まれているので、次の更新サイクルでは、この状態と新しい状態の違いを検出して、マウスが移動しているかどうかを示すことができます.
更新プロセスを見てください.前述したように、まず新しいMouseStateがoriginalMouseStateに格納されているMouseStateと異なるかどうかを確認します.異なる場合、回転値が更新され、カーソルが画面の中央に戻ります.
float rotationSpeed = 0.005f;

MouseState currentMouseState = Mouse.GetState();

if (currentMouseState != originalMouseState)

{  float xDifference = currentMouseState.X - originalMouseState.X;  float yDifference = currentMouseState.Y - originalMouseState.Y; leftrightRot -= rotationSpeed * xDifference; updownRot -= rotationSpeed * yDifference; Mouse.SetPosition(Window.ClientBounds.Width / 2, Window.ClientBounds.Height / 2); }

UpdateViewMatrix();


rotationSpeed変数は、マウスの回転速度を定義します.マウス座標の現在位置と前位置の水平距離と垂直距離を取得し、RightベクトルとUpベクトルの周りの回転を調整します.
最後の行のコードは、カーソルをウィンドウの中央に再配置します.
注:もう1つの方法は、currentMouseStateをoriginalMouseStateに保存することです.これにより、次の更新サイクルの新しいcurrentMouseStateと比較する準備ができます.しかし、カーソルが画面の端に移動すると、この方法は無駄になります.例えば、カーソルが画面の右端にある場合、ユーザがカーソルを右に移動してもX座標は変わらず、解決策はカーソルを画面の中央に再配置することである.
最後にUpdateViewMatrixメソッドが呼び出され、新しい回転値に基づいてviewMatrix変数が更新されます.次はUpdateViewMatrixメソッドのコードです.最初の行のコードを除いて、前のチュートリアルで詳しく説明しました.カメラの回転と位置を格納する行列に基づいて、この方法は、View行列を作成するために使用されるTargetおよびUpベクトルを計算する.
Matrix cameraRotation = Matrix.CreateRotationX(updownRot) * Matrix.CreateRotationY(leftrightRot);



Vector3 cameraOriginalTarget = new Vector3(0, 0, -1); 

Vector3 cameraOriginalUpVector = new Vector3(0, 1, 0);



Vector3 cameraRotatedTarget = Vector3.Transform(cameraOriginalTarget, cameraRotation);

Vector3 cameraFinalTarget = cameraPosition + cameraRotatedTarget;



Vector3 cameraRotatedUpVector = Vector3.Transform(cameraOriginalUpVector, cameraRotation);

Vector3 cameraFinalUpVector = cameraPosition + cameraRotatedUpVector;



viewMatrix = Matrix.CreateLookAt(cameraPosition, cameraFinalTarget, cameraFinalUpVector);

最初の行のコードにはいくつかの説明が必要です.ここでRightベクトルは(1,0,0)なので、x軸を指します.これはCreateRotationX法を使用してこの回転を作成した理由です.ここでのUpベクトルは(0,1,0)なので、CreateRotationYメソッドを使用して左右の回転を作成します.乗算の順番:M 1*M 2は「M 1はM 2の後ろにある」を表し、ここでは「上/下回転は左/右回転の後にある」ということです.行列の乗算順序の詳細については、チュートリアル4-2を参照してください.
これにより、マウスの動きに合わせてカメラが回転します.そして、Forwardキーを押すとカメラを前に移動させたいです.更新中、まずキーの状況を検出し、カメラの位置にどのベクトルを追加するかを指定します.
KeyboardState keyState = Keyboard.GetState();

if (keyState.IsKeyDown(Keys.Up))

   AddToCameraPosition(new Vector3(0, 0, -1)); 

if (keyState.IsKeyDown(Keys.Down))

    AddToCameraPosition(new Vector3(0, 0, 1)); 

if (keyState.IsKeyDown(Keys.Right))

    AddToCameraPosition(new Vector3(1, 0, 0)); 

if (keyState.IsKeyDown(Keys.Left))

    AddToCameraPosition(new Vector3(-1, 0, 0));

Upキーを押すとForwardベクトルがカメラ位置に追加され、Downキーを押すとカメラ位置からForwardベクトルなどが減算されます.ただし、これらの変数をカメラの位置に追加する前に、カメラの回転量で回転する必要があります.詳細については、前のチュートリアルを参照してください.これはAddToCameraPositionメソッドによって処理されます.
private void AddToCameraPosition(Vector3 vectorToAdd)

{ float moveSpeed = 0.5f; Matrix cameraRotation = Matrix.CreateRotationX(updownRot) * Matrix.CreateRotationY(leftrightRot); Vector3 rotatedVector = Vector3.Transform(vectorToAdd, cameraRotation); cameraPosition += moveSpeed * rotatedVector; UpdateViewMatrix(); }

まず、UpdateViewMatrixメソッドに示すように、カメラの回転行列を計算します.そして、この回転行列に基づいて指定ベクトルを回転させると、この回転されたベクトルに変数が乗じられ、この変数はカメラの移動速度を定義するために使用され、カメラのPositionが変化します.最後に、新しいカメラ位置に基づいて新しいViewマトリクスを作成するUpdateViewMatrixメソッドを呼び出します.
コード#コード#
一人称カメラを作成するには、Up軸とRight軸の回転量、カメラの位置、対応するウィンドウの中心にあるカーソルのMouseStateの4つの変数を保存する必要があります.更新中にキーまたはマウスの移動を検出すると、これらの変数の変更がトリガーされ、これらの変数に基づいて新しいViewマトリクスが作成されます.
protected override void Initialize() 

{  base.Initialize();  float viewAngle = MathHelper.PiOver4;  float aspectRatio = (float)this.Window.ClientBounds.Width / (float)this.Window.ClientBounds.Height;  float nearPlane = 0.5f;  float farPlane = 100.0f; projectionMatrix = Matrix.CreatePerspectiveFieldOfView(viewAngle, aspectRatio, nearPlane, farPlane); leftrightRot = 0.0f; updownRot = 0.0f; cameraPosition = new Vector3(1,1,10); UpdateViewMatrix(); Mouse.SetPosition(Window.ClientBounds.Width / 2, Window.ClientBounds.Height / 2); originalMouseState = Mouse.GetState(); }protected override void Update(GameTime gameTime)

{  if (GamePad.GetState(PlayerIndex.One).Buttons.Back == ButtonState.Pressed)  this.Exit();  float rotationSpeed = 0.005f; MouseState currentMouseState = Mouse.GetState();  if (currentMouseState != originalMouseState)  {  float xDifference = currentMouseState.X - originalMouseState.X;  float yDifference = currentMouseState.Y - originalMouseState.Y; leftrightRot -= rotationSpeed * xDifference; updownRot -= rotationSpeed * yDifference; Mouse.SetPosition(Window.ClientBounds.Width / 2, Window.ClientBounds.Height / 2); UpdateViewMatrix(); } KeyboardState keyState = Keyboard.GetState(); if (keyState.IsKeyDown(Keys.Up)) AddToCameraPosition(new Vector3(0, 0, -1));  if (keyState.IsKeyDown(Keys.Down)) AddToCameraPosition(new Vector3(0, 0, 1)); if (keyState.IsKeyDown(Keys.Right)) AddToCameraPosition(new Vector3(1, 0, 0)); if (keyState.IsKeyDown(Keys.Left)) AddToCameraPosition(new Vector3(-1, 0, 0)); base.Update(gameTime); }private void AddToCameraPosition(Vector3 vectorToAdd)

{  float moveSpeed = 0.5f; Matrix cameraRotation = Matrix.CreateRotationX(updownRot) Matrix.CreateRotationY(leftrightRot); Vector3 rotatedVector = Vector3.Transform(vectorToAdd, cameraRotation); cameraPosition += moveSpeed * rotatedVector; UpdateViewMatrix(); }private void UpdateViewMatrix()

{ Matrix cameraRotation = Matrix.CreateRotationX(updownRot) Matrix.CreateRotationY(leftrightRot); Vector3 cameraOriginalTarget = new Vector3(0, 0, -1); Vector3 cameraOriginalUpVector = new Vector3(0, 1, 0); Vector3 cameraRotatedTarget = Vector3.Transform(cameraOriginalTarget, cameraRotation); Vector3 cameraFinalTarget = cameraPosition + cameraRotatedTarget; Vector3 cameraRotatedUpVector = Vector3.Transform(cameraOriginalUpVector, cameraRotation); Vector3 cameraFinalUpVector = cameraPosition + cameraRotatedUpVector; viewMatrix = Matrix.CreateLookAt(cameraPosition, cameraFinalTarget, cameraRotatedUpVector); }

QuakeCameraクラス
一人称カメラが頻繁に使用されるので、この章のコードを分離してクラスに書きます.本書の多くの例はこのクラスを使用しており、あなたのプロジェクトに統合しやすいです.