0爆弾について
0爆弾というのはスーパーマリオを始め、ファミコンで画面を上下に分割してるゲームではよく使われるテクニックです。具体的には、0番スプライトを画面分割したい位置に配置して$2002をリードし続けます。リードしたときにbit6が立っていたら0番スプライトを描画した瞬間、というわけです。
上の図は以前Tweetしたワルキューレの0爆弾についての説明です。
https://twitter.com/Karu_gamo/status/1357928328842289152
便利な0爆弾ですがいろいろと問題もあります。スーパーマリオのように画面上方で分割する場合、NMIの処理が重すぎるとメインループに戻ってきた時にすでに0爆弾よりも下を描画してたらアウトです(そのフレームは画面が崩れることになります)。音楽やBG書き換えなどのNMI中に行いたい処理の負荷を把握しておく必要がありますね(特に音)。
画面の下の方で分割する場合には、メインループ処理を0爆弾の描画までに終わらせておく(又は中断する)必要があります。確実に処理するためには、早めに0爆弾待ちしなければなりませんので、処理にムダが発生してしまうわけです。
まぁ、その辺の問題はやればわかることですので置いておいて、実装上の問題についてメモを残しておきます。
先ほどは、NMIの負荷が大きかったケースを書きましたが、逆にNMIが早く終わってしまった場合も考慮する必要があります。実は0爆弾の判定はスキャンライン中しか機能しないようです。ですのでVBlank中は常にヒットが返ってきてしまいます。余談ですが、$2002リード時のbit7はスキャンラインかVBlankを判定できる…といろんなところに書いてあるのですが、どうも機能してないっぽいんですよね。私のやり方が悪いのか、そういう仕様なのかはわかりません。そこで、他のゲームを解析してみると…どうやら、2回ループさせて判定しているようです。
CHECK_SCANLINE:
lda $2002
and #$40
bne CHECK_SCANLINE
CHECK_0BOMB:
lda $2002
and #$40
beq CHECK_0BOMB
こんな感じですかね? 1回目では$2002のリードでbit6がヒットしてたらループします。ここでヒットしてる時は、恐らくまだVBlank中です。ヒットしなければスキャンライン中というわけです。もちろん、初回いきなり0爆弾の可能性もありますが、その時はご愁傷様です…。
2回目のループではすでにスキャンライン中ですので、普通にbit6がヒットするまでループして待ちます。
以上のようにやっても、まだ0爆弾が判定しない? そんなときはそもそも0爆弾の描画処理が行われてるのかを考えてみてください。例えば、0番スプライトが透明色しかない場合には、0爆弾を描いたことにはなりませんのでヒットしません。
調べていませんが、ファミコンには左8ピクセル内のスプライトを描画しないフラグもあります。スプライトが左隅にあったら判定されないかもしれません。調べたわけではないので憶測です…。
そんな感じで、スキャンラインorVBlankの判定ってどうやんのさ? というのを今まで適当にやってたんですが、ちょっと込み入った事情があってキッチリ判定できないとヤバかったので他のゲームを調べてわかったことをメモとして残しておこう! という記事でした。0爆弾はIRQなどを使わずにスキャンラインを知ることができるテクニックですが、IRQが使えるならそっちの方がムダが少なくて良いので、無理して使用する必要もないかと思います。私はファミコンらしくてけっこう好きです。0爆弾ラブ。
この記事が気に入ったらサポートをしてみませんか?