[DXライブラリ3D]カメラと主人公の相対座標について

フォーラム(掲示板)ルール
フォーラム(掲示板)ルールはこちら  ※コードを貼り付ける場合は [code][/code] で囲って下さい。詳しくはこちら
アバター
ptolemy
記事: 258
登録日時: 12年前

[DXライブラリ3D]カメラと主人公の相対座標について

#1

投稿記事 by ptolemy » 11年前

以前、
http://dixq.net/forum/viewtopic.php?f=3&t=14539
で同じことを質問して、"ステージの移動範囲は相対座標にするとよい"で、解決としたんですが、
いまいちどうしたらいいのかわからないものがあって、質問します。

X座標を例にすると、

コード:

camera.X=player.X;//カメラとプレイヤー(主人公)のX座標は、常に同じ

int WINAPI WinMain(HINSTANCE,HINSTANCE,LPSTR,int){

	while(){
		if(Wを押したら){
			player.X+=1.0f;
		}

		if(マウスを動かしたら){
			//プレイヤーは、Y軸を中心に回転(回転のプログラムは、長いのでカット)
			//カメラは、プレイヤーを中心に回転
		}
	}
}
とすると、回転ができなくなります。
180°回転だと、
回転する前→相対で、正常に動く
回転した後→回転をするが、相対座標になってるので、引き戻され、
         カメラとプレイヤーが背中合わせになる。

という現状です。
また、逆に相対位置ではなく、独立して動かした場合、
例えば、上のプログラムだと、"Wを押したときcamera.Xも加算される。"や以前の質問だと

コード:

if(player.X>19421){
    player.X=19421;
    camera.X=19421;
}
のようにカメラも付け足す。場合は、180°回転した場合
回転する前→正常
回転した後→回転すると指定位置からずれるので背中合わせになる。
という状態です。

わかりにくいと思うので、イラストも載せます。
結果的には、どういう方法でもいいので、ステージの移動範囲を制御したいです。
イラストは、こちらです。
質問に何かミスがあったらすみません。

アバター
usao
記事: 1892
登録日時: 12年前
連絡を取る:

Re: [DXライブラリ3D]カメラと主人公の相対座標について

#2

投稿記事 by usao » 11年前

何が何だかわかりませんが,
(1)カメラ位置が常に プレイヤのいくらか前方
(2)カメラの向きが常に プレイヤの前方方向と一致
ということをしたいのでしょうか?


>プレイヤーは、Y軸を中心に回転
>カメラは、プレイヤーを中心に回転

という状態を考えると,前記(1)のような状況であれば,プレイヤの向きの回転に伴って
カメラの X,Z 座標が変化することになると思うのですが,そのことと

>カメラとプレイヤー(主人公)のX座標は、常に同じ

という謎の記述とが矛盾してはいないでしょうか?
(とりあえずその例示された絵に 座標軸の向き も書き入れてもらえると話がわかりやすいような気もします.)


仮に(1)のようなことがしたいのであれば,中学校(高校だろうか?)あたりで習ったような事柄に立ち戻って

 カメラ位置(位置ベクトル) = プレイヤ位置(同) + プレイヤ前方方向単位ベクトル×プレイヤとカメラとの間の距離

として毎フレーム単純に算出してやれば良いだけなのではないでしょうか?


>回転のプログラムは、長いのでカット
とのことですが,
そもそもそこがバグってるのでしょうから,そこを省略したらコード張る意味が無いのではないでしょうか?
それに,果たしてそんなに長くなるものでしょうか?
(私はDXライブラリのことは存じませんので,ライブラリの都合で長くなる,という話なのかもしれませんが)
仮に,本当にY軸周りにしか回転しない のであればスカラー量(回転角度)一個の足し算引き算だけで終了ではないでしょうか?
(→まぁそこから回転マトリクス等の計算をするのでしょうけど,それでもたかだか数行程度では?)

アバター
ptolemy
記事: 258
登録日時: 12年前

Re: [DXライブラリ3D]カメラと主人公の相対座標について

#3

投稿記事 by ptolemy » 11年前

曖昧なことばっかり書いてすみません。

少し混乱してました。
なので質問を書き直します。
言葉で書きます。
プレイヤーとカメラとの位置関係について、今まで、

コード:

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

static	const	float	ROTATE_SPEED=DX_PI/40;//回転スピード(DX_PI/A)

void	rotate(float	*x,float	*y,const	float	ang,float	mx,float	my){
	const	float	ox=*x-mx,oy=*y-my;
	*x=ox*cos(ang)+oy*sin(ang);
	*y=-ox*sin(ang)+oy*cos(ang);
	*x+=mx;
	*y+=my;

}

int WINAPI WinMain(HINSTANCE,HINSTANCE,LPSTR,int){
	ChangeWindowMode(TRUE),DxLib_Init(),SetDrawScreen(DX_SCREEN_BACK)

	//初期位置の設定
	//カメラの場所設定
	camera.X=player.X;
	camera.Y=2584;
	camera.Z=player.Z-46;

	//カメラが見る座標を設定
	cursor_x=player.X;
	cursor_z=player.Z-1320;
	cursor_y=2690;

	SetCameraNearFar(2.0f,1000000.0f);
//メインループ
	while(ScreenFlip()==0&&ProcessMessage()==0&&ClearDrawScreen()==0){
					
		if(keybord_Get(KEY_INPUT_W)>0&&GAMESTART==1){
			player.HX=player.speed*-sin(player.angleY);
			player.HY=player.speed*-cos(player.angleY);
			player.X+=player.HX;
			player.Z+=player.HY;
			camera.X+=player.HX;
			camera.Z+=player.HY;
			cursor_x+=player.HX;
			cursor_z+=player.HY;
 		}
	
		//方向回転
		GetMousePoint(&Mouse_x,&Mouse_y);
		if(cnt>0){
			if(Mouse_x>320){
				rotate(&camera.X,&camera.Z,+ROTATE_SPEED,player.X,player.Z);
				rotate(&cursor_x,&cursor_z,+ROTATE_SPEED,player.X,player.Z);
				rotate(&TAMA_end_x,&TAMA_end_z,+ROTATE_SPEED,player.X,player.Z);
				player.angleY+=ROTATE_SPEED;
			}
			if(Mouse_x<320){
       				rotate(&camera.X,&camera.Z,-ROTATE_SPEED,player.X,player.Z);
				rotate(&cursor_x,&cursor_z,-ROTATE_SPEED,player.X,player.Z);
				rotate(&TAMA_end_x,&TAMA_end_z,-ROTATE_SPEED,player.X,player.Z);
				player.angleY-=ROTATE_SPEED;
			}	
	
		}
		cnt++;
		SetMousePoint(320,240);


		if(player.Z<-9000){
			player.Z=-9000;
		}
		if(player.Z>19643){
			player.Z=19643;
		}
		if(player.X<-316526){
			player.X=-316526;
		}
		if(player.X>19421){
			player.X=19421;
		}


	}
	ClearDrawScreen();
	DxLib_End();
	return	0;

}
このようにしていました。

変数については、player.angleYがプレイヤーの回転角です。
このようにして、カメラとカメラが見る座標を初期設定した後、
独立して、管理していたのですが、上のように移動範囲を決めたところ、
プレイヤーの座標は、回転しても変わらないので、いいのですが、
カメラと、カメラが見る座標に関しては、プレイヤー中心に回っていますので、
回転すると変わってしまって、カメラとその見る座標は、プレイヤーとは、同じく範囲を決めれません。

なので、相対座標で管理しようと思ったのですが、ただ、回転しないのであればcamera.Z=player.X-100(例)の
ように相対座標で管理できますが、回転をして、常に-100では、ないようなものは、
どうやって相対座標で管理すればよいのかわかりませんでした。

プログラムでは、マウスの座標が動くと回転のようにしてあります。
どこか勘違いをして、悩んでいるのかもしれませんので、おかしいところは、ご指摘お願いします。

__________
カメラ位置(位置ベクトル) = プレイヤ位置(同) + プレイヤ前方方向単位ベクトル×プレイヤとカメラとの間の距離
この式のプレイヤ前方方向単位ベクトルとは、上のプログラムでいうHX,HYのことですか?
この式は、"プレイヤーの位置からプレイヤーの向いている方向へカメラの距離分すすめる"というものですが、
カメラとプレイヤーの距離の差がわかりません。初期位置の時の差ですか?


一応、質問の答えが上の式といのは、わかります。
今悩んでいるのは、この式のカメラとプレイヤーの差がわかりません。
質問がかなりありますが、よろしくお願いします。

アバター
usao
記事: 1892
登録日時: 12年前
連絡を取る:

Re: [DXライブラリ3D]カメラと主人公の相対座標について

#4

投稿記事 by usao » 11年前

うーむ,とりあえず簡単に考えてみられてはいかがでしょう?

例えば…
2次元で{→がX正の方向,↓がY正の方向}みたいな世界において,
プレイヤが取り得る向きは4方向={0,90,180,270}[度] しかないものとしましょう.
それらの向きでのプレイヤの方向を表す単位ベクトルを(X,Y)で書けば,それぞれ
{ (1,0), (0,1), (-1,0), (0,-1) }
です.
で,【プレイヤの位置からプレイヤが現在向いてる方向に5だけ離れた座標 K=(kx,ky)】を各フレームにおいて計算したい,という問題.

・プレイヤの現在位置を(px, py)
・プレイヤの現在向いている方向を表す単位方向ベクトルを(ux, uy) : ※これは前記4パターンのうちいずれかの値になっている
という4個の変数で管理しているとしたら,Kの座標を求める処理
kx = ?
ky = ?
はどう書けば良いでしょうか.


カメラがプレイヤの前方(例えば常に距離100だけ前方)にある,というルールの上で
カメラ位置を求める ことについては,この簡単な例とやることは一緒ではないのでしょうか?
(実際の問題では, (ux,uy)を プレイヤの向いている角度 という別の変数から三角関数で求めるところまでができているのだから.)


※張られている絵の中に壁らしき緑の線が見られるので,
 カメラが壁の向こうに行っちゃうことを許さないようなルールを考えられているのかな?とか思いますが,とりあえず壁が無い場合の話として.

アバター
ptolemy
記事: 258
登録日時: 12年前

Re: [DXライブラリ3D]カメラと主人公の相対座標について

#5

投稿記事 by ptolemy » 11年前

参考に

コード:

#include"DXLib.h"
#include"keybord.h"
#include<math.h>
static	const	float	ROTATE_SPEED=DX_PI/40;//回転スピード(DX_PI/A)

static	int	KAMAE_Z_Index=0,HASHA_Z_Index=1,ZENSHIN_Z_Index=2,ZENSHIN_N_Index=3;

void	rotate(float	*x,float	*y,const	float	ang,float	mx,float	my){
	const	float	ox=*x-mx,oy=*y-my;
	*x=ox*cos(ang)+oy*sin(ang);
	*y=-ox*sin(ang)+oy*cos(ang);
	*x+=mx;
	*y+=my;

}
//初期化
//カメラ
camera.X=player.X;
camera.Y=2584;
camera.Z=player.Z-46;
//カメラが見る座標
cursor_x=player.X;
cursor_z=player.Z-1320;
cursor_y=2690;

	
SetCameraNearFar(2.0f,1000000.0f);

int WINAPI WinMain(HINSTANCE,HINSTANCE,LPSTR,int){

	ChangeWindowMode(TRUE),DxLib_Init(),SetDrawScreen(DX_SCREEN_BACK);

	//メインループ
	while(ScreenFlip()==0&&ProcessMessage()==0&&ClearDrawScreen()==0){

		//左右:90°の差をなくす。
		if(keybord_Get(KEY_INPUT_A)>0){
			player.ang=player.angleY+(90.0/180.0f*3.141592f);
			player.HX=player.speed*sin(player.ang);
			player.HY=player.speed*cos(player.ang);
			camera.HX=sin(player.ang);
			camera.HY=cos(player.ang);
			IDOU=1;
		}
		if(keybord_Get(KEY_INPUT_S)>0){
			player.HX=player.speed*sin(player.angleY);
			player.HY=player.speed*cos(player.angleY);
			camera.HX=sin(player.angleY);
			camera.HY=cos(player.angleY);
			IDOU=1;
		}
		if(keybord_Get(KEY_INPUT_W)>0){
			player.HX=player.speed*-sin(player.angleY);
			player.HY=player.speed*-cos(player.angleY);
			camera.HX=-sin(player.angleY);
			camera.HY=-cos(player.angleY);
			IDOU=1;
		}
		if(keybord_Get(KEY_INPUT_D)>0){
			player.ang=player.angleY-(90.0/180.0f*3.141592f);
			player.HX=player.speed*sin(player.ang);
			player.HY=player.speed*cos(player.ang);
			camera.HX=sin(player.ang);
			camera.HY=cos(player.ang);
			IDOU=1;
		}



		//45°の差をなくして斜め移動

		if((keybord_Get(KEY_INPUT_W)>0)&&(keybord_Get(KEY_INPUT_D)>0)){
			player.ang=player.angleY+(45.0/180.0f*3.141592f);
			player.HX=player.speed*-sin(player.ang);
			player.HY=player.speed*-cos(player.ang);
			camera.HX=-sin(player.ang);
			camera.HY=-cos(player.ang);
			IDOU=1;
		}
		if((keybord_Get(KEY_INPUT_W)>0)&&(keybord_Get(KEY_INPUT_A)>0)){
			player.ang=player.angleY-(45.0/180.0f*3.141592f);
			player.HX=player.speed*-sin(player.ang);
			player.HY=player.speed*-cos(player.ang);
			camera.HX=-sin(player.ang);
			camera.HY=-cos(player.ang);
			IDOU=1;
		}

		if((keybord_Get(KEY_INPUT_S)>0)&&(keybord_Get(KEY_INPUT_D)>0)){
			player.ang=player.angleY-(45.0/180.0f*3.141592f);
			player.HX=player.speed*sin(player.ang);
			player.HY=player.speed*cos(player.ang);
			camera.HX=sin(player.ang);
			camera.HY=cos(player.ang);
			IDOU=1;
		}
		if((keybord_Get(KEY_INPUT_S)>0)&&(keybord_Get(KEY_INPUT_A)>0)){
			player.ang=player.angleY+(45.0/180.0f*3.141592f);
			player.HX=player.speed*sin(player.ang);
			player.HY=player.speed*cos(player.ang);
			camera.HX=sin(player.ang);
			camera.HY=cos(player.ang);
			IDOU=1;
		}

		//移動
		if(IDOU==1&&GAMESTART==1){
			IDOU=0;
			player.X+=player.HX;
			player.Z+=player.HY;
			camera.X=player.X+camera.HX*0;
			camera.Z=player.Z+camera.HY*46;
			cursor_x=player.X+camera.HX*0;	
			cursor_z=player.Z+camera.HY*1320;
    		}


	
		//方向回転
		GetMousePoint(&Mouse_x,&Mouse_y);
		if(cnt>0){
			if(Mouse_x>320){
				rotate(&camera.X,&camera.Z,+ROTATE_SPEED,player.X,player.Z);
				rotate(&cursor_x,&cursor_z,+ROTATE_SPEED,player.X,player.Z);
				rotate(&TAMA_end_x,&TAMA_end_z,+ROTATE_SPEED,player.X,player.Z);
				player.angleY+=ROTATE_SPEED;
			}
			if(Mouse_x<320){
				rotate(&camera.X,&camera.Z,-ROTATE_SPEED,player.X,player.Z);
				rotate(&cursor_x,&cursor_z,-ROTATE_SPEED,player.X,player.Z);
				rotate(&TAMA_end_x,&TAMA_end_z,-ROTATE_SPEED,player.X,player.Z);
				player.angleY-=ROTATE_SPEED;
			}
	
		}
		cnt++;
		SetMousePoint(320,240);



		if(player.Z<-9000){
			player.Z=-9000;
		}	
		if(player.Z>19643){
			player.Z=19643;
		}
		if(player.X<-316526){
			player.X=-316526;
		}
		if(player.X>19421){
			player.X=19421;
		}

		//ESCキーで終了
		if(keybord_Get(KEY_INPUT_ESCAPE)>0){
			break;
		}
	}

	ClearDrawScreen();
	DxLib_End();
	return	0;
}
と書いてみたのですが、カメラの座標がおかしな場所へ行ったり来たりとうまくいきません。
*差の部分を-差で書くと、回転しない場合だけ正常です。
先ほどの式の差とは、これではないんですか?

ちなみに、僕は、中学3年なので、まだベクトルに関しては、まだ習ってないです。
以前のトピックスで少し浅く触れたくらいなのでベクトルは完ぺきなわけではありません。
いま、夏休み中ですが、休みが明けて3か月くらいしたらベクトルを習うと思います。

アバター
usao
記事: 1892
登録日時: 12年前
連絡を取る:

Re: [DXライブラリ3D]カメラと主人公の相対座標について

#6

投稿記事 by usao » 11年前

>以前のトピックスで少し浅く触れたくらいなのでベクトルは完ぺきなわけではありません。

そうでしたか.
では,三角関数(sin,とcos)については大丈夫でしょうか?

DXライブラリの部分の正しい書き方がわからないので,疑似コードになりますが
例えば以下のようなことをしてみて,動きを把握してみてはいかがでしょうか.

コード:

int WINAPI WinMain( 略 )
{
  //なんかライブラリに必要な初期処理
  ...

  //なんか適当な座標.「プレイヤの位置」に相当
  double Cx=100;
  double Cy=100;
  //なんか適当な距離.「プレイヤ位置からカメラ位置までの距離」に相当
  double r = 50;
  //現在の角度[rad].「プレイヤの向いている方向を表す角度」に相当
  double angle = 0;

  //メインループ
  while( 略 )
  {
    angle += 0.1;  //毎フレーム一定量だけ回転.※増分は適当に.キー操作で増減させるとかでも.

    //(Cx,Cy)から,現在の方向(角度angleな方向)に r だけ離れた座標(kx,ky)を計算.「カメラの位置」に相当
    double ux = cos(angle);
    double uy = sin(angle);
    double kx = Cx + r*ux;
    double ky = Cy + r*uy;

    位置(Cx,Cy)と(kx,ky)を描画してみる
  };

  //なんかライブラリに必要な終了処理
  ...
  //
  return 0;
}
(ux,uy)がどんなものなのかが把握できれば,
「何かキーを押したら,現在の角度の方向に(Cx,Cy)を一定量移動させる」みたいな機能を追加することができるハズです.

アバター
ptolemy
記事: 258
登録日時: 12年前

Re: [DXライブラリ3D]カメラと主人公の相対座標について

#7

投稿記事 by ptolemy » 11年前

できました!!

変数で言うrが初期位置のcamera.X=player.X; camera.Z=player.Z-64と混乱してました。
rとは、直角三角形のa*a+b*b=r*rで求められる斜辺の長さだと、理解出来ました。

詳しく教えていただいて本当にありがとうございました。

閉鎖

“C言語何でも質問掲示板” へ戻る