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つの変数を変更します.次の変数が必要です.
MouseStateには、マウスの位置とbitsの一部が含まれており、マウスボタンが押されたかどうかを表しています.Initializeメソッドでは、2つの変数の初期値を指定します.
まず回転値を0に設定し、カメラを選択した位置に配置します.後で、viewMatrix変数を初期化するためのUpdateViewMatrixメソッドを作成します.
次に、カーソルを画面の中心に設定します.最後の行のコードにはMouseStateが格納されており、カーソルの位置が含まれているので、次の更新サイクルでは、この状態と新しい状態の違いを検出して、マウスが移動しているかどうかを示すことができます.
更新プロセスを見てください.前述したように、まず新しいMouseStateがoriginalMouseStateに格納されているMouseStateと異なるかどうかを確認します.異なる場合、回転値が更新され、カーソルが画面の中央に戻ります.
rotationSpeed変数は、マウスの回転速度を定義します.マウス座標の現在位置と前位置の水平距離と垂直距離を取得し、RightベクトルとUpベクトルの周りの回転を調整します.
最後の行のコードは、カーソルをウィンドウの中央に再配置します.
注:もう1つの方法は、currentMouseStateをoriginalMouseStateに保存することです.これにより、次の更新サイクルの新しいcurrentMouseStateと比較する準備ができます.しかし、カーソルが画面の端に移動すると、この方法は無駄になります.例えば、カーソルが画面の右端にある場合、ユーザがカーソルを右に移動してもX座標は変わらず、解決策はカーソルを画面の中央に再配置することである.
最後にUpdateViewMatrixメソッドが呼び出され、新しい回転値に基づいてviewMatrix変数が更新されます.次はUpdateViewMatrixメソッドのコードです.最初の行のコードを除いて、前のチュートリアルで詳しく説明しました.カメラの回転と位置を格納する行列に基づいて、この方法は、View行列を作成するために使用されるTargetおよびUpベクトルを計算する.
最初の行のコードにはいくつかの説明が必要です.ここでRightベクトルは(1,0,0)なので、x軸を指します.これはCreateRotationX法を使用してこの回転を作成した理由です.ここでのUpベクトルは(0,1,0)なので、CreateRotationYメソッドを使用して左右の回転を作成します.乗算の順番:M 1*M 2は「M 1はM 2の後ろにある」を表し、ここでは「上/下回転は左/右回転の後にある」ということです.行列の乗算順序の詳細については、チュートリアル4-2を参照してください.
これにより、マウスの動きに合わせてカメラが回転します.そして、Forwardキーを押すとカメラを前に移動させたいです.更新中、まずキーの状況を検出し、カメラの位置にどのベクトルを追加するかを指定します.
Upキーを押すとForwardベクトルがカメラ位置に追加され、Downキーを押すとカメラ位置からForwardベクトルなどが減算されます.ただし、これらの変数をカメラの位置に追加する前に、カメラの回転量で回転する必要があります.詳細については、前のチュートリアルを参照してください.これはAddToCameraPositionメソッドによって処理されます.
まず、UpdateViewMatrixメソッドに示すように、カメラの回転行列を計算します.そして、この回転行列に基づいて指定ベクトルを回転させると、この回転されたベクトルに変数が乗じられ、この変数はカメラの移動速度を定義するために使用され、カメラのPositionが変化します.最後に、新しいカメラ位置に基づいて新しいViewマトリクスを作成するUpdateViewMatrixメソッドを呼び出します.
コード#コード#
一人称カメラを作成するには、Up軸とRight軸の回転量、カメラの位置、対応するウィンドウの中心にあるカーソルのMouseStateの4つの変数を保存する必要があります.更新中にキーまたはマウスの移動を検出すると、これらの変数の変更がトリガーされ、これらの変数に基づいて新しいViewマトリクスが作成されます.
QuakeCameraクラス
一人称カメラが頻繁に使用されるので、この章のコードを分離してクラスに書きます.本書の多くの例はこのクラスを使用しており、あなたのプロジェクトに統合しやすいです.
に質問
一人称射撃ゲームのようなカメラを作りたいです.マウスでカメラを回転させ、キーボードでカメラを移動したいです.
ソリューション
まず、チュートリアル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クラス
一人称カメラが頻繁に使用されるので、この章のコードを分離してクラスに書きます.本書の多くの例はこのクラスを使用しており、あなたのプロジェクトに統合しやすいです.