プチコン3号経験者によるプチコン4まとめ (5) スプライト機能を生かしたシューティングゲーム【後編】

さーて、[【前編】](https://qiita.com/yamachan360/items/77dd7bcf851a8f5f6b12) を引き継いでプチコン4らしい、シューティングゲームのサンプルを完成させましょう。

現状は自機が動き、弾を撃て、敵も1種類ながら攻めてくるけど、当たり判定がないのでゲームとして成立していない、でしたね。今回は当たり判定を中心に実装していきましょう。

# 今回のサンプル動画

![qiita.gif](https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/193519/80d30e5c-73ee-4514-804b-ab83b738542c.gif)

# でもその前に

前回出てきた SPFUNC で、個人的に気になった点がありました。それは

> SPFUNC 内で SPCLR CALLIDX() しても許されるのか？

という点です。高級言語的に考えれば、自分の呼び出し元を削除するわけですから、実行のコンテキストを考えて、かなり行儀の悪いコードです。でもプチコンなら、スマイルブームさんなら、なんとなく許している気もしていて。なにせ便利ですから！

というわけで、[前回のサンプル](https://qiita.com/yamachan360/items/77dd7bcf851a8f5f6b12#%E6%95%B5%E3%82%92%E7%99%BB%E5%A0%B4%E3%81%95%E3%81%9B%E3%82%8B) に以下の行を追加して試してみました。敵機が弾を撃つと、そのまま消滅してしまう、という仕掛けです。
![image.png](https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/193519/1d8a57e9-b56a-010b-049d-d31d958ee679.png)
試した結果、問題なく動作しているように見えます。なので、とりあえず使っていこうと思います。もし何か不具合があれば、報告しますね！

# 自機の当たり判定を実装する

さて、[前回のサンプル](https://qiita.com/yamachan360/items/77dd7bcf851a8f5f6b12#%E6%95%B5%E3%82%92%E7%99%BB%E5%A0%B4%E3%81%95%E3%81%9B%E3%82%8B) に当たり判定を付けてみましょう。まずは敵機や敵弾に当たると、自機が破壊されるようにコードを修正します。

![image.png](https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/193519/39fc55ed-6de0-0f4d-70a3-78118f587ae5.png)

まずは当たり判定のマスクですが、これは単純に 1 を使います。ビット1が自機の当たり判定、というわけです。これは2進数では1桁目のビットが立っている状態(&B0001)ですね。

これを実装したのが、上記のコードの (1)～(3) の `SPCOL` 命令です。(1) が自機、(2)が敵機、(3) が敵弾ですね。

そして(4)のメインループ部分で、自機の当たり判定をチェックするようにしました。今回のサンプルは「Bボタンを押すと即終了」という変わった作りになっていますが、その終了条件に `OR SPHITSP(0)>0` が追加されることで、「自機が敵機や敵弾に当たると即終了」という動作が追加されたわけです。

そして同じく(4)のコードで、メインループを抜けた後に自機の爆発アニメーションを設定しています。Bボタン終了でも自機が爆発しちゃうのは、まあ許してください。

その自機の爆発ですが、(5) で定義されています。`"UV."` 指定がキモで、自機を表示する画像を、3種類の爆発画像を表示するアニメーション設定で置き換えているわけです。ピリオド付きなので、スプライトの自動削除もしてくれて完璧です！

このサンプルを実行した様子がこちら。敵機や敵弾に当たると、自機がこんな感じで爆発してゲーム終了になります。
![2019072216422400-B4374FDA41BFF09D976C1FEA83EFB230.jpg](https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/193519/5b0f8b58-99d7-a182-2bff-c9108e17644a.jpeg)
と、5ヶ所の変更で、自機への当たり判定が実装できました。ぐっとゲームっぽい雰囲気になってきましたね。

※ 自機がやられた場合の音をセットするのを忘れていたことに気がつきました。(4)の最後にBEEP文を追加してみてください

# コードを少し圧縮してみる

さて、この段階でサンプルプログラムが画面いっぱいになってしまいました。2画面以上にしてしまうと、キャプチャしてご紹介するのがちょっと面倒になります。よって見やすさを少し犠牲にしつつ、上記のサンプルプログラムを圧縮してみます。

結果は以下になりました。
![2019072217241500-B4374FDA41BFF09D976C1FEA83EFB230.jpg](https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/193519/8c7a3773-b1d3-f27d-b46f-da4cc64e5ec9.jpeg)
まずコメントを何行か削り、そして命令を `:` で繋いで記述することで、行数を減らしてみました。結果として下のほうに、もうちょっとコードを足せる領域ができました。

ただコードは少しだけ修正しています。前のコードで (1)～(3) は `SPCOL SN,1`と記述していましたが、これだと `1` がスケールの指定になって、マスクとして動作していませんでした。なので `SPCOL SN,0,1` と変更しました。ちなみにこれは `SPCOL SN,,1` でも同じです。

# 弾に当たり判定を実装する

さて、今度は発射された弾に当たり判定をつけてみましょう。自機の弾と敵機の弾が衝突すると、打ち消しあってどちらも消える、という動作にしてみます。

以下が修正したコードです。
![image.png](https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/193519/c1e213f5-5a85-0e0a-6aaf-bebf872ce591.png)
まず、弾の当たり判定マスクは 2 を使います。これは2進数では2桁目のビットが立っている状態(&B0010)ですね。

これを実装したのが、上記のコード (1)～(2) の `SPCOL SN,0,2` 命令です。

そして(3)では、敵弾用の `SPFUC` 関数を定義していて、その中で自機の弾との当たり判定をチェックしています。自機の弾と衝突していたら、衝突相手であるその自機の弾と自分自身(敵弾)を削除する、という単純な処理です。

そして(3)で定義した関数を敵弾のスプライトに指定しているのが(4)の部分です。

と、4ヶ所を修正するだけで、自機の弾と敵弾が打ち消しあうようになり、よりゲームらしさが増してきました。

# 敵機の当たり判定を実装する

さて、最後は敵機の当たり判定を実装しましょう。

敵機に関しては、耐久力(ヒットポイント、HP)を設定して、自機の弾が何発か当たらないと倒せないようなコードにしてみます。
![image.png](https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/193519/ae24cb0e-73d1-b6f2-3b7a-eff5ce9c0d91.png)
まずは例によって `SPCOL` で設定するマスクです。今回は値としては 4、つまり2進数では3桁目のビットが立っている状態(&B0100)を使います。

コード中では (1)～(2) で自機の弾と敵機に指定しています。この時に 4 という値をそのまま使うのではなく、元々のコードのマスク値に4を足した値を使用するのがポイントです。

※ 重ねる際には2進数演算で AND をするのですが、マスクのように異なった桁を利用している場合は、単に値を足してもokなのです。

そして(3)でついに出てきました！ [第3回](https://qiita.com/yamachan360/items/882df02ac3c9c5ea69bc) で出てきた `SPVAR` 命令です。今回は敵機のスプライトに `"HP"` という名前の変数を定義し、そこに敵機の耐久力を設定しています。この敵の場合は 4 という値が設定されていますので、この敵機は自機の弾が4発当たらないと倒せない、となります。

そして今回、一番長い修正になります (4)～(5) の部分を見ていきましょう。これは敵機のスプライトに `SPFUNC` で指定される、`ENEMY1` というルーチンの拡張です。

まず (4) で敵機と自弾の衝突をチェックします。衝突しているようであれば (5) の処理が実施されます。`SPVAR` で格納した `"HP"` の値から 1　を引き、0 以下になれば敵機の爆破処理になります。

なお敵機の爆破処理はちょっと手を抜いて、自機の爆破処理をそのまま流用しています。そして敵機の破壊ごとにスコアを 1 増やしています。

さーて、これで最低限のゲーム要素は実現できました。たった一画面のプログラムですが、それっぽいシューティングゲームが実装できたと思います。
![2019072217492400-B4374FDA41BFF09D976C1FEA83EFB230.jpg](https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/193519/0bd57cb2-0599-d0b6-2f5a-40e2092f7f5b.jpeg)

# というわけで！

2回に渡ってシンプルなシューティングゲームのサンプルを拡張しつつ解説してみましたが、如何だったでしょうか。個人的には一画面ぶんの短いコードで、これだけ実装できるプチコン4の表現力にあらためて感心しました。

【追記】[オマケ編](https://qiita.com/yamachan360/items/cdf07b8fc4b75ff393ac) も投稿しましたので、良かったらもう少しだけ、お付き合いくださいー。

私の投稿に含まれる私の作成した全てのプチコン用コードは [Creative Commons Zero](https://creativecommons.org/publicdomain/zero/1.0/deed.ja) ライセンスとします。好きな段階のものをベースに改造して、自由にお使いください。

それではまた！