Skip to content

ダンジョン生成

概要

Rift Survivors のダンジョンは連続階層制で構成される。1Fから15Fまで、各フロアがBSP(Binary Space Partitioning)アルゴリズムでプロシージャル生成される。ダンジョン全体は1つのシード値から決定論的に生成され、全フロアの構造が再現可能。

設計思想: チョコボの不思議なダンジョン + MCDungeons

チョコボの不思議なダンジョンの「階層を降りていく探索」に、 Minecraft Dungeonsのアクション戦闘を組み合わせる。 各フロアはBSPで自動生成されるが、5F/10F/15Fのボスフロアは固定レイアウト。

階層構成

フロアごとのパラメータ

フロア敵ステータス倍率敵数トラップ数モンスターハウス確率ドロップ品質
1F1.0x2000%1.0x
2F1.1x2215%1.0x
3F1.2x25210%1.0x
4F1.3x28315%1.0x
5Fボス戦00%ボス報酬
6F1.5x25210%2.0x
7F1.6x28315%2.0x
8F1.8x30420%2.0x
9F2.0x32525%2.0x
10Fボス戦00%ボス報酬(2x)
11F2.2x30420%3.0x
12F2.5x32525%3.0x
13F2.8x35630%3.0x
14F3.0x38735%3.0x
15Fボス戦00%ボス報酬(3x)

フロア生成アルゴリズム: BSP(Binary Space Partitioning)

アルゴリズム全体フロー

BSP分割の詳細

分割パラメータ

パラメータ説明
全体サイズ80×80 units1フロアの大きさ
最大分割回数5回再帰の深さ上限
最小区画サイズ10×10 unitsこれ以下は分割しない
分割比率0.4〜0.6分割位置のランダム幅
分割方向交互(横→縦→横...)偏りを防ぐ

分割アルゴリズム(疑似コード)

typescript
interface BSPNode {
  x: number; y: number;
  width: number; height: number;
  left?: BSPNode;
  right?: BSPNode;
  room?: Room;
}

function splitBSP(node: BSPNode, depth: number, rng: SeededRNG): void {
  if (depth >= MAX_DEPTH) return;
  if (node.width < MIN_SIZE * 2 && node.height < MIN_SIZE * 2) return;

  const splitHorizontally = node.width < node.height
    ? true
    : node.width > node.height
      ? false
      : rng.next() > 0.5;

  if (splitHorizontally) {
    const splitY = node.y + lerp(node.height * 0.4, node.height * 0.6, rng.next());
    node.left  = { x: node.x, y: node.y, width: node.width, height: splitY - node.y };
    node.right = { x: node.x, y: splitY, width: node.width, height: node.y + node.height - splitY };
  } else {
    const splitX = node.x + lerp(node.width * 0.4, node.width * 0.6, rng.next());
    node.left  = { x: node.x, y: node.y, width: splitX - node.x, height: node.height };
    node.right = { x: splitX, y: node.y, width: node.x + node.width - splitX, height: node.height };
  }

  splitBSP(node.left, depth + 1, rng);
  splitBSP(node.right, depth + 1, rng);
}

部屋配置ルール

各リーフノード内にランダムサイズの部屋を配置する。

部屋の幅  = random(区画幅 × 0.5, 区画幅 × 0.9)
部屋の高さ = random(区画高さ × 0.5, 区画高さ × 0.9)
部屋の位置 = 区画内でランダムにオフセット(壁から最低1unit離す)
パラメータ
部屋最小サイズ6×6 units
部屋最大サイズ区画の90%
壁厚0.5 units
生成される部屋数8〜16部屋(分割回数に依存)

部屋タイプ

部屋タイプ一覧

タイプ出現数説明視覚的特徴
スタート部屋1プレイヤーの初期位置(1Fのみ)/ 階段出口明るいネオン照明、安全地帯
戦闘部屋4〜8敵がスポーンする主要エリア暗い照明、赤い警告ライン
エリートアリーナ1〜2エリート敵が出現する大部屋紫のオーラ、広い空間
宝物部屋1〜2アイテムの宝箱(未識別チップ含む)金色のライティング
回復部屋1〜2HP回復+バフアイテム緑色のライティング
階段部屋1次フロアへの階段が配置シアン色のリフトエフェクト
モンスターハウス0〜1リフトサージ発生部屋入室まで通常部屋に見える

部屋タイプの配置ルール

距離計算: 部屋間の距離はBSPツリー上のホップ数(部屋中心間のマンハッタン距離ではなく、通路を通った実際の経路長)で算出する。

階段オブジェクト

各フロアには次のフロアに進むための階段が1つ配置される。

パラメータ
配置位置スタート部屋から最遠の部屋
サイズ2×2 units
視覚エフェクトシアン色の下向き渦 + パーティクル
インタラクションFキーで次フロアへ移動
移動演出0.5秒のフェードアウト → 次フロアロード → フェードイン
条件なし(いつでも降りられる。全敵撃破は不要)

設計意図

トルネコ/チョコボと同様、階段はいつでも使える。 敵が多すぎる場合は戦闘を避けて階段を目指す「逃げプレイ」も有効な戦略。 ただしレベルが足りないままボスフロアに到達すると苦戦する。

ボスフロアレイアウト(固定)

5F/10F/15Fのボスフロアは、BSP生成ではなく固定レイアウトを使用する。

┌────────────────────────────────────────────────────┐
│                                                    │
│  ┌──────────┐    ┌────────────────────────────┐    │
│  │          │    │                            │    │
│  │  前室    │────│    ボスアリーナ              │    │
│  │ 回復     │ゲート│                           │    │
│  │ アイテム  │    │   [ボス]                    │    │
│  │          │    │                            │    │
│  │  [入口]  │    │   撃破後:                   │    │
│  │  ↑階段   │    │   [帰還ポータル] [次の階段]  │    │
│  └──────────┘    └────────────────────────────┘    │
│                                                    │
└────────────────────────────────────────────────────┘
パラメータ5Fボスフロア10Fボスフロア15Fボスフロア
前室サイズ10×10 units10×10 units10×10 units
アリーナサイズ20×20 units25×25 units30×30 units
ゲート仕様入場後閉鎖入場後閉鎖入場後閉鎖
ボス撃破後帰還ポータル + 6F階段帰還ポータル + 11F階段帰還ポータル(最終)

トラップ(グリッチトラップ)

不思議のダンジョン要素: グリッチトラップ

チョコボの不思議なダンジョンのワナ要素を取り入れる。 床に不可視のトラップが配置され、踏むと様々な効果が発動する。 「???チップ」(未識別アイテム)と同様、不確定要素としてプレイに緊張感を与える。

トラップ一覧

トラップ名効果ダメージ/影響視覚予兆
データリークHP減少最大HPの15%ダメージなし(踏むまで不可視)
スタンパルス一定時間行動不能2秒間スタンなし
ワープホールランダムな部屋に転送ダメージなしなし
アラームトラップ敵を追加スポーン周囲に敵8体スポーンなし
デバフフィールドステータス低下ATK -30% / 30秒なし
コラプトトラップ持ちアイテム1つが呪い化ランダムで呪い付与なし

トラップの配置ルール

トラップ配置数 = フロア番号に応じた数(上記テーブル参照)
配置位置 = 通路または部屋内のランダムな床タイル
配置禁止 = スタート部屋、階段の直近2タイル、回復部屋
発動条件 = プレイヤーが踏む(敵は発動しない)
一度発動したトラップは可視化され、再発動しない

トラップへの対策

  • スキル「トラップスキャン」を選択すると、半径3unit以内のトラップが可視化される
  • 一部の武器ボーナス「トラップ耐性」でトラップダメージを軽減可能
  • 踏んだトラップは可視化されるため、リベンジ時は同じ場所を避けられる

モンスターハウス(リフトサージ)

不思議のダンジョン要素: リフトサージ

トルネコの「モンスターハウス」に相当する要素。 一見普通の部屋に入ると、突然大量の敵が出現する。 危険だが、全滅させれば大量の報酬を獲得できる。

リフトサージの仕様

パラメータ
出現確率フロアごとに異なる(上記テーブル参照)
出現数/フロア最大1部屋
発動条件プレイヤーが部屋に入室
出現敵数50〜80体(フロア深度で増加)
部屋封鎖発動後、部屋の全出入口が封鎖(全敵撃破で解除)
敵の種類そのフロア帯の通常敵 + エリート1〜2体
予兆なし(入室するまで通常部屋と区別不能)

リフトサージ報酬

報酬
EXP通常フロアの3〜5倍
アイテムドロップ5〜8個(高品質)
???チップ1〜3個
レア武器1個(Rare以上確定)

リフトサージの危険性

リフトサージは回避できない(入室するまでわからない)。 レベルが低い状態で遭遇すると非常に危険。 逆にレベルが十分なら大量のEXPとアイテムを稼ぐチャンス。 リベンジ時は同じ部屋にリフトサージがあることがわかるため、対策を立てられる。

通路生成

BSPツリーの各内部ノードにおいて、左右の子ノードに属する部屋同士を通路で接続する。

通路パラメータ

パラメータ
通路幅2.0 units
通路形状L字型(水平→垂直 or 垂直→水平)
接続方式各部屋の最寄りの辺の中点を結ぶ

通路生成アルゴリズム

typescript
function connectRooms(roomA: Room, roomB: Room, rng: SeededRNG): Corridor {
  const pointA = roomA.center;
  const pointB = roomB.center;

  if (rng.next() > 0.5) {
    return [
      { x1: pointA.x, y1: pointA.y, x2: pointB.x, y2: pointA.y },
      { x1: pointB.x, y1: pointA.y, x2: pointB.x, y2: pointB.y }
    ];
  } else {
    return [
      { x1: pointA.x, y1: pointA.y, x2: pointA.x, y2: pointB.y },
      { x1: pointA.x, y1: pointB.y, x2: pointB.x, y2: pointB.y }
    ];
  }
}

環境バリエーション

テーマ

ダンジョンのビジュアルテーマはフロア帯で変化する。

テーマ適用フロア色調環境ハザード
データグリッド1F〜5Fシアン / ブルーなし(序盤は安全)
ネオンアーケード6F〜10Fピンク / マゼンタ電撃トラップ(床が周期的に通電)
グリッチコア11F〜15Fパープル / グリーン不安定床(一定時間で崩壊)

テーマ変化の意図

フロア帯ごとにビジュアルが変わることで、深度の進行を視覚的に体感できる。 「色が変わった = 危険度が上がった」という直感的なフィードバック。

環境ハザード

ハザードダメージ発動間隔予兆出現フロア
電撃トラップHP 5%/秒8秒ON/4秒OFF床の点滅(2秒前)6F〜10F
不安定床即死(落下)プレイヤーが乗って3秒後亀裂のひび割れ(1秒前)11F〜15F

環境オブジェクト

オブジェクト機能破壊可能
データモニュメント触れるとEXPジェム(大)ドロップYes
エネルギーピラー一定時間ごとにHP回復フィールド展開No
破壊可能な壁攻撃で破壊、ショートカット生成Yes(HP 50)
爆発バレル攻撃で爆発(半径2.0, 50ダメージ, 敵味方問わず)Yes(HP 1)

ミニマップ

ダンジョン探索中はHUD上にミニマップを表示する。

表示要素アイコン/色
現在位置白い矢印
訪問済み部屋薄い灰色
未訪問部屋非表示
通路薄い灰色のライン
階段シアンの下矢印アイコン
宝物部屋金色のアイコン
帰還ポータル(ボス撃破後)シアンのアイコン
敵(ミニマップ内)赤い点
トラップ(発見済み)黄色の×マーク

ミニマップサイズ: 画面右上 150×150px。M キーで全体マップ表示に切り替え。

シード値によるリプレイ可能な生成

シード値の役割

ダンジョン全体(全15フロア)は1つのシード値から決定論的に生成される。 各フロアの生成には シード値 + フロア番号 を入力として使用する。

typescript
interface DungeonSeed {
  seed: number;              // 乱数シード値(ダンジョン全体)
}

function generateFloor(seed: number, floor: number): Floor {
  // フロアごとのサブシードを生成
  const floorSeed = hash(seed, floor);
  const rng = createSeededRNG(floorSeed);

  if (isBossFloor(floor)) {
    return generateBossFloor(floor, rng);
  }

  // BSP分割、部屋配置、敵配置、トラップ配置、
  // モンスターハウス判定を全て rng から生成
  return generateNormalFloor(floor, rng);
}

function isBossFloor(floor: number): boolean {
  return floor === 5 || floor === 10 || floor === 15;
}

全フロアの決定論的生成

要素シード依存
各フロアのマップ構造シード + フロア番号から決定
敵の種類・配置シード + フロア番号から決定
ボスの種類・弱点シードから決定(サイクル固定)
トラップの位置シード + フロア番号から決定
モンスターハウスの有無・位置シード + フロア番号から決定
アイテム配置シード + フロア番号から決定
ドロップテーブル同じ(乱数は戦闘時に再生成)
ボスヒントの配置シード + フロア番号から決定

リベンジとの連携

死亡時にシード値をlocalStorageに保存。リベンジポータルから再挑戦すると 同じシード値で全フロアが再現される。マップ構造、トラップ位置、 モンスターハウスの場所が全て同じなので、前回の経験を活かした攻略が可能。

パフォーマンス考慮

Three.jsでの実装指針

項目方針
床・壁のメッシュタイルベースのInstancedMesh で一括描画
通路同一マテリアルのメッシュを結合(BufferGeometry merge)
視野外の部屋Frustum Culling(Three.js標準)
LODプレイヤーから遠い部屋のオブジェクトを簡略化
描画上限Draw Call 目標: 100以下
フロア遷移現フロアのみメモリに保持。次フロア移動時に前フロアを破棄

メモリ目安

要素サイズ見込み
BSPツリーデータ(1フロア)~2KB
部屋ジオメトリ(1フロア)~500KB
テクスチャ~2MB(環境テーマ1種分)
合計(1フロア)~3MB
ボスフロア(固定レイアウト)~1MB