ページ 11

クォータービューでの描画とマップの配列のデータの持ち方について

Posted: 2010年7月09日(金) 17:07
by KEYONN_
おはようございます。こんにちは、こんばんわ、みなさん。
TKOZです。

ところで、現在、クォータービュー形式のゲームを作っております。
クォータービューの(一般的な?)描画方法と配列のデータの持ち方と
どうやれば、マウス座標などから配列を参照できるのかについて質問します。

私は、私なりにクォータービューを紙に印刷し、関数電卓とシャープペンシル、消しゴムなどで
計算し、求めた値に基づいて描画なり、配列を計算したのですが、
どうもうまくいきませんので、質問したいです。

具体的には、マウス座標から配列を参照するやり方がわかりません。
バグが出ており、右上が0,0とすると、目で測って求めた値とは違うのです。

そのほかに、一般的なクォータービューの描画方法や配列のデータの持ち方も質問したいです。

ソースコードを添付するので、どうか、C言語何でも質問掲示板の皆様、よろしくお願いします。
#pragma once
#include"Main.h"
#include "DxLib.h"
#include "parser.c"

int GHandle;

#define SCREEN_WIDTH 800
#define SCREEN_HEIGHT 600
#define CHIP_WIDTH 128
#define CHIP_HEIGHT 64
#define MAX_CHIPX (21)
#define MAX_CHIPY (17)

typedef struct n3d{
int x;//X座標
int y;//Y座標
int z;//Z座標
}n3d;

typedef struct Chara{
int MovingValue;//移動量
int HP;//HP(ヒットポイント
int MP;//MP(マジックポイント
int HavingItem[100];//持っているアイテムの数と種類
int ii[MAX_CHIPY][MAX_CHIPX];//移動用の表示配列データ
int jj[MAX_CHIPY][MAX_CHIPX];//移動用の表示配列データ
}Chara;
class SLGMode{
public:
n3d xyz;//キャラの座標
n3d show;//現在のいるマスの座標
n3d menu;//メニューの座標
int menuflag;//メニューの表示フラグ
int menunumber;//現在マウス座標の上にあるメニューの番号
int image[100];//イメージ配列
int moveflag;//移動フラグ
int selectnumber;//現在マウスで選択されているメニュー番号
int dir;//移動方向
int MoveMode;//移動状態
int Divimage[4];//4種類のマップチップのイメージ配列
Chara C;//主人公キャラの情報
public:
SLGMode()//コンストラクタ(初期化関数)
{
xyz.x=256+128+128;
xyz.y=224;
show.x=256+128;
show.y=224;
menu.x=0;
menu.y=0;
menuflag=0;
menunumber=0;
moveflag=0;
dir=0;
C.MovingValue =5;
}
void DrawBlock()//マップチップ?を描画する関数
{
int i,j;
for(i=0;i<17;i++)
{
static int flag=0;
static int X=0,Y=0;
for(j=0;j<21;j++)
{
int Sub=0;
if(flag==0)
{

Sub=128*(i+1);

X=(640+128+128)-Sub;
Y=-32;
flag=1;
}

DrawGraph(X,Y,
Divimage[BGData[j]],TRUE);
X+=64;Y+=32;
}
flag=0;
}

}
void DrawLINE()//線を描画するメンバ関数
{
int i,j;

//DrawBox(0,0,800,600,GetColor(255,255,255),TRUE);

DrawRectGraph(show.x,show.y,0,0,128,64,image[0],TRUE,FALSE);


for(i=0;i<MAX_CHIPY;i++)
{
for(j=0;j<MAX_CHIPX;j++)
{
DrawLine(j*CHIP_WIDTH,i*CHIP_HEIGHT , j*CHIP_WIDTH+CHIP_WIDTH , i*CHIP_HEIGHT+CHIP_HEIGHT ,
GetColor(255,255,255) ) ;
DrawLine(j*CHIP_WIDTH,i*CHIP_HEIGHT , i*CHIP_WIDTH , j*CHIP_HEIGHT ,
GetColor(255,255,255) ) ;

}
}
DrawGraph(xyz.x-96,xyz.y-64,image[1],TRUE);
}
//関係の無いメンバ関数は飛ばす
int GetXOfIndex(int NowX,int NowY)//現在座標からBGData配列の添え字を取得する関数
{
int i,j;
int X2=9-NowX/128-2;
int X=17-NowX/64-4*X2-1;
int XX=X,YY=0;

do{
XX-=2;
YY+=1;
}while(NowY/32+1==YY);
return X;
}
int GetYOfIndex(int NowY)//現在座標からBGData配列の添え字を取得する関数
{
int i,j;

return NowY/32+1;
}

Re:クォータービューでの描画とマップの配列のデータの持ち方について

Posted: 2010年7月09日(金) 21:18
by パコネコ
クオータービューってこういうのですよね
____________→x
/_/_/_/_/_/_/
/_/_/_/_/_/_/
/_/_/_/_/_/_/
↓y
…もっと斜めだった気がするけど

   →X
  /\
 /\/\
/\/\/\
\/\/\/
 \/\/
↓Y
…こんな感じ
前に計算した時は、1マスの横幅をMxとして、縦幅をMyとして
座標x=Mx*(x+y)
座標y=My*(y-x)
で左上からのマス目をx、yとした時の式でした。
間違ってたり、すでに出してましたらすいません。
で、これがあってるとして計算してみると
マウスから習得した座標をpx,pyとした場合
px=Mx*(x+y)
px/Mx=x+y
ここで止まっちゃいました…
py=My*(y-x)
py/My=y-x
これを代入して
py/My+x=yを使って
px/Mx-py/My-x=x
px/Mx-py/My=2x

x=(px/Mx-py/My)/2
y=py/My+(px/Mx-py/My)/2
これが、出てきました。
yのほうをきれいにして、
2*y=2*py/My+px/Mx-py/My
y=(px/Mx+py/My)/2

よって

x=(px/Mx-py/My)/2
y=(px/Mx+py/My)/2

これでどうですか?
今計算したんで計算ミスがあるかもですが…

Re:クォータービューでの描画とマップの配列のデータの持ち方について

Posted: 2010年7月09日(金) 21:47
by MNS
マウス座標 → マップ座標は、
確か、y座標の差分を補正した後、グリッドの高さと幅の比率をあわせて、求める
という段階を踏んでいたと記憶しています.

そうしますと、マウスの座標をmouse_x,mouse_yという変数に記憶しておいて、
差分を補正
mouse_y -= CHIP_HEIGHT/2 * MAX_CHIPX;
グリッドの縦横比を考慮して
mouse_y *= CHIP_WIDTH/CHIP_HEIGHT;
あとは求めて
map_x = (mouse_x - mouse_y) / CHIP_WIDTH;
map_y = (mouse_x + mouse_y) / CHIP_WIDTH;

負の値になると、1グリッドずれるので注意してください

Re:クォータービューでの描画とマップの配列のデータの持ち方について

Posted: 2010年7月09日(金) 23:41
by Poco
やらなければならないのは、ひし形っぽく交差する軸を持つ座標系から、正方格子のような軸を持つ座標系への変換ですよね?
なんとなくですけど、一次変換を利用するとうまく計算出来ると思います。
↓のようなイメージで。
http://keysformath.seesaa.net/article/17244983.html

----追記
MNSさんが書かれている算出方法がまんま一次変換ですね。。 画像

Re:クォータービューでの描画とマップの配列のデータの持ち方について

Posted: 2010年7月10日(土) 00:13
by パコネコ
# MNSさん
CHIP_WIDTHって何を表わすんですか?
勉強不足ですいません。

Re:クォータービューでの描画とマップの配列のデータの持ち方について

Posted: 2010年7月10日(土) 11:48
by MNS
># MNSさん
>CHIP_WIDTHって何を表わすんですか?

私は、1グリッド(マップチップ単体)の幅として使用しました。
TKOZさんのコードから引用したものです。そのようなものとして使っていたのなら良いのですけれど。

Re:クォータービューでの描画とマップの配列のデータの持ち方について

Posted: 2010年7月10日(土) 19:15
by パコネコ
クオータービューって「 基本的 」に縦横の大きさは同じなのでしょうか?

Re:クォータービューでの描画とマップの配列のデータの持ち方について

Posted: 2010年7月10日(土) 19:43
by KEYONN_
>パコネコさん
>MNSさん
>ぽこさん
返信とアドバイスありがとうございます。
今、ちょっと時間が無いので、明日試してみる事にします。

Re:クォータービューでの描画とマップの配列のデータの持ち方について

Posted: 2010年7月11日(日) 18:06
by KEYONN_
あの、右上座標(896,0)を(0,0)としたいのですが、
その場合は補正値を加えるだけでよろしいのでしょうか? 画像

Re:クォータービューでの描画とマップの配列のデータの持ち方について

Posted: 2010年7月11日(日) 19:55
by Poco
MNSさんが述べられた算出方法の後に、左上原点のmap_xを右上原点に変換したほうが良いと思います。

#この作業を補正といえば補正ですが。。

Re:クォータービューでの描画とマップの配列のデータの持ち方について

Posted: 2010年7月13日(火) 17:00
by KEYONN_
単純に足したり引くだけでは0,0に変換できない事が分かりました。
どうすれば、(896,0)を0,0に出来るのでしょうか?
ヒントかアドバイスをください。

Re:クォータービューでの描画とマップの配列のデータの持ち方について

Posted: 2010年7月13日(火) 19:05
by MNS
何をしたいのか、いまいち良くわからないのですが、
画面の原点を896,0に移し、かつX軸の向きを逆にしたい場合は、
マウスのx座標をmouse_xという変数に格納しておいたとすると、
mouse_x = abs(mouse_x - 896);
とするのはどうでしょうか?

Re:クォータービューでの描画とマップの配列のデータの持ち方について

Posted: 2010年7月14日(水) 19:58
by KEYONN_
何度も何度もすみません。
添付した画像のようには出来ないでしょうか?

もちろん、というかおそらくこれが出来るなら計算も出来るだろうと思われると思いますが、
うまくいかないんです。

原因は分かっています。(多分…?)GetXOfIndex()でif(NowX==X && NowY==Y)という記述がありますが、
事前の計算ですでにそれを超えてます。どうすれば、座標からインデックスを取り出せるでしょうか?
GetOfIndex2()は、原因が分かりません。

その関数を5つ書きます。

void DrawBlock()//ブロック(マップチップを描画する関数)
{
int i,j;
static int xx,yy;
xx=0;yy=0;
for(i=0;i<17;i++)
{
static int flag=0;
static int X=0,Y=0;
xx=0;
for(j=0;j<21;j++)
{
int Sub=0;
if(flag==0)
{

Sub=128*(i+1);

X=(640+128+128)-Sub;
Y=-32;
flag=1;
}

DrawGraph(X,Y,
Divimage[BGData[j]],TRUE);
X+=64;Y+=32;
xx++;
DrawFormatString(X,Y,GetColor(255,255,255),"(%d,%d)",yy,xx);
}
yy++;
flag=0;
}
yy=0;

}
int GetXOfIndex2()
{
int mouse_x,mouse_y;
GetMousePoint(&mouse_x,&mouse_y);
mouse_x -= CHIP_HEIGHT/2 * MAX_CHIPX;
mouse_y *= CHIP_WIDTH/CHIP_HEIGHT;
mouse_x = abs(896-mouse_x);

int NowX = (mouse_x - mouse_y) / CHIP_WIDTH-5;
//NowY = (mouse_x + mouse_y) / CHIP_WIDTH;
return NowX;
}
int GetYOfIndex2()
{
int mouse_x,mouse_y;
GetMousePoint(&mouse_x,&mouse_y);
mouse_x -= CHIP_HEIGHT/2 * MAX_CHIPX;
mouse_y *= CHIP_WIDTH/CHIP_HEIGHT;
mouse_x = abs(896-mouse_x);

//NowX = (mouse_x - mouse_y) / CHIP_WIDTH;
int NowY = (mouse_x + mouse_y) / CHIP_WIDTH-5;
return NowY;
}
int GetXOfIndex(int NowX,int NowY)
{
int i,j;
static int xx,yy;
xx=0;yy=0;
for(i=0;i<17;i++)
{
static int flag=0;
static int X=0,Y=0;
xx=0;X=0;
for(j=0;j<21;j++)
{
int Sub=0;
if(flag==0)
{

Sub=128*(i+1);

X=(640+128+128)-Sub;
Y=-32;
flag=1;
}

if(X==NowX && Y==NowY) return xx;
X+=64;Y+=32;
xx++;

}
yy++;
flag=0;
}
yy=0;
return 0;
}
int GetYOfIndex(int NowX,int NowY)
{
int i,j;
static int xx,yy;
xx=0;yy=0;
for(i=0;i<17;i++)
{
static int flag=0;
static int X=0,Y=0;
xx=0;
X=0;
for(j=0;j<21;j++)
{
int Sub=0;
if(flag==0)
{

Sub=128*(i+1);

X=(640+128+128)-Sub;
Y=-32;
flag=1;
}

X+=64;Y+=32;
xx++;
if(NowY==Y) return j;

}
yy++;
flag=0;
}
yy=0;
return 0;
} 画像

Re:クォータービューでの描画とマップの配列のデータの持ち方について

Posted: 2010年7月14日(水) 20:09
by KEYONN_
GetYOfIndex2が上手くいけばなんとかなるのですが…上手くいかないです。
ちなみに、画像の添え字はY,Xの順番です。

Re:クォータービューでの描画とマップの配列のデータの持ち方について

Posted: 2010年7月14日(水) 20:48
by Poco
マウスの位置は・・・・
というメッセージを出す箇所もソースコードを提供してください。

----追記
↑は自分で何とかしました。 画像

Re:クォータービューでの描画とマップの配列のデータの持ち方について

Posted: 2010年7月14日(水) 21:30
by Poco
TKOZさん:

2つ質問があります。
画面の左上を原点とし、x方向が右方向、y方向が下方向となっている座標系をマウス座標系と呼び、
TKOZさんがマップチップの配列の座標系をマップ座標系と呼んだとき、

1.マップ座標系の原点をマウス座標系で表現するとどうなりますか?
 認識のズレをなくすため、(x座標,y座標)という形式で回答ください。

2.マップ座標系での単位ベクトル(1,0)および(0,1)をマウス座標系でのベクトル表現で
 表すとどうなりますか?
 これも認識のズレをなくすため、(x座標,y座標)という形式で回答ください。

Re:クォータービューでの描画とマップの配列のデータの持ち方について

Posted: 2010年7月14日(水) 21:48
by KEYONN_
1は、(0,0)ですね。間違えました。勘違いしてました。(896,0)です。
2は、マップ座標系の単位ベクトル?(1,0)は、(640+128,-32)です。
  (0,1)は、(896+64,0)です。
ベクトルってあのベクトルでしょうか?
  だとしたら、勘違いしてました。
  マップ座標系の単位ベクトル(1,0)は、(1,0)です。
  (0,1)は、(0,1)じゃないでしょうか?
画像

Re:クォータービューでの描画とマップの配列のデータの持ち方について

Posted: 2010年7月14日(水) 22:07
by Poco
> 1は、(0,0)ですね。間違えました。勘違いしてました。(896,0)です。

了解です。

> 2は、マップ座標系の単位ベクトル?(1,0)は、(640+128,-32)です。
>   (0,1)は、(896+64,0)です。
>

すみません、表現が悪かったですね。x座標、y座標ではなく、x成分、y成分というべきでした。

えっと、↑はマウス座標系でのx座標、y座標ですね。
つまり、マップ座標系の各単位ベクトルをマウス座標系での成分で表すと、
X方向は(640+128-896,-32)=(-128,-32)となります。
つまり、マップ座標系でX方向に1進むと、マウス座標系で(-128,-32)進むことになります。

んで、Y方向は(896+64-896,0-0)=(64,0)
つまり、マップ座標系でY方向に1進むと、マウス座標系で(64,0)進むことになります。
これは嘘ですよね?
こういうふうに考えた場合、マップ座標系でY方向に1進むと、マウス座標系でどれだけ
進むことになりますか?

#X方向がこれであっているなら、Y方向は(-128,32)になるはずなんですけどね。
#なんとなく、TKOZさんが掲載された画像と違うような……

Re:クォータービューでの描画とマップの配列のデータの持ち方について

Posted: 2010年7月14日(水) 22:34
by KEYONN_
大きなスケッチブックに白と黒でスクリーンショットを印刷してセロハンテープで張ってみました。
Y方向は、(896+64,32)ですね。

Re:クォータービューでの描画とマップの配列のデータの持ち方について

Posted: 2010年7月14日(水) 22:58
by Poco
そうすると、マップをひとマス描画すると、図の様になります。
赤と青と緑の線で囲まれている領域がひとマスです。
TKOZさんが用意しているマップチップとかなり異なる形になるのですが…

Re:クォータービューでの描画とマップの配列のデータの持ち方について

Posted: 2010年7月14日(水) 23:37
by Poco
用意したマップチップに合わせるなら、図の上下どちらかの様にマップ座標系の
X方向、Y方向を決定したほうが良いと思います。

Re:クォータービューでの描画とマップの配列のデータの持ち方について

Posted: 2010年7月15日(木) 00:27
by 白い時空
このスレッドを見て、自己満足で、
http://dixq.net/g/26.htmlをクォータービューにしてみました。(マウス位置も表示させてみました。)
が、参考にならないかもしれません。関数名とかは適当です。

zero(原点)とvec[0](マップ座標のx方向)とvec[1](マップ座標のy方向)の値を変更してみてください。


これをやるには、行列がわからないとだめなので、高3レベルの数学が必要でした。
分からないとちょっと厳しいかも。
マウスからマップチップの座標を取得するときは逆行列を使う必要がありました。

Re:クォータービューでの描画とマップの配列のデータの持ち方について

Posted: 2010年7月15日(木) 03:22
by Poco
マップチップに対する配列のインデックスのつけ方がおかしい気がしたので、
とりあえず、描画ルーチンだけ直してみました。
微妙に求める結果と違いますが、もう考える気力がありません。
違いは以下のとおりです。
 ・マウス座標→配列のインデックスへの変換で、XとYの結果が入れ替わっている
 ・配列のインデックス(マップチップ座標)のY方向が微妙にずれている。

----
void DrawBlock()
{
for ( int i = 0; i < MAX_CHIPY; i++ ) {
for ( int j = 0; j < MAX_CHIPX; j++ ) {
int X = 832 + 64 * i - 64 * j;
int Y = 32 * i + 32 * j;
DrawGraph(X,Y,
Divimage[BGData[j]],TRUE);
DrawFormatString(X + 64,Y + 32,GetColor(255,255,255),"(%d,%d)",j,i);
}
}
}

//ゲームのメインループに以下を追加
int mx, my;
GetMousePoint(&mx, &my);
DrawFormatString(0,60,GetColor(0,255,255),"マウス位置は、(%d=>%d,%d=>%d)です。",
mx,S.GetXOfIndex2(),my, S.GetYOfIndex2());

Re:クォータービューでの描画とマップの配列のデータの持ち方について

Posted: 2010年7月15日(木) 08:22
by Poco
#ひと眠りすると、原因がすぐに分かるもんですね。

前の描画ルーチンは、No:56680の図の上のパターン、
この投稿の描画ルーチンはNo:56680の図の下のパターンの場合です。
マップ座標系のX方向、Y方向が異なります。
こちらの方だと、GetOfIndex2()等を劇的に変更させる必要はなさそうです。
#微調整は必要ですが。
#MNSさんが提示した変換式は、この方向の座標系が前提だったということですかね。

void DrawBlock()
{
for ( int i = 0; i < MAX_CHIPY; i++ ) {
for ( int j = 0; j < MAX_CHIPX; j++ ) {
int X = 832 - 64 * i - 64 * j;
int Y = 32 * i - 32 * j;
DrawGraph(X,Y,
Divimage[BGData[j]],TRUE);
DrawFormatString(X + 64,Y + 32,GetColor(255,255,255),"(%d,%d)",j,i);
}
}
}

Re:クォータービューでの描画とマップの配列のデータの持ち方について

Posted: 2010年7月15日(木) 15:56
by KEYONN_
TKOZです。何とか解決しました。
力技の2つのテーブル化で対応しました。
また、問題が発生したら、書き込みます。
画像