Skip to content

システム構成・エンジン設計

実装の正典は src/engine.s(全ロジック単一ファイル)。本書はその構造の解説です。

ROM / ハードウェア構成

項目内容
マッパーmapper 2(UNROM)・固定バンクのみ使用
PRG-ROM128KB(8 × 16KB、全バンク出力・$FF パディング)
CHRCHR-ROM なし。CHR-RAM 8KB にリセット時転送
ミラーリング垂直
画面固定 1 画面(スクロールなし)
リンカ設定cfg/nes.cfg

UNROM バス競合

バンク切替時は ROM 上の同アドレス値と一致する値を書き込むこと(lda banktable,x / sta banktable,x 方式)。現状は固定バンクのみで切替コードなし。詳細はビルド手順の備考。

エンジン全体構造(src/engine.s)

リセット
  ├─ CHR-RAM 転送(フォント / ステージBG / AIスプライト)
  ├─ パレット設定(BG 4本 + スプライト 4本)
  └─ メインループ
       ├─ nmi_flag 待ち(1フレーム同期)
       ├─ パッド読み取り(pad_cur / pad_prev / pad_new)
       ├─ フェーズ進行(phrase_frame → beat_index / beat_frame)
       ├─ コール表示 or レスポンス判定
       ├─ フレーズ集計 → 観客増減 → ゲームオーバー判定
       └─ 描画要求を ppu_buf に積む

NMI(vblank)
  ├─ OAM DMA(スプライト転送)
  ├─ ppu_buf フラッシュ(バッファ経由の PPU 書き込み)
  └─ frame_count++ / nmi_flag セット

PPU アクセス規約(重要)

初期化後、メインスレッドは $2007 に直接触らない。 すべての PPU 書き込みは ppu_buf に積み、NMI ハンドラが vblank 中にフラッシュする。

  • ppu_buf 容量は 96 バイト — 1 フレームに積める描画量の上限。超過する更新は複数フレームに分割する

タイミング設計

音楽・譜面・判定が同一のフレームカウンタを共有するのが本エンジンの核。構造的に音とズレない。

定数意味
FRAMES_PER_BEAT32112.5 BPM(NTSC 60fps で整数割り)
1 フレーズ256 フレーム8 拍 = コール 4 拍 + レスポンス 4 拍。phrase_frame(8bit)が自然にラップ
16 分音符8 フレーム将来の譜面細分化単位(仕様書 §6)

判定システム

チューニングは engine.s 冒頭の定数のみで完結する(single point of tuning)。

定数内容
JUDGE_PERFECT4目標拍 ±4 フレーム → PERFECT +100
JUDGE_GOOD8目標拍 ±8 フレーム → GOOD +50
AUD_INIT / AUD_MAX8 / 16観客の初期値・上限(0 でゲームオーバー)
  • 振り ID: MOVE_REST(0) / MOVE_L / MOVE_R / MOVE_U / MOVE_D / MOVE_A / MOVE_B — 譜面(chart)はこの ID 列
  • 誤ボタン・無入力は MISS。フレーズ集計(perfect_cnt / miss_cnt / target_cnt)で観客増減を決定

申し送り(PR #18 レビュー)

「超早入力(判定窓より前の入力)の扱い」「ppu_buf 書き込み順」の 2 件が判定チューニング時の再検討項目。

キャラアニメーション

  • 全振り共通: 4 コマ × ANIM_STEP_LEN(5) = 20 フレーム固定(拍間 32 フレーム内に収まる)
  • 接地固定: 足位置は動かさない。ジャンプのみ pose_dy で Y 方向に浮上(ユーザー確定要件)
  • アイのポーズ番号は pose(0〜25 の 26 フレーム)
  • お手本ガールはアイのスプライトをパレット差し替え + 水平フリップで共用(CHR 節約)

主要 RAM(zeropage)

変数役割
game_state0 = プレイ中 / 1 = ゲームオーバー
phrase_frame / beat_index / beat_frameフレーズ内位置(拍 0〜3 コール、4〜7 レスポンス)
chart_pos / resp_index譜面読み取り位置 / 次に判定するレスポンス拍
perfect_cnt / miss_cnt / target_cntフレーズ集計
audience観客数 0〜16
poseアイの現在ダンスフレーム(0〜25)

サウンド設計(仕様書 §6 / 未実装部分)

  • 自作最小シーケンサを実装予定(famitone2 不使用)。音楽の行カウンタを判定システムと共有
  • チャンネル配分: パルス 2(メロディ + ベース)/ 三角波(キック・ベース)/ ノイズ(ハイハット・スネア)/ SE はノイズ・パルス 1 を一時借用
  • 現状は拍頭ビープのみ(コール ~A4 440Hz / レスポンス ~A5 880Hz、BEEP_* 定数)

ビルド・実行

bash
make            # build/engine.nes(131,088 バイト)
make run        # Mesen2 で起動(要 MESEN 環境変数・GUI セッション)
make hello      # 旧 Hello World ROM

詳細はビルド手順。実機書き込みはフラッシュライターカート改造