なぜ『スーパーマリオブラザーズ』(FC)では、マリオがブロックを叩く前に隠し1UPフラグがクリアされたのか?
『スーパーマリオブラザーズ』(FC)の逆アセンブルコード(こちら)を解析していたところ、隠し1UPキノコに関する興味深い仕様を見つけました。
それは、1UPの二重取得を防ぐフラグが、マリオが実際に隠しブロックを叩く前にクリアされた という点です。
該当コード:
; https://gist.github.com/1wErt3r/4048722#file-smbdis-asm-L4172
Hidden1UpBlock:
lda Hidden1UpFlag ;if flag not set, do not render object
beq ExitDecBlock
lda #$00 ;if set, init for the next one
sta Hidden1UpFlag
jmp BrickWithItem ;jump to code shared with unbreakable bricks
例えば、1-1 の隠し1UPの場合、この処理は マリオが以下の画像の位置に到達した時点で実行されます。しかし、この時点では 1UP のブロックはまだ画面外にあります。
そのため、もし初心者プレイヤーがこの地点でクリボーにやられてしまうと、次回のプレイでは 1UPを取得するチャンスが完全に失われる ことになります。
この仕様は、Webアプリに例えると「ボタンを押した瞬間にクーポンを取得」ではなく、「ページを開いた瞬間にクーポンを取得済みとみなす」ような挙動に似ています。
もし運悪くクーポンを押さないままページをリロードしてしまうと、クーポンは未取得のまま失われてしまう、という状況です。
考えられる理由の一つは、ファミコンのハードウェア制約を回避するための最適化です。
もし**「マリオがブロックを叩いた瞬間」**にフラグをクリアする仕様だった場合、以下のような追加処理が必要になると思います。
- マリオがジャンプするたびに、隠し1UPブロックとの衝突を判定する
- プレイヤーが1UPを取得できるかどうかをチェックする
- さらに、マリオの位置 => 取得可否のフラグを検索するテーブルを作成・参照する処理も発生する(O(N) の空間計算量を犠牲にして O(1) の時間計算量を得るため)
この仕様について、詳しい方のご意見を伺いたいです!
これは単なる最適化なのでしょうか? それともゲームバランスやデザイン上の意図があったのでしょうか?