弾がインベーダーに当たれば得点となるのがこのゲームのルールです。ということで、当たるようにしましょう。
まずは変数を用意します。
int iStateHou; // 砲台表示状態
砲台の弾の移動処理の中で当たったかどうかの判定を入れます。
void GmMoveTamaHou(void)
{
if (posTamaHou.x == -1) { // 表示中ではない
return;
}
PatBlt( hdcScreen, // 対象のHDC
posTamaHou.x, // 表示位置 X座標
posTamaHou.y, // 表示位置 Y座標
32, // 表示サイズ 幅
24, // 表示サイズ 高さ
WHITENESS ); // 白で塗りつぶす
posTamaHou.y -= 24; // 上へ昇る
if (posTamaHou.y <= 0) { // 上端を越えた時
posTamaHou.x = -1; // 表示終了
} else {
BitBlt( hdcScreen, // 転送先HDC
posTamaHou.x, // 表示位置 X座標
posTamaHou.y, // 表示位置 Y座標
32, // 表示サイズ 幅
24, // 表示サイズ 高さ
hdcBmp, // 転送元HDC
0, // 転送元 X座標
0, // 転送元 Y座標
SRCCOPY ); // そのまま転送
if ((posTamaHou.x == posInv.x) && (posTamaHou.y == posInv.y)) {
PatBlt( hdcScreen, // 対象のHDC
posTamaHou.x, // 表示位置 X座標
posTamaHou.y, // 表示位置 Y座標
32, // 表示サイズ 幅
24, // 表示サイズ 高さ
WHITENESS ); // 白で塗りつぶす
posInv.x = 320 - 32;
posInv.y = 24;
}
}
}
弾とインベーダーの大きさが異なる場合や、移動量が異なる場合、当たり判定はもっと複雑になりますが、今回はキャラクタのサイズを規定して、移動量もそれにあわせているため、弾の座標値とインベーダーの座標値が一致しているかどうかで当たりの判定が行えます。
次に、インベーダーの弾の移動処理の中に砲台との当たり判定を入れます。こちらも同様に、弾の座標値と砲台の座標値との比較で当たったかどうかの判定を行います。
void GmMoveTamaInv(void)
{
PatBlt( hdcScreen, // 対象のHDC
posTamaInv.x, // 表示位置 X座標
posTamaInv.y, // 表示位置 Y座標
32, // 表示サイズ 幅
24, // 表示サイズ 高さ
WHITENESS ); // 白で塗りつぶす
posTamaInv.y += 24; // 下へ落ちる
if ((posTamaInv.x == posHou.x) && (posTamaInv.y == posHou.y)) {
iStateHou = 1;
posTamaInv.x = posInv.x; // 表示終了
posTamaInv.y = posInv.y + 24;
}
if (posTamaInv.y >= 240-24) { // 下端を越えた時
posTamaInv.x = posInv.x; // 表示終了
posTamaInv.y = posInv.y + 24;
}
BitBlt( hdcScreen, // 転送先HDC
posTamaInv.x, // 表示位置 X座標
posTamaInv.y, // 表示位置 Y座標
32, // 表示サイズ 幅
24, // 表示サイズ 高さ
hdcBmp, // 転送元HDC
0, // 転送元 X座標
0, // 転送元 Y座標
SRCCOPY ); // そのまま転送
}
インベーダーの方は、弾が当たってもゲームが継続するので特別な処理は不要ですが、砲台は3台破壊されると終わりなので、その処理が必要となります。そこで、弾が砲台に当たったときにステータスを変更し、後でそのステータスを判定して砲台が破壊されたときの処理を行うようにします。
WM_TIMERが通知されたときに弾とインベーダーが動いています、砲台が爆発している間はこれらを一時的に止めてしまいます。
case WM_TIMER:
switch (iStateHou) {
case 0: // ゲーム中
GmMoveInv();
GmMoveTamaInv();
GmMoveTamaHou();
GmMoveHou();
break;
case 1: // 破壊
GmDestroyHou();
break;
}
InvalidateRect(hWnd, NULL, FALSE);
break;
砲台が破壊されたときは、少しだけ爆発を表現してみます。二つの絵を交互に表示するとそれらしく見えることでしょう。枚数を増やせばもっと違った爆発も表現できますが、それは各自考えてみてください。
void GmDestroyHou(void)
{
static int iInvTime = 0;
iInvTime++;
if (iInvTime % 2) {
if (iInvTime > 10) {
iInvTime = 0;
posHou.x = 0; // 表示位置 X座標
iStateHou = 0; // 元の処理へ戻す
}
BitBlt( hdcScreen, // 転送先HDC
posHou.x, // 表示位置 X座標
posHou.y, // 表示位置 Y座標
32, // 表示サイズ 幅
24, // 表示サイズ 高さ
hdcBmp, // 転送元HDC
64, // 転送元 X座標
24, // 転送元 Y座標
SRCCOPY ); // そのまま転送
} else {
PatBlt( hdcScreen, // 対象のHDC
posHou.x, // 表示位置 X座標
posHou.y, // 表示位置 Y座標
32, // 表示サイズ 幅
24, // 表示サイズ 高さ
WHITENESS ); // 白で塗りつぶす
}
}
さて、ここまで変更したらビルドしてみましょう。
さきほど、砲台が3台破壊されるとゲームが終わると言いましたが、実は、まだ終わりの処理が入っていません。砲台の数も設定していないし、残機数の表示もしていないからです。それらは、もう少し先で実装します。その前に、次回は得点の表示を追加しましょう。