@huyi1985

Are you sure you want to delete the question?

If your question is resolved, you may close it.

Leaving a resolved question undeleted may help others!

We hope you find it useful!

なぜ『スーパーマリオブラザーズ』(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) の時間計算量を得るため)

この仕様について、詳しい方のご意見を伺いたいです!
これは単なる最適化なのでしょうか? それともゲームバランスやデザイン上の意図があったのでしょうか?

7 likes

4Answer

面白い仕様ですね。開発者でないと本当のことはわかりませんが、おそらく最終的には、作り込むのが面倒だったという話に落ち着くんじゃないかと思います。当たり判定がどうとかいう話よりも、一定の所まで進んだときにフラグを消す方が作るのは楽ですから。

で、確かマリオって1画面(半画面程度かも?)ぐらい先までは見えないだけである程度のデータを処理していましたよね? 確かカメ蹴ってBダッシュで追いかけたとき、画面右端から消えたカメが跳ね返ってきたやられたような記憶があります。と考えると隠し1UPキノコが消えるのは、隠し1UPキノコが含まれた画面のデータ処理を始めたタイミングではないのかなと。つまり内部的には隠し1UPキノコの場所まで進んでいるという扱いなのではないでしょうか?

隠し1UPキノコは後から追加された要素な気もしますし、どこにコードを付け足せるかな?と考えたら、画面のデータ処理を始めた所に入れ込もうと考えるのは自然だと思います。もちろんバグとも言えるので作り込めば修正できますが、こうやって気づかれにくい話なわけで気づいていたとしても修正するまでもなかったのかなと。面倒ですし。

1Like

ありえそうなのが残容量問題かなと。
この処理するのに何バイト必要?
せやったらここにブロック置きたいからその処理なくても問題ないかな。
みたいなやり取りはあったかもわからんです。
そこはバグでいいと割り切った可能性も高い気がします。

また、プログラムエリアの残容量を合計したら要求を満たす分あったとしても、プログラムブロックとして考えると連続したエリアを確保できなければ処理はできませんし、JMP命令で飛ばそうとすると余計に容量食ってしまいます。故に入れられなかった可能性も考えられますね。

1Like

まだ続いているみたいなので別視点の意見を
※根拠はありません

当時スーパーマリオはFC版だけではなくアーケード版もあったように思います
このときに1UPが出やすくしてしまうとその分長く遊べてしまうので
それを回避するためにこういう仕様にしたのかもしれません

(無限1UPは想定していないバグと言うことで)

1Like

Your answer might help someone💌