HSP3 ゲームのプログラミング | |
(5) キャラクタ同士の衝突判定
画像に赤色のバーを追加して、キャラクタとバーの衝突について考える。
ダウンロード move3.bmp (58.6KB)
図のように、それぞれの画像は指定した座標に画像の左上が来るように描画される。 図では、キャラクタは座標(x0,y0)に描画され、バーは座標(x1,y1)に描画される。この座標(x0,y0)と(x1,y1)を比較して、一致すれば衝突した、一致しなければしていないと判定できる。判定は、一度にできないので、条件式は「x0 = x1 & y0 = y1」と記述する。 しかし、1点だけで衝突判定すると実際にはなかなか衝突にはならない。ある程度、範囲を持たせて判定することになる。例えば、「x0 - 10 <= x1 & x0 + 10 >= x1 & y0 = y1」と記述するとx座標が左右10ドットの範囲で衝突したと判定される。範囲は内容によって変更が必要である。 |
まず、x方向について考える。実際には図のように、2つの画像から見た目で衝突している範囲を考えて、衝突の範囲を決定する。図では、±16ドットの範囲で衝突したと判定するのが適当とした。 |
y方向についても、図のように4ドットの範囲(y0+28≦y1≦y0+32)で衝突とさせる。条件式は次のようになる。 |
以上から、衝突判定の条件式は次のようになる。
abs(x0 - x1) <= 16 & abs(y0 - y1 + 30) <= 2
図のように、x方向のサイズが違う場合も、y方向で示したような式の変形が必要になる。 図のように衝突の判定をするとき、x0 <= x1 かつ x0 + 16 >= x1 となる。 x0<=x1 → x0-x1<=0 → x0-x1+8<=0 + 8 → x0 - x1 + 8 <= 8 x0+16>=x1 → x0-x1>=-16 → x0-x1+8>=-16+8 → x0 - x1 + 8 >= -8 x0 - x1 + 8の計算結果は、-8 〜 8の範囲になる。したがって、条件式は次のようになる。 abs(x0 - x1 + 8) <= 8 … 条件式A’’ |
(move51.hsp)
キャラクタをバーで打ち返す。
buffer 1
;ウィンドウID 1番 picload "move3.bmp" ;画像ファイル読み込み screen 0 ;ウィンドウID 0番 gmode 2, 32, 32 ;コピーモード設定 x0 = 100 : y0 = 100 ;キャラクタの座標 dx0 = 8 : dy0 = 8 ;キャラクタの移動量 x1 = 100 : y1 = 450 ;バーの座標 dx1 = 16 : dy1 = 0 ;バーの移動量 repeat redraw 0 ;仮描画 color 255, 255, 255 ;白色。背景と同じ色。 boxf ;ウィンドウと同じサイズの四角形を塗りつぶしで描画する。 color 0, 0, 0 ;黒色 |
|
pos x0, y0
;カレントポジション設定 gcopy 1, 0, 0 ;画像コピー pos x1, y1 ;カレントポジション設定 gcopy 1, 64, 0, 32, 8 ;画像コピー |
キャラクタとバーの 描画処理 |
if abs(x0 - x1) <= 16 & abs(y0 - y1 + 30) <= 2 : dy0 = -dy0 ;衝突判定 | 衝突判定 |
x0 = x0 + dx0 ;x座標加算 y0 = y0 + dy0 ;y座標加算 if x0 >= ginfo_winx - 32 : dx0 = -dx0 ;右壁に衝突。 if x0 <= 0 : dx0 = -dx0 ;左壁に衝突。 if y0 >= ginfo_winy - 32 : dy0 = -dy0 ;下壁に衝突。 if y0 <= 0 : dy0 = -dy0 ;上壁に衝突。 |
キャラクタの 座標計算 と 判定 |
stick key, 15 ;キー入力 if key & 1 : x1 = x1 - dx1 ;左 if key & 4 : x1 = x1 + dx1 ;右 if key & 128 : end ;[Esc] if x1 <= 0 : x1 = 0 ;左壁に衝突 if x1 > ginfo_winx - 32 : x1 = ginfo_winx - 32 ;右壁に衝突 |
キー入力とバーの 座標計算 と 判定 |
redraw 1 ;実描画 await 100 ;無限ループの時のお約束 loop stop |
キャラクタをバーで打ち返すとキャラクタがはね返る。打ち返しに失敗しても下の壁ではね返る。
キー入力とバーの座標計算にある判定は、左右のウィンドウ枠を超えないようにするものである。この判定の2行は次のようにlimit命令(関数)で書き換えることができる。
x1 = limit(x1, 0, ginfo_winx - 32)
サンプルプログラムの衝突判定には「条件式A’」を使っている。これを「条件式A」に変えて実行せよ。
if abs(x0 - x1) <= 16 & abs(y0 - y1 + 30) <= 2 : dy0 = -dy0
↓
if abs(x0 - x1) <= 16 & y0 + 32 = y1 : dy0 = -dy0
バーで打ち返すことができない。
原因は、バーのy1(y座標)は450で、キャラクタのy0(y座標)は100から8(dy0)ずつ増える。しかし、y0が450になることはないので衝突したと判定されない。
y0+32の変化 132 140 148 156 164 172 180 188 196 204 212 220 … 396 404 412 420 428 436 444 452
対策としては、次のようにキャラクタとバーの座標を移動量から計算する。
dx0 = 8 : dy0 = 8 ;キャラクタの移動量
x0 = 10 * dx0 : y0 = 10 * dy0 ;キャラクタの座標
x1 = 10 * dx0 : y1 = 54 * dy0 ;バーの座標
dx1 = 16 : dy1 = 8 ;バーの移動量
もう一つの対策としては、HSP標準のウィンドウサイズは640×480であるが、図のように8ドット単位のグラフ用紙だと考えて、座標はグラフの交点だけを使うようにするとよい。
(move52.hsp)
キャラクタをバーで打ち返す。ただし、画面を8ドット単位のグラフ用紙として考える。
buffer 1 ;ウィンドウID 1番 picload "move3.bmp" ;画像ファイル読み込み screen 0 ;ウィンドウID 0番 gmode 2, 32, 32 ;コピーモード設定 mm = 8 ;間隔 x0 = 12 : y0 = 12 ;キャラクタの座標 dx0 = 1 : dy0 = 1 ;キャラクタの移動量 x1 = 12 : y1 = 55 ;バーの座標 dx1 = 2 : dy1 = 0 ;バーの移動量 repeat redraw 0 ;仮描画 color 255, 255, 255 ;白色。背景と同じ色。 boxf ;ウィンドウと同じサイズの四角形を塗りつぶしで描画する。 color 0, 0, 0 ;黒色 pos x0 * mm, y0 * mm ;カレントポジション設定 gcopy 1, 0, 0 ;画像コピー pos x1 * mm, y1 * mm ;カレントポジション設定 gcopy 1, 64, 0, 32, 8 ;画像コピー if abs(x0 - x1) <= 2 & y0 + 3 = y1 : dy0 = -dy0 ;衝突判定 x0 = x0 + dx0 ;x座標加算 y0 = y0 + dy0 ;y座標加算 if x0 >= (ginfo_winx - 32) / mm : dx0 = -dx0 ;右壁に衝突。 if x0 <= 0 : dx0 = -dx0 ;左壁に衝突。 if y0 >= (ginfo_winy - 32) / mm : dy0 = -dy0 ;下壁に衝突。 if y0 <= 0 : dy0 = -dy0 ;上壁に衝突。 stick key, 15 ;キー入力 if key & 1 : x1 = x1 - dx1 ;左 if key & 4 : x1 = x1 + dx1 ;右 if key & 128 : end ;[Esc] x1 = limit(x1, 0, (ginfo_winx - 32) / mm) redraw 1 ;実描画 await 100 ;無限ループの時のお約束 loop stop
(move97.hsp)
下壁に当たったら、はね返らずにメッセージ(ダイアログ)を表示して、再開または終了できるようにする。
2007 © Hiroshi Masuda |