【開発[#2] 9日目】戦略SLG

「凝った。」

当初、1週間くらいでそこそこ動くものを作れると思っていた。

作り始めたら、土台が気になった。
データ構造が気になった。
セーブの設計が気になった。
9日経って、まだタイトル画面しか動いていない。

でも後悔はしていない。


■ この8日間でやったこと

前回の記事(開発1日目)から約8日が経過した。
大きく3つのフェーズに分けて進めてきた。

  • フェーズ1(2〜4日目):素材調達とデータ設計
  • フェーズ2(5〜7日目):データ基盤の実装と自動化
  • フェーズ3(8〜9日目):仕様の言語化と画面実装の開始

順番に書いていく。


■ フェーズ1:素材とデータ設計

武将立ち絵102体

本作には102名の武将が登場する。全員分の立ち絵を生成AIを駆使して生成した。
プロンプトは3000文字くらい、英単語も400Wordsほど。調整に数日使った。塗り方にはかなり拘った。

スタイルは「semi-painted watercolor illustration style」に統一。自作の絵を参照画像として渡しスタイルを再現させる手法(塗りや顔などの作画)が安定することがわかった。生成した画像はUnity上で512×768にリサイズして使用する。顔絵(384×384)は立ち絵の上部中央をクリッピングして自動生成する仕組みにした。

世界地図の処理

地形有地図と白地図の2種類を用意し、Pythonで処理した。

白地図のボロノイ分割処理でB01〜B30の30枚のリージョンスプライトを自動生成したが、流石に形状がカクカクだったので結局手作業で地形より30個の白地図用ピースを作成した。地形有地図・白地図ともに海部分をflood fillで透過処理している。地形有地図の上に白地図30ピースを半透明で重ねる実装方針とした。


■ フェーズ2:データ基盤の実装と自動化

前のゲーム(鋼鉄の交響曲)で仕様変更や調整によるスパゲッティコード化に苦しんだ。
今回は最初から「土台に時間をかける」と決めていた。

ScriptableObjectとCSVインポーター

OfficerDataBastionDataをScriptableObjectとして設計し、CSVからの一括インポーターをEditorスクリプトで実装した。

KingdomChronicle/Import Officer Data
KingdomChronicle/Import Bastion Data
KingdomChronicle/Import Scenario Data

メニューから実行するだけで全データが自動登録される。武将102件・拠点30件・シナリオ4本のインポートが完了している。

Spriteの自動アサイン

武将立ち絵・顔絵・拠点スプライトの自動アサインもインポーター内に実装した。

武将立ち絵:CR_{ID:D3}       例:CR_001
武将顔絵 :CR_{ID:D3}_Face  例:CR_001_Face
拠点領域 :B{ID:D2}         例:B01

ISpriteEditorDataProviderを使ってSpriteのRectをプログラムから登録している。UnityはY軸が左下原点なのでRect計算時に注意が必要だった。一度ミスした。

セーブデータ設計

セーブデータは3層構造で設計した。

内容
SystemData設定系(音量・言語等)
SaveDataRecordプレイ記録(コレクション・クリア数)
SaveDataCustomOfficerカスタム武将データ
SaveDataGameゲーム進行データ(4スロット)

カスタム武将については、元データ削除後もゲームが破綻しないよう、スロット内にスナップショットを複製する設計にした。

ScenarioDatabaseを途中で削除した

当初シナリオデータを管理するScenarioDatabaseを作っていたが、途中で削除した。

シナリオは4本固定だ。102件の武将・30件の拠点と違い、IDで大量のデータを索引する必要がない。Resources.Load<ScenarioData>("Data/Scenarios/S01")で直接ロードする方が実装がシンプルになる。

「とりあえず作る」より「本当に必要かを問い直す」。
そういう判断を意識するようにしている。


■ フェーズ3:仕様の言語化と画面実装

実装より先に、仕様を言語化して確定させた。
曖昧なまま実装すると、後で大量の手戻りが発生する。

戦争発生パターン(4種)

パターン概要
1vs1侵攻戦・迎撃戦・遭遇戦
同時多発同一勢力が複数戦争に同時関与・戦力は完全分離
三つ巴補正値=他全勢力との1vs1補正値の平均・最大戦力値の勢力が勝利
援軍侵攻側は要請コマンド必須・迎撃側は自動通知

訓練度の参照タイミングは「コマンドを入力した時点の値」に確定した。出陣後に訓練しても戦力値には反映されない。

三すくみの補正倍率

有利兵科に対して×1.5の武力補正を適用する。

これにより武力60の弓兵が武力90の槍兵と同等の戦力値になる。単一兵科の高武力集中は弱点になり、混成編成が戦略的に有利という設計だ。騎馬が見た目上武力寄りのキャラ(騎士系)になりやすいので、槍と弓の高武力確保が必須戦略になる。

ターンサイクル

1. ターン開始フェーズ
   戦争結果反映・収入・イベント
   → ここまでの情報が次フェーズで見える

2. プレイヤーコマンド入力フェーズ
   入力時点の値で全パラメータ確定

3. AIコマンド入力フェーズ(非表示)
   次ターンの1で結果が開示される

AIは後出しになるため構造的に有利。この優位をどこまで活かすかを難易度設定と連動させる。以下の仕様は仮で最終的な難易度はテストプレーで調整する。

Easy  :AI資源収入 ×1.0(プレイヤーと同等)
Normal:AI資源収入 ×1.2
Hard  :AI資源収入 ×1.5

タイトルシーンのモック実装

仕様が固まったところで画面実装に着手した。

演出フローをManagerTitle.csに実装している。

黒フェードイン → 背景フェードイン → ロゴフェードイン
→ PUSH ANY KEY 点滅 → キー入力
→ パネル右スライドイン + ロゴ左移動 + ボタン上スライドイン

NewGameフローはNewGameDataという静的クラスでScenarioIdDifficultyを一時保持してシーン遷移する設計にした。ManagerSceneTransitionを汚さずに済む。


■ 現時点の開発状況

カテゴリ状況
武将データ(102名)✅ 完了
拠点データ(30件)✅ 完了
シナリオデータ(4本)✅ 完了
セーブデータ設計✅ 完了
タイトルシーン✅ モック完了
スタートシーン⬜ 次回着手
メインシーン⬜ 未着手
戦闘計算式⬜ 仕様詰め中

執筆後記

「1週間くらいで作れると思ってた」は、いつも嘘になる。

でも今回は悔しくない。
土台をちゃんと作ったから、これからが速くなるはずだ。

スタートシーンが動いたら、一気にゲームらしくなる。
それを楽しみに、次のセッションへ。