スポンサーサイト

上記の広告は1ヶ月以上更新のないブログに表示されています。
新しい記事を書く事で広告が消せます。

アクションゲームのカメラワークの実装方法 ~前編~

今回、現時点で最良の方法と思われる
カメラワークの実装方法について記載してみたいと思います。

まず、単純なカメラワークの実装方法。
-----------------------------------------
【1】カメラの座標を保持するクラスを作成
【2】カメラに影響を受ける描画クラスを作成
【3】主人公の座標から、カメラの座標を修正

-----------------------------------------

もしかしたら、クラスを使わずに
実装しようとする方も居る
かもしれないので、
より、概念だけ分かる様に単純化してみます。


単純化すると、下記になります。
------------------------------------------
【1】g_CameraPosX,g_CameraPosYなどのグローバル変数を用意
【2】カメラに影響を受ける描画オブジェクトは、
   描画する際に、オブジェクトの座標 - カメラの座標とする。
【3】主人公の位置から逆算して、カメラの座標を修正

------------------------------------------

分かりにくいので順に考え方から説明します。


■カメラワークの原理
例えば、実行ファイルでのウィンドウサイズが800×600で、
主人公がX座標800、Y座標800の位置に居るとし、(主人公の背丈は100ドット分)
また、カメラの左上の座標は、X座標0、Y座標300とします。

この場合、
広大なゲームの世界のうち、
カメラが、X座標0~800、Y座標300~900の部分を切り取って
実行画面に映し出している

という認識を持ってみて下さい。

【参考画像】
Sample_20131217_1.jpg

そう考えると、主人公を 実行画面の左端に映し出す為には、
カメラの左上の座標を、(800,300)にすれば良い
と分かると思います。

【参考画像】
Sample_20131217_2.jpg


■カメラワークの実装方法
では、上記の例えで言う「切り出す」という処理を
プログラムでは、どう実装すれば良いか。

下記の様に、単純にカメラ座標用の変数に値を入れただけでは、
主人公は表示されません。


g_CameraPosX = 800;
g_CameraPosY = 300;
g_PlayerPosX = 800;
g_PlayerPosY = 800;

DrawObject( g_PlayerPosX, g_PlayerPosY, g_Handle );

※DrawObject()は、画像ハンドルと、X,Y座標を指定すれば、
 該当の画像が、指定座標に描画される関数とする。


なぜなら、カメラ座標用の変数に値を入れようが、
主人公の描画位置は800
(ウィンドウの表示領域外)のままだからです。

では、どうすれば良いか、というと
カメラの座標を主人公の座標から引きます。

DrawObject(g_PlayerPosX - g_CameraPosX,  g_PlayerPosY - g_CameraPosY, g_Handle );

DrawObject(800 - 800, 800 - 300, g_Handle );

DrawObject(0, 500, g_Handle );




要は、ゲーム世界のX座標:800の地点を、
ウィンドウ上のX座標:0の所に表示させたい
訳です。

その為には、800を引けば(左方向にずらす)OKという事です。

※他の座標でも同じです。
ゲーム世界のX座標:1200の地点を、
ウィンドウ上のX座標:0の場所に表示させたい場合は、
1200を引けばOKです。


これで、カメラを基準とした描画方法は分かったと思います…!
カメラの影響を受けるオブジェクトは、
下記の様にカメラ座標を引いて
やれば良いのです。
DrawObject(g_PlayerPosX - g_CameraPosX,  g_PlayerPosY - g_CameraPosY, g_Handle );


【補足】
また逆に、「制限時間表示」「スコア表示」などは
カメラワークの影響で上下左右に動いてもらっても困る
ので、
カメラ座標は引かない様にしましょう。

※DrawObject(g_ScorePosX, g_ScorePosY, g_Handke);の様に、固定表示にする。



カメラワークに影響を受けるオブジェクトの表示方法は分かったと思うので、
次は、カメラ座標をどのように動かすか?を考えていきます。

これは、簡単。
カメラの座標 = 主人公の座標 - 300; と言う風に、
主人公の位置から逆算すればOKです。

【参考画像】
Sample_20131217_3.jpg

ただ、これだと、
主人公がどんなに移動しても、
主人公が中心に来るようにカメラ座標が修正
されます。

つまり、主人公が激しくジャンプしたりすると、
ガクガクとカメラも激しく上下に動くことになって
非常に見づらい状態
になります。


■カメラワークの修正その1
このカメラがガクガクと動いてしまう挙動の修正案としては、
カメラの座標修正を特定条件下のみに制限する事です。

左右移動であれば、
「左右の端付近に来た時に座標修正」という方法で対応します。

【参考画像】
Sample_20131217_4.jpg


で、「主人公が画面端付近に来た」という判定
プログラムでどう行うか、についてですが、

これは、主人公の座標とカメラ座標の差分を求めて行います。

例えば、
・ウィンドウサイズ … 横800×縦600
・主人公 … (X,Y) = (0, 500)
・カメラ左上 … (X,Y) = (0, 0)

とします。

この時、「画面右端付近」というと、X座標が600くらいでしょうか。
(つまり、主人公のX座標と、カメラのX座標との差が
 600以上の時にカメラ座標を修正する
、と考える。)

すると、下記の様になります。
if( g_PlayerPosX - g_CameraPosX > 600 ){
g_CameraPosX = g_PlayerPosX - 600;
}


また「画面左端付近」も同様に考えて、
主人公とカメラのX座標の差分が200未満の時に、
カメラ座標を修正
するようにします。

if( g_PlayerPosX - g_CameraPosX < 200 ){
g_CameraPosX = g_PlayerPosX - 200;
}


まとめると下記になります。
if( g_PlayerPosX - g_CameraPosX > 600 ){
g_CameraPosX = g_PlayerPosX - 600;
}else if( g_PlayerPosX - g_CameraPosX < 200 ){
g_CameraPosX = g_PlayerPosX - 200;
}


【補足】
「もっと早めにカメラが動いてくれないと、
進んだ先に何があるのか分からない!」と感じた場合
は、
上記の600を500にしてみたり、200を300にしてみたりして、
微調整すればOKだと思います。


■カメラワークの修正その2
で、あともう一つ条件を追加せねばなりません。
マップが存在しない場所にまで
カメラは動いてもらっては困る
ので、

【参考画像】
Sample_20131217_5.jpg


全体マップの外側をカメラが映すような状態になった場合は、
カメラの位置を調整する様にします。

右へ移動して、マップの終端が見える状態になる場合は、
下記の様に「カメラの映す領域の右端 = マップの末端」になるように調整すればOK。

【参考画像】
Sample_20131217_6.jpg


これも、どうプログラムを書けば実装出来るのか考えてみます。

これは簡単で、下記の様にすれば実装出来ます。
------------------------------------------------------
カメラの座標 + ウィンドウの横幅の値が、
マップの横幅を超えれば、

(マップの横幅 - ウィンドウの横幅)を、カメラ座標とする

------------------------------------------------------

マップの横幅 … 1000
カメラの座標 … 250
ウィンドウの横幅 … 800
とすると、

if( 250 + 800 > 1000 ){
g_CameraPosX = 1000 - 800;
}

となります。

全部変数にすると、
if( g_CameraPosX + WND_WIDTH > MAP_WIDTH ){
g_CameraPosX = MAP_WIDTH - WND_WIDTH;
}

になります。

左方向へ移動し、
左側にマップが表示されない領域が出来る場合
の処理は、
下記の様になります。
if( g_CameraPosX < 0 ){
g_CameraPosX = 0;
}

※マップの左端のX座標は、0とする。
つまり、マップの横幅が1000の場合は、
0~999までがX座標の取りうる範囲とする。

左にはみ出す場合は、判定方法が少し楽になります。
(右端の場合は、左上のX座標 + ウィンドウの横幅で、
  右端の座標を調べる手間が発生するのですが、左端はカメラ座標をそのまま使えば良い。)


まとめると、下記の様になります!
if( g_PlayerPosX - g_CameraPosX > 600 ){
g_CameraPosX = g_PlayerPosX - 600;
}else if( g_PlayerPosX - g_CameraPosX < 200 ){
g_CameraPosX = g_PlayerPosX - 200;
}

if( g_CameraPosX + WND_WIDTH > MAP_WIDTH ){
g_CameraPosX = MAP_WIDTH - WND_WIDTH;
}else if( g_CameraPosX < 0 ){
g_CameraPosX = 0;
}


※上記の判定方法は、ウィンドウサイズ < マップのサイズを想定しています。
なので、ウィンドウが800×600に対し、マップサイズが100×100しかないという、
意味不明な状況に関しては考慮していません。
(カメラの座標を移動させるまでも無く、マップ全体が実行画面に収まる場合。)


さて、これで、
必要な時にだけカメラワークが行われるし、
マップが存在しない部分が映されそうになった場合も、
マップが存在する範囲のみが映る様にカメラ座標が修正される
し、
問題ない、と考えられるはずです。

しかし…、結論から言います。
これだけでは、不十分です。

特にアクションゲームにおいては、
致命的に、おかしなカメラワークが行われる
パターンが発生
します。


さて、そのおかしなカメラワークが発生する条件とは何か。
また、その対象方法は何か。

カメラワーク実装方法 ~後編~ で纏めます…!
お楽しみに…!!(`・ω・´)
スポンサーサイト

テーマ : ゲーム製作 関連 - ジャンル : ゲーム

コメント
コメントの投稿
管理者にだけ表示を許可する



上記広告は1ヶ月以上更新のないブログに表示されています。新しい記事を書くことで広告を消せます。