ページ 11

[DXLIB]プレイヤーの背面から敵を映すカメラ

Posted: 2017年3月21日(火) 19:13
by Yggdra
はじめまして、3Dに手を出して間もない者なのですが、カメラの位置設定で困っております。

対戦格闘ゲームのようなものを作ろうとしているのですが、
敵を軸にプレイヤーに円運動をさせた場合にカメラをプレイヤーの背面にもっていきたいのです。

あれこれ調査はしてみたのですが、独学では厳しいと思い、皆様の力をお借りしたいと思います。

下記コードの74行目カメラの位置設定箇所です。

コード:

#include #include <math.h>
#include "DxLib.h"

int WINAPI WinMain(HINSTANCE, HINSTANCE, LPSTR, int) {
	int playerModel;
	int enemyModel;
	VECTOR playerPos;
	VECTOR enemyPos;
	VECTOR camPos;
	VECTOR camTgt;
	VECTOR subVector;
	int field;
	float playerAngle;
	float enemyAngle;

	// 初期化
	if(DxLib_Init() == 0) {
		// 異常終了
		return 0;
	}
	// 3Dモデルの読み込み
	playerModel = MV1LoadModel("XXX.pmd");
	enemyModel = MV1CreateCloneModel(playerModel);
	field = MV1LoadModel("XXX.mqo");

	// 奥行0.1~10000までをカメラの描画範囲とする
	SetCameraNearFar(0.1f, 10000.0f);
	// 3Dモデルの座標を初期化
	playerPos = VGet(0.0f, 0.0f, -30.0f);
	enemyPos = VGet(0.0f, 0.0f, 30.0f);
	camPos = VGet(playerPos.x + 5.0f, 25.0f, playerPos.z - 30.0f);
	// while( 裏画面を表画面に反映, メッセージ処理, 画面クリア )
	while(ScreenFlip() == 0 && ProcessMessage() == 0 && ClearDrawScreen() == 0) {
		// 指定位置にモデルを配置
		MV1SetPosition(playerModel, playerPos);
		MV1SetPosition(enemyModel, enemyPos);
		// 3Dモデル2から3Dモデル1に向かうベクトルを算出
		subVector = VSub(enemyPos, playerPos);
		// atan2 を使用して角度を取得
		playerAngle = atan2f(subVector.x, subVector.z);
		// atan2 で取得した角度に3Dモデルを正面に向かせるための補正値( DX_PI_F )を足した値を3Dモデルの Y軸回転値として設定
		MV1SetRotationXYZ(playerModel, VGet(0.0f, playerAngle + DX_PI_F, 0.0f));

		// 3Dモデル1から3Dモデル2に向かうベクトルを算出
		subVector = VSub(playerPos, enemyPos);
		// atan2 を使用して角度を取得
		enemyAngle = atan2f(subVector.x, subVector.z);
		// atan2 で取得した角度に3Dモデルを正面に向かせるための補正値( DX_PI_F )を足した値を3Dモデルの Y軸回転値として設定
		MV1SetRotationXYZ(enemy->Model, VGet(0.0f, enemyAngle + DX_PI_F, 0.0f));

		if(CheckHitKey(KEY_INPUT_LEFT) > 0){
			// 敵を軸に左回転
			playerPos.x += cosf(-(MV1GetRotationXYZ(playerModel).y)) * 1.0f;
			playerPos.z += sinf(-(MV1GetRotationXYZ(playerModel).y)) * 1.0f;
		}
		if(CheckHitKey(KEY_INPUT_RIGHT) > 0){
			// 敵を軸に右回転
			playerPos.x += cosf(-(MV1GetRotationXYZ(playerModel).y)) * -1.0f;
			playerPos.z += sinf(-(MV1GetRotationXYZ(playerModel).y)) * -1.0f;
		}
		if(CheckHitKey(KEY_INPUT_UP)){
			// 前進
			playerPos.x += sinf(MV1GetRotationXYZ(playerModel).y) * -1.0f;
			playerPos.z += cosf(MV1GetRotationXYZ(playerModel).y) * -1.0f;
		}
		if(CheckHitKey(KEY_INPUT_DOWN)){
			// 後退
			playerPos.x += sinf(MV1GetRotationXYZ(playerModel).y) * 1.0f;
			playerPos.z += cosf(MV1GetRotationXYZ(playerModel).y) * 1.0f;
		}
		// カメラ追従
		camTgt = enemyPos;
		camPos = VGet(playerPos.x + 5.0f * cosf(MV1GetRotationXYZ(playerModel).y), 25.0f, playerPos.z  -30.0f * sinf(MV1GetRotationXYZ(playerModel).y));
		SetCameraPositionAndTarget_UpVecY(camPos, camTgt);
		// 3Dモデルの描画
		MV1DrawModel(playerModel);
		MV1DrawModel(enemyModel);
		MV1DrawModel(field);
	}
	// DXライブラリ終了処理
	DxLib_End();
	// 終了
	return 0;
}
// End Of File

Re: [DXLIB]プレイヤーの背面から敵を映すカメラ

Posted: 2017年3月22日(水) 19:01
by 梅衣堂ひよ
注視点は敵の座標のままでおkとして、
カメラのプレイヤーからの相対座標をあらかじめ変数として持っておきます。
次にカメラの向き(Y軸)、つまりenemyAngleをもとに回転行列を作成、カメラの向きに合わせて回転行列を用いて相対座標を回転させます。
最後に相対座標を追従対象(この場合はプレイヤー)の座標と足したものをカメラの座標とすればプレイヤー追従カメラが敵をロックしているかのように動作します。

ただ、モデルの描画座標がフレームの最初に行われているため、カメラに比べてモデルの方が1フレーム分遅れます。

Re: [DXLIB]プレイヤーの背面から敵を映すカメラ

Posted: 2017年3月22日(水) 19:25
by 梅衣堂ひよ
※追記
気になっていたのですが、
17行目なんですが、DxLib_Initは0が正常終了なのでこれだと正常終了した時に異常と判断されてしまいます。
それと、どうしてもわからない場合は言ってくださいね。一応DxLibを用いて組んでみたので動作確認済みですから。

Re: [DXLIB]プレイヤーの背面から敵を映すカメラ

Posted: 2017年3月22日(水) 21:48
by Yggdra
ご回答ありがとうございます!

早速おっしゃっていたように組んでみたのですが、どうも挙動がおかしくなります。

カメラ設定周りのコードを抜粋して貼りますので、どこがおかしいのかご教授願えないでしょうか。
※中略箇所は前と変わっていません。

コード:

int WINAPI WinMain(HINSTANCE, HINSTANCE, LPSTR, int) {
 ~ 中略 ~
	MATRIX cycleLine;
	VECTOR relativePos;
	float relativeAngle;
 ~ 中略 ~
	while(ScreenFlip() == 0 && ProcessMessage() == 0 && ClearDrawScreen() == 0) {
 ~ 中略 ~
		// 相対座標の作成
		relativePos = VSub(camPos, playerPos);
		// 回転行列の作成
		CreateRotationYMatrix(&cycleLine, enemyAngle);
		// 相対座標の回転
		GetMatrixXYZRotation(&cycleLine, NULL, &relativeAngle, NULL);
		VectorRotationY(&relativePos, &relativePos, relativeAngle);
		// カメラ座標の設定
		camTgt = enemyPos;
		camPos = VGet(playerPos.x + relativePos.x, 25.0f, playerPos.z + relativePos.z);
		SetCameraPositionAndTarget_UpVecY(camPos, camTgt);
 ~ 中略 ~
	}
	// DXライブラリ終了処理
	DxLib_End();
	// 終了
	return 0;
}
追伸:17行目の件ですが余分なコードを削除したときのゴミです。

Re: [DXLIB]プレイヤーの背面から敵を映すカメラ

Posted: 2017年3月23日(木) 04:06
by 梅衣堂ひよ
まず相対座標ですが、この変数自体は回転していないプレイヤーに対してどの位置にカメラがあるかを決めるものなので、基本的に初期化で値を決めたら弄らないでください。
じゃあどうやって回転後の座標を格納するかといったら、別に回転後の座標を格納する変数を用意しておいてください。
次に回転の仕方ですが、行列の作成は問題ないです。ただし、行列を用いてベクトルを変換する場合は、VTransform関数を使います。あっという間に変換してくれる優れものです。
今回は回転だけなのでVTransformSRでも動くかもしれません。動くならSRの方が計算が少ないため、軽いです。
ここで回転させた値は回転後の座標として、先ほど用意した回転後の座標用の変数に格納し、プレイヤー座標と足した値がカメラの位置になります。

ちなみに、カメラの位置が注視点より高い場合、注視点に近付けば近付くほどカメラは見下ろすようになっていきますのでそれを避けるにはある程度工夫が必要になりますので注意してください。

Re: [DXLIB]プレイヤーの背面から敵を映すカメラ

Posted: 2017年3月23日(木) 08:22
by Yggdra
無事実装することが出来ました!ありがとうございます。

色々動かしていたら別の問題が発生したのですが、トピックと大きくずれてしまうため、また困ったときにトピックを立てたいと思います。

一応説明致しますと、下記コードでは綺麗に円運動しなくて、モデルが少しずつ後ろに下がってしまうというものです。

コード:

        if(CheckHitKey(KEY_INPUT_LEFT) > 0){
            // 敵を軸に左回転
            playerPos.x += cosf(-(MV1GetRotationXYZ(playerModel).y)) * 1.0f;
            playerPos.z += sinf(-(MV1GetRotationXYZ(playerModel).y)) * 1.0f;
        }
        if(CheckHitKey(KEY_INPUT_RIGHT) > 0){
            // 敵を軸に右回転
            playerPos.x += cosf(-(MV1GetRotationXYZ(playerModel).y)) * -1.0f;
            playerPos.z += sinf(-(MV1GetRotationXYZ(playerModel).y)) * -1.0f;
        }