アクションゲームでは、キャラクタや背景の「当たり判定」や移動・消滅などに伴う「画面描き換え」が必要になります。このような処理を行う方法はいくつかあるのですが、今回はその中でも最も単純な画面の情報を記憶する配列を作成する方法をブロック崩しを例に試してみましょう。 画面の構造 画面の情報を配列に記憶するには、まず画面をキャラクタと同じ大きさ(32ピクセル前後が多い)でグリッド状に分割します。通常ゲーム画面は、16×16キャラクタ程度ですので配列も16×16程度の大きさになるでしょう。こうして画面をキャラクタ単位の座標に分けたら、各座標の情報を数値として2次元配列に記憶して行きます。これは、その座標に何があるかを表すもので、例えば何もなければ0、ブロックがあれば1、自機がいれば2、ボールがあれば3、などと適当に決めておきましょう。 今回のブロック崩しでは、キャラクタを32×32ピクセル、画面の大きさを16×16キャラクタ(512×512ピクセル)としました。画面情報配列の値は、何もなければ0、壁があれば1、自機なら2、ブロックがあれば3とします。この辺りは、今後キャラクタを増やしたりすると変わってくるので適当に作っておけば良いでしょう。あるいは、キャラクタの番号を先頭のdefineで定義するようにしてプログラムでは直接数値を使わないようにすると修正が楽かもしれませんね。 lpBuf=(LPBYTE)GlobalAlloc /* DIB用メモリ確保 */ (GPTR,sizeof(BITMAPINFO)+255*sizeof(RGBQUAD)+512*512+32*32*4); lpDIB=(LPBITMAPINFO)lpBuf; /* DIB用メモリを分配 */ lpRGB=(RGBQUAD*)(lpBuf+sizeof(BITMAPINFOHEADER)); lpScreen=lpBuf+sizeof(BITMAPINFO)+255*sizeof(RGBQUAD); /* 画面ビットマップ */ for (i=0;i<4;i++) /* キャラクタ用ビットマップ配列 */ lpChr[i]=lpScreen+512*512+32*32*i; 画面とキャラクタのビットマップを作成したら、画面情報配列を初期化します。 /* 画面情報配列初期化 */ FillMemory(map[0],256,1); /* 全体を壁で塗りつぶす */ for (i=0;i<15;i++) /* ブロックとタイル配置 */ for (j=1;j<15;j++) if (i<8) map[j][i]=0; else map[j][i]=3; map[iX][iY]=2; /* 自機の初期位置 */ こうして、画面の用意が出来たらメインループに入ります。後は、このメインループ内で終了まで移動・描画処理を繰り返すわけです。 メインループでの移動と描画処理メインループでは、最初にゲーム画面のビットマップ全体を描き換えます。画面情報配列(map[][])を参照すれば、画面上のどこに何があるのか、という情報を取得できるので2重ループで配列を参照しながら一気に画面全体を描いてしまいましょう。 for (i=0;i<16;i++) /* マップ情報で画面作成 */ for (j=0;j<16;j++) for (k=0;k<32;k++) CopyMemory(lpScreen+j*32+(k+i*32)*512,lpChr[map[j][i]]+k*32,32); 画面情報配列には、キャラクタ番号を入れてあるのでmap[x][y]とすれば座標(x、y)にあるキャラクタ番号を取得できます。後は、キャラクタ番号をキャラクタのビットマップ配列のインデックスにして描くべきキャラクタの先頭アドレスを取得すれば良いですね。 画面を描き換えたら、キー入力の取得と自機の移動を行います。自機の移動は、移動しようとしている先に何もなければ(タイル状の床?なら)自機の座標を更新し画面情報配列に新しい座標を書いて以前の座標を消すだけです。こうしておけば、次回のメインループの処理の先頭で新しい位置に自機が描画されます。 /* 自機の移動 */ if (GetAsyncKeyState(VK_RIGHT)<0 && map[iX+1][iY]==0) { /* 右方向 */ map[iX][iY]=0; /* 現在の座標をクリア */ map[++iX][iY]=2; /* 新しい座標を設定 */ } if (GetAsyncKeyState(VK_LEFT)<0 && map[iX-1][iY]==0) { /* 左方向 */ map[iX][iY]=0; /* 現在の座標をクリア */ map[--iX][iY]=2; /* 新しい座標を設定 */ } プログラムVC++でビルド、実行してみてください。 カーソルキーで自機を左右に移動できます。キャラクタ単位(32ピクセル単位)の移動なので動きはかなり粗いですね。滑らかにするには、画面情報のグリッドを細かくする(例えば1/2キャラクタ単位とか)、あるいは動きのあるキャラクタは画面情報とは別管理とする、などの方法が考えられるでしょう。 次回はボールの移動と当たり判定を入れてとりあえず「ブロック崩し」ができるようにしてみます。 |