モンスターブレイカー — ブロック崩しと RPG を融合させた Flame ゲーム

| 開発記録 | モンスターブレイカー

タグ: #Flame #ゲーム #Flutter

ブロック崩しは単調、RPG は操作が複雑。だったら混ぜてみよう、で始めたのがモンスターブレイカーです。Flame でコアロジックを純 Dart に切り出し、Wave 制バトルとパーティ・装備・呪文を載せました。初期 HP 5 だとすぐ死ぬ、みたいな調整の記録です。

コンセプト

ブロック崩しは飽きない。でも繰り返すだけだと単調です。RPG は深い。でも操作が複雑になりがちです。

この 2 つを掛け合わせました。「ボールを打ち返すアクションで RPG のバトルが進行する」ゲーム。それがモンスターブレイカーです。

Flame でのコア構成

Flame 公式のサンプルをベースに、独自要素を載せました。

  • BreakoutSimulation(純 Dart のコアロジック)
  • StageLayout(グリッド → ワールド座標マッピング)
  • 円 vs AABB の swept collision
  • 4 種のブロック型(BlockComponent 階層)
  • 党(Party)駆動のゲームプレイ、降下・クリア・ゲームオーバー判定

ポイントは、ロジック層を純 Dart で切り出したことです。Flame に依存しない形にしました。こうするとテストが書けます。

ボールとブロックの当たり判定は swept(連続)方式で計算しています。フレームの dt が大きいときに「すり抜け」が起きないようにするためです。概念だけ抜き出すと次のとおりです。

class BreakoutSimulation {
  CollisionResult? sweepBallVsBlocks({
    required Ball ball,
    required Iterable<Block> blocks,
    required double dt,
  }) {
    final motion = ball.velocity * dt;
    CollisionResult? earliest;
    for (final block in blocks) {
      final hit = _sweepCircleAabb(
        center: ball.position,
        radius: ball.radius,
        motion: motion,
        box: block.aabb,
      );
      if (hit == null) continue;
      if (earliest == null || hit.t < earliest.t) {
        earliest = CollisionResult(block: block, hit: hit);
      }
    }
    return earliest;
  }
}

Wave 制バトル

通常のブロック崩しは「ブロックを全部消したらクリア」です。本作は Wave 制にしました。

  • 弱モンスター(雑魚)が複数体出現する Wave
  • 中ボスが出現する Wave
  • ボス Wave

段階的に難易度が上がります。各 Wave をクリアすると、生存メンバーが HP の 50% を回復します。RPG らしい段階感が出ました。

マルチボール

ボール 1 個では火力が足りませんでした。そこでマルチボールに対応しました。ボールが分裂して、複数の敵を同時に攻撃できます。

ダメージポップアップとヒット位置

ヒットしたときのダメージ数字を、ヒット位置にポップアップ表示するようにしました。最初はパドルの上に出していたのですが、これがぜんぜん駄目でした(どこを攻撃したのか自分でも分からない)。ヒット位置に出すのが正解です。

さらに、ダメージ数字は「黒文字+白アウトライン」にしました。どんな背景色でも見やすくなります。

HP バランス調整

プレイヤーの初期 HP は当初 5 でした。すぐ死にます。20 にしました。

バランス調整はテストプレイの繰り返しです。コミット履歴には balance: Bump playerInitialHp 5 -> 20 のような調整が並んでいます。

SaveData と永続化

パーティ編成・装備・呪文・所持アイテムは SharedPreferences に永続化しました。あいだに SaveRepository を挟んでいます。Flame コンポーネントから直接 SharedPreferences を触らせないためです。

まとめ

  • ロジック層を Flame から切り離すとテストが書ける
  • Wave 制は単調さを打破する強力なギミック
  • バランス調整はテストプレイの量が全て

ゲーム開発はコードより「触ってみての気持ちよさ」が全てです。数字をいじって自分で遊んで、また数字をいじる。この往復にいちばん時間を使いました。