DirectX11 ゲーム開発 ロックオンカメラを実装してみる ~その1~


はじめに

DirectX11とVisualStudio2015を使ってこんな感じのロックオンカメラを作ってみました。
常にプレイヤー(白い戦車)敵(赤い戦車)を写すカメラです
今回はカメラの考え方とロックオンカメラについての解説をしたいと思います。

注視点と位置

今回作ったカメラクラスには、注視点と位置があります。
投影行列とかは省略

カメラクラス
class Camera
{
public:
    DirectX::XMFLOAT3   pos;                //  「位置(座標)」
    DirectX::XMFLOAT3   target;             //  「注視点」
  //========================省略===============================================
};

「位置」というのはその名の通りカメラのいる位置(座標)です。

そして、私が最初に理解できなかったのは「注視点」です。
「最初はカメラの向いている方向ベクトル」だと思っていました。ですがこれは間違いです。
当時はこれがわからなくてとても苦戦しました。
「注視点」は「」です。つまり、ベクトルではなく座標なんですね。
見ている方向ではなく見ている点だったわけです。

(図が下手ですいません)
この図を見ていただくとわかると思いますが target(注視点)にプレイヤーの座標を渡せば常にプレイヤーを写してくれるようになります。

ロックオン

さて、理屈が大体わかったところでいよいよロックオンカメラの解説に入ります。
「プレイヤーの座標を注視点に渡すとプレイヤーを写してくれる」ので、プレイヤーの代わりにエネミーの座標を渡せばエネミーを常に映してくれそうです。

Update関数
void Camera::Update(DirectX::XMFLOAT3* enemy_pos)
{
  target = *enemy_pos;  //注視点に敵の座標を代入。
}

ここで問題が発生します。このままだと、プレイヤーが画面外に出てしまうことがあります。
プレイヤーと敵を同時にカメラに収めるにはどうすればいいでしょうか。

今回はプレイヤーと敵の距離のベクトルを使うやり方で実装しました。

要するに「敵とプレイヤーを結んだ直線上にカメラを設置すればいいよね」ってことです。
このやり方では、注視点にエネミーの座標と②ベクトルを足した値を、位置にプレイヤーの座標と③のベクトルを足したものを入れています。距離の値に好きな値を入れることでプレイヤーとカメラの距離を変えられるのが利点です。

ちなみに、プレイヤーとエネミーの座標が完全に一致するとカメラがバグります。理由は注視点と位置が重なっているためです。
よくわからない人はとりあえず注視点と位置は完全一致させないことだけ覚えましょう。

Update関数
// カメラのy座標が0だと地面に埋まるため、1.0fを代入しています。
//yを高くすると見降ろしになります。
void Camera::Update (DirectX::XMFLOAT3 target_pos, DirectX::XMFLOAT3 player_pos, float distance)    //ロックオンカメラ
{
    // 単位ベクトル取得
    DirectX::XMFLOAT3 player_to_target = DirectX::XMFLOAT3(target_pos.x - player_pos.x, target_pos.y - player_pos.y, target_pos.z - player_pos.z);
    float length = sqrtf(powf(player_to_target.x, 2.0f) + powf (player_to_target.y, 2.0f) + powf (player_to_target.z, 2.0f));
    DirectX::XMFLOAT3 unitvec_player_to_target = DirectX::XMFLOAT3(player_to_target.x / length, player_to_target.y / length, player_to_target.z / length);

    //カメラ位置取得
    pos = DirectX::XMFLOAT3(player_pos.x - unitvec_player_to_target.x * distance, 1.0f, player_pos.z - unitvec_player_to_target.z * distance);

    //注視点取得
    target = DirectX::XMFLOAT3(target_pos.x + unitvec_player_to_target.x, target_pos.y + unitvec_player_to_target.y, target_pos.z + unitvec_player_to_target.z);
}

まとめ

カメラの「注視点」と「位置」を中心にいろいろ話しました。
私もまだ勉強中でよくわかっていない部分もあるのですが、できるだけわかりやすく解説したつもりです。
勉強が進んで新しく発見した事があればまた記事にしたいなと思っています。