始まり
やりたかったのは、ハードボイルドな探偵ものだった。
薄暗い事務所、ミントを噛み砕く探偵、控えめなノックの音。新宿の夜を舞台に、古き良き探偵小説の空気感をゲームにしたかった。それだけのつもりだった。
ところが、AIと一緒にストーリーを組み立てていくうちに、話がどんどんおかしな方向に転がり始めた。
「地下道に毎週置かれる青いバラ」の謎を追っていたはずが、いつの間にか「ゴーストプロトコル」だの「ウロボロス」だの物騒なコードネームが飛び交い、警察庁の元局長が暗殺を「業務委託」で決裁していたり、黒幕がデジタル空間で「神」を気取っていたりする。
完全にサイバーパンクだった。
最初は「いや、そっちに行く?」と思ったけれど、AIが提案してくるプロットが妙に筋が通っていて、気がつけば乗っかっていた。ハードボイルドとサイバーパンクが混ざり合って、自分では絶対に思いつかないカオスな世界観が出来上がった。
ゲームの構成
出来上がったのは、3ルート・28シナリオファイル・8種類のミニゲームを持つノベルゲームだ。
シナリオの規模
static readonly string[] allFiles = {
"Chapter1", "Chapter2",
"Chapter2_Saeki", "Chapter2_Rin",
"Flashback1",
"Chapter3", "Chapter3_Saeki", "Chapter3_Rin", "Chapter3_Merge",
"Flashback2",
"Chapter4", "Chapter5",
"END_Main_Good", "END_Main_Bad",
"RinStory_Ch1", "RinStory_Ch2", "RinStory_Ch3", "RinStory_Ch4", "RinStory_Ch5",
"END_Rin_Good", "END_Rin_Bad",
"KasumiStory_Ch1", "KasumiStory_Ch2", "KasumiStory_Ch3",
"KasumiStory_Ch4", "KasumiStory_Ch5", "KasumiStory_Ch6",
"END_Kasumi_Good", "END_Kasumi_Bad"
};
- メインルート: 全5章+グッド/バッドエンド
- 凛ルート: 全5章+グッド/バッドエンド(19歳のハッカー)今後追加予定
- 霞ルート: 全6章+グッド/バッドエンド(バーテンダー)今後追加予定
- フラッシュバック: 2本(故人・遠藤の過去)今後追加予定
全てのシナリオはJSONで管理されていて、選択肢による分岐とファイル間の連鎖で物語が進む。
技術的な構成
JSON駆動のダイアログシステム
シナリオデータは1行1行がJSON構造体として定義されている。
[Serializable]
public class DialogueLine
{
public string charName; // 話者名
public string text; // セリフ
public string pose; // キャラクター表情
public string bg; // 背景画像
public string bgm; // BGM切替
public string se; // 効果音
public string choice1; // 選択肢1
public string choice2; // 選択肢2
public string next1; // 選択肢1のジャンプ先
public string next2; // 選択肢2のジャンプ先
public string miniGame; // ミニゲーム発動
public string nextFile; // 次のシナリオファイルへ連鎖
}
1つのJSONフィールドで「セリフ表示」「背景変更」「BGM切替」「選択肢分岐」「ミニゲーム起動」「次章への連鎖」を全て制御できる。プログラマーが個別にイベントを組む必要がなく、シナリオライター(=AI)がJSONを書くだけでゲームが動く。
8種類のミニゲーム
ADVパートの途中でシナリオに応じたミニゲームが発動する。全てAction<bool>コールバックで成否をADVエンジンに返す統一設計。
| ミニゲーム | 内容 | シーン |
|---|---|---|
| HackingGame | 16進コードの記憶・再現(サイモン風) | 凛のハッキングシーン |
| CipherLinkGame | 暗号フラグメントのペアリング | 霞と遠藤の暗号鍵復元 |
| QTEBattleGame | タイミングバー+キーシーケンス | 格闘シーン |
| StealthGame | 8×6グリッドの潜入パズル | ビル侵入シーン |
| AlleyChaseGame | 路地裏の追跡 | 追跡シーン |
| DigitalInquisitionGame | デジタル尋問 | 情報引き出し |
| WisdomRingGame | 知恵の輪 | 謎解きシーン |
| HangOnGame | 耐久 | 危機脱出シーン |
// HackingGame: 16進コードの色で記憶する
static readonly string[] hexPool = {
"7A", "BD", "1C", "E9", "FF", "42", "D1", "93", "A3", "C8", "55", "F4"
};
// StealthGame: 8×6グリッドで敵の視界を避ける
const int COLS = 8, ROWS = 6;
struct Enemy
{
public int x, y, dir, min, max;
public bool horiz; // 水平パトロールか垂直か
}
ミニゲームに失敗してもストーリーは進む(難易度が変わる場合がある)。ADVのテンポを崩さないように、各ミニゲームはチュートリアル→プレイ→結果の3ステップで完結する設計にした。
多言語対応
LanguageManagerで全テキストをキーベースで管理。ミニゲームのチュートリアルも含めて多言語化している。
// ミニゲーム内のUIテキストも全てキーで参照
MakeLabel(tutGo.transform, LanguageManager.T("breach_title"), 40, ...);
MakeLabel(tutGo.transform, LanguageManager.T("tut_hacking"), 24, ...);
キャラクターの話
でも、このゲームで一番気に入っているのは世界観よりもキャラクターだ。
主人公の冴木蓮は33歳の探偵。ミントを噛む癖があって、過去に何かを失っている男。彼を「おじさん」と呼ぶ19歳の凛は、生意気だけど腕の立つハッカーで、この二人の掛け合いが妙に楽しい。バーで働く霞や、物語の発端となる故人・遠藤——AIと一緒に作ったはずなのに、どのキャラクターもちゃんと「生きている」感じがする。
正直、最初に自分が思い描いていたゲームとはまったく違うものが出来上がった。でも、これはこれで好きだ。むしろ自分一人では絶対に辿り着けなかった場所にいる、という感覚がある。
灰色の残響——タイトルも、AIとの共作にふさわしい名前だと思っている。