2013年06月14日

クォータービューの作り方

 最近は3Dを駆使した映像表現が多くなり、クォータービューで表現されたゲームは随分減ったように感じます。しかし、クォータービュー特有の箱庭感は3Dとはまた違う良い味が出ると思うのは私だけでしょうか?今回はそのクォータービューの作り方についてです。

 そもそもクォータービューとは拙作鉄道事業戦略のようなスプライト表示です。英語ではIsometricViewと言われるようです。

図1
鉄道事業戦略

 で、スクリーン座標系(ディスプレイに対しての座標)とクォータービュー座標系(ゲーム内部処理での座標)を相互変換してやらなければなりません。何らかの関係はありそうですが、頭の中でぐるぐる考えてもオーバーヒートしそうです。そこで、高校数学Bで出てくるベクトルを使って、二つの座標系の関係を整理しましょう。例えば下図のようなクォータービューの場合です。座標の上段がクォータービュー座標、下段が各マス頂上のスクリーン座標です。

図2
iso02.png

 クォータービュー座標系をベクトルで表すと、X軸方向1マスはVix=(32,16)、Y軸方向1マスはViy=(-32,16)と書けます。クォータービュー座標はこの組み合わせで表現できます。例えば、クォータービュー(3,2)地点は3*Vix+2*Viyとなります。

図3
iso03.png

 これを解いてやると、スクリーン座標は(3*32+2*(-32),3*16+2*16)=(32,80)。図2と一致しているのが分かります。あとは方程式を作ってやればプログラムはできそうです。

【クォータービュー座標をスクリーン座標へ変換】
 Xs = Xc + Xi・Xx + Yi・Xy
 Ys = Yc + Xi・Yx + Yi・Yy

 但しXi,Yiはクォータービュー座標、Xs,Ysはスクリーン座標、Vix=(Xx,Yx)、Viy=(Xy,Yy)、クォータービュー座標(0,0)でのスクリーン座標をXc,Ycとする。

 スクリーン座標をクォータービュー座標へ変換するには上記連立方程式のXi,Yiについて求めます。

【スクリーン座標をクォータービュー座標へ変換】
 Xi = (Yy(Xs - Xc) - Xy(Ys - Yc)) / (Xx・Yy - Xy・Yx)
 Yi = (Yx(Xs - Xc) - Xx(Ys - Yc)) / -(Xx・Yy - Xy・Yx)
※2014/06/27 ミスを修正いたしました。ご指摘有難うございました。

 余談ですが、プログラミングに数学は必要ないという意見もあります。作成するソフトによっては確かにそうでしょう。しかしゲーム製作では、この例でも分かるように数学はプログラミングの大きな助けになると思います。数学を勉強している学生諸君は苦手意識を持たずに積極的に勉強することをお薦めします。

 あとはクラスに落とし込んでいくだけです。

【メンバ変数】
double xpx,ypx:ベクトルVix
double xpy,ypy:ベクトルViy
double posx,posy:
   クォータービュー(0,0)地点のスクリーン座標。描画位置調整。
double denom:後述

【メンバ関数】
int init(int srcx_per_x_axis, int srcy_per_x_axis,
     int srcx_per_y_axis, int srcy_per_y_axis):
     Vix,Viyベクトルの設定
int set_srcpos(int srcpos_x,int srcpos_y):表示位置の設定
int srcx(double isox,double isoy):スクリーンX座標取得
int srcy(double isox,double isoy):同Y座標取得
double isox(int srcx,int srcy):クォータービューX座標取得
double isoy(int srcx,int srcy):同Y座標取得
int srcpos_x():クォータービュー(0,0)のスクリーンX座標取得
int srcpos_y():同Y座標取得
int srcx_per_x_axis():VixのX座標取得
int srcy_per_x_axis():同Y座標取得
int srcx_per_y_axis():VixのX座標取得
int srcy_per_y_axis():同Y座標取得

 それぞれの座標取得関数は上記で求めた方程式をそのまま書くだけ。わざわざここにソースコードを書くまでもないでしょう。
 クォータービューを求める方程式の分母(Xx・Yy - Xy・Yx)はdenomとして予めinit()で計算します。計算処理速度向上もありますが、0除算エラーの防止が主目的です。
 クォータービュー座標は小数点以下での正確な座標が計算されます。マス頂上なら少数点以下 .0、マス中央なら小数点以下 .5、と言った具合です。
 画像表示する場合は注意が必要です。クォータービュー座標から得られたスクリーン座標はあくまでも菱形の頂上の点の座標です。そのままだとマウス操作時等でずれが生じます。描画時はさらに左へ動かしましょう。

さて、init()で数値を変えてやれば次のように色々な視点にできます。

図4
iso04.png
図5
iso05.png

 設定方法ではSLGに限らず奥行きのある2Dアクションゲームにも応用が出来るのではないでしょうか?応用範囲の広いクラスだと思います。


今回のソースコード
isometricview.zip



posted by ぷーすけ at 19:48| Comment(4) | プログラミング
この記事へのコメント
はじめまして。
SLGゲームを作りたく、クォータービューの実装方法を検索かけていたら見つけました。XNAで組んでいるのですが変換させる公式は合ってると思います。
恐縮なのですが、これらの関数群のゲームでの使い方を書いて頂けませんでしょうか?
宜しくお願い致します
Posted by yan at 2014年03月05日 00:36
はじめまして。ぷーすけと申します。

マップチップを描画させる際に、スクリーンに映るマス全てに
ループでアクセスすることになると思います。
その描画関数でスクリーン座標を指定する時に
上記公式で求めた結果を代入する形になると思います。

XNAは専門外なので、これ以上は別所でお尋ねになるのをオススメします。
Posted by ぷーすけ at 2014年03月05日 20:09
【スクリーン座標をクォータービュー座標へ変換】の公式に括弧が足りてないっす。

誤) Xi = Yy(Xs - Xc) - Xy(Ys - Yc) / (Xx・Yy - Xy・Yx)

正) Xi = (Yy(Xs - Xc) - Xy(Ys - Yc)) / (Xx・Yy - Xy・Yx)

意味を理解せずにコピペしていたらうまくいかず、添付されているソースコードを見て気づきました。
Posted by at 2014年06月18日 15:35
ミスを確認いたしました。申し訳ありません。
修正致しました。
Posted by ぷーすけ at 2014年06月27日 00:29
コメントを書く
お名前:

メールアドレス:

ホームページアドレス:

コメント: