DXライブラリとC言語でゲーム制作。今回は3Dゲームでカメラを操作(回転)できるようにする方法について。
カメラ操作(回転)の基本
3Dゲームでカメラを操作(回転)できる場合、ある点(基本はプレイヤー)を軸にカメラ座標を回転させることになる。プレイヤーを中心とした半径Rの球面上をカメラが移動するイメージ。
3D座標空間での軸は以下の通り。

DXライブラリ置き場でカメラ操作(回転)のサンプルコードがあり、それを見るとおおざっぱな流れはこんな感じ。
- X軸方向にカメラからプレイヤーの距離分伸ばしたベクトルを作成
- そのベクトルを垂直方向に回転(Z軸回転)させる
- さらに水平方向に回転(Y軸回転)させる
- 注視点座標を足してカメラの座標を決定する
Unityなどのゲームエンジンでもカメラを回転させるアルゴリズムは大体同じ。余談だがベクトルの回転は行列の一次変換を用いて行っている。3D処理では行列を使うことが多々あるのできちんと知りたい人は勉強しておくと吉。
カメラ操作(回転)の実装
さてカメラ操作(回転)の実装。今回はプレイヤーの座標が必要なので前回作成したPlayer.cpp/hにプレイヤーの座標を渡す関数を追加。
Player.h
//以下の関数を追加 void Player_TakePosition(VECTOR* target);
Player.cpp
//以下の関数を追加 //プレイヤーの座標を渡す void Player_TakePosition(VECTOR* target) { *target = player.Position; }
続いてCamera.cppに以下のコードを以下のようにする。
Camera.cpp
#include "DxLib.h" #include "Input.h" #include "Camera.h" #include "Player.h" #include <math.h> const static float CAMERA_ANGLE_SPEED = 0.05f; //カメラの旋回速度 const static float CAMERA_PLAYER_LENGTH = 3.8f; //カメラとプレイヤーの距離 const static float CAMERA_PLAYER_TARGET_HEIGHT = 1.0f; //プレイヤー座標からどれだけ高い位置を注視点とするか //カメラ構造体 typedef struct { VECTOR Eye; //カメラの座標 VECTOR Target; //カメラの注視点 float AngleH; //水平角度 float AngleV; //垂直角度 }camera_t; camera_t camera; //カメラ初期化 void Camera_Initialize() { //カメラの角度の初期化 camera.AngleH = 0.0f; camera.AngleV = 0.0f; //奥行0.1~1000までをカメラの描画範囲とする SetCameraNearFar(0.1f, 1000.0f); //ライティング処理をOFF SetUseLighting(FALSE); } //カメラ情報更新 void Camera_Update() { //カメラの角度を計算 //→キーor右スティック右の入力があれば if (Input_GetGamepad(XINPUT_THUNMBR_RIGHT) > 0 || Input_GetKeyboard(KEY_INPUT_RIGHT) > 0) { camera.AngleH += CAMERA_ANGLE_SPEED; //-180度以上になったら角度値が大きくなりすぎないように360度引く if (camera.AngleH > DX_PI_F) camera.AngleH -= DX_TWO_PI_F; } //←キーor右スティック左の入力があれば if (Input_GetGamepad(XINPUT_THUNMBR_LEFT) > 0 || Input_GetKeyboard(KEY_INPUT_LEFT) > 0) { camera.AngleH -= CAMERA_ANGLE_SPEED; //-180度以下になったら角度値が大きくなりすぎないように360度足す if (camera.AngleH < -DX_PI_F) camera.AngleH += DX_TWO_PI_F; } //↑キーor右スティック上の入力があれば if (Input_GetGamepad(XINPUT_THUNMBR_UP) > 0 || Input_GetKeyboard(KEY_INPUT_UP) > 0) { camera.AngleV -= CAMERA_ANGLE_SPEED; //ある一定の角度以下にはならないようにする if (camera.AngleV < -DX_PI_F / 2.0f + 0.6f) camera.AngleV = -DX_PI_F / 2.0f + 0.6f; } //↓キーor右スティック下の入力があれば if (Input_GetGamepad(XINPUT_THUNMBR_DOWN) > 0 || Input_GetKeyboard(KEY_INPUT_DOWN) > 0) { camera.AngleV += CAMERA_ANGLE_SPEED; //ある一定の角度以上にはならないようにする if (camera.AngleV > DX_PI_F / 2.0f - 0.6f) camera.AngleV = DX_PI_F / 2.0f - 0.6f; } //プレイヤーの座標をゲット VECTOR tmp; Player_TakePosition(&tmp); //カメラの注視点はプレイヤー座標から規定値分高い座標 camera.Target = VAdd(tmp, VGet(0.0f, CAMERA_PLAYER_TARGET_HEIGHT, 0.0f)); //カメラの座標を決定する { MATRIX RotZ, RotY; //カメラの回転に使う行列 float Camera_Player_Length; //水平方向の回転はY軸回転 RotY = MGetRotY(camera.AngleH); //垂直方法の回転はZ軸回転 RotZ = MGetRotZ(camera.AngleV); //カメラからプレイヤーまでの初期距離をセット Camera_Player_Length = CAMERA_PLAYER_LENGTH; // カメラの座標を算出 // X軸にカメラとプレイヤーとの距離分だけ伸びたベクトルを // 垂直方向回転( Z軸回転 )させたあと水平方向回転( Y軸回転 )して更に // 注視点の座標を足したものがカメラの座標 camera.Eye = VAdd(VTransform(VTransform(VGet(-Camera_Player_Length, 0.0f, 0.0f), RotZ), RotY), camera.Target); } //プレイヤーを見る角度にカメラを設置 SetCameraPositionAndTarget_UpVecY(camera.Eye, camera.Target); } //描画 void Camera_Draw() { } //カメラ終了処理 void Camera_Finalize() { }
今回はカメラの情報を扱う構造体を追加。座標のほか、注視点および水平・垂直方向に回転させる際に必要となるか角度を持たせる。またカメラの旋回速度などの値も定義しておく。
Camera_Update()にてキー入力に応じてカメラを回転させる。今回キーボードではカーソルキー、ゲームパッドでは右スティックで操作(回転)できるようにしている。垂直方向の角度について、一定の角度以上(以下)になると映像がひっくり返ってしまうので一定の角度以上(以下)にならないようにする。
最後にSetCameraPositionAndTarget_UpVecY()でカメラの座標および注視点の座標を反映させるのを忘れずに。
描画関数および終了処理関数は現状やることがないので空のまま。
以下実行例。よく見ると描画がおかしい部分があるが多分モデル内のオブジェクトの描画順を指定していないため。
コメント