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

■ 12〜17日目のまとめ

今回は6日分をまとめて記録する。

前回まででScene_Titleの基本実装は終わっていたが、各画面のデザインが仮素材のままだった。今回はそこを仕上げ、タイトルシーンを一旦完成とした。あわせてScene_Startの機能実装を本格的に進め、君主選択制御・武将変更パネルまで動くようになった。

結構、Claudeの提案に振り回される展開も多く、手戻りに近い無駄な工程もあったのでAIをディレクションする能力を高めるべきと反省する局面が多かった。前提条件にいつの間にか認識齟齬があったり、複雑化するほど丁寧な要件指定が必要と痛感した。
小さく閉じた機能設計精度は高いが規模が大きくなって複雑化してくると業務系アプリケーションではあまり問題ないのかもしれないが、ゲームのような独自性が高いアプリケーションだとAIの推論が的外れになる事も多いですね。


■ 12日目(5/3):バグ修正・多言語化対応・各種画面実装

LocalizeHelperの削除と多言語化設計の統一

大規模な対応となった。それまで使っていたLocalizeHelper.cs(日本語・英語の2言語決め打ちでテキストを返すユーティリティ)を全廃した。

理由は拡張性。bool isJapaneseの二択設計では将来的に中国語やドイツ語を追加できない。代わりにSystemLanguage型のswitch式を使う方針に統一した。この変更が影響したファイルは14本・34箇所にのぼった。

LocalizeText.SetDynamicText()への統一も同時に行い、TextMeshProUGUIには必ずLocalizeTextをアタッチするプロジェクト標準を確立した。

コレクション画面(Panel_Collection)実装

タイトルシーンの武将図鑑画面を実装した。

全132名をID順にNo.1〜No.132で表示する。24名/ページ(横8×縦3)・最大6ページのページング構成。CollectionCard.csをPrefab化してCommonフォルダに配置し、登録済み/未登録(?????表示)の2状態を持つ設計にした。

カードをクリックするとPanel_OfficerDetailが開き、立ち絵・能力値・兵科・特技・経歴などの詳細を確認できる。

カスタム武将登録画面(Panel_ForgeOfficer / Panel_CustomOfficerEdit)実装

「My Officers」から起動するカスタム武将登録機能を実装した。

画像を取り込むとSHA256ハッシュ値を生成し、そのハッシュをシードとしてパラメータを自動生成する。同じ画像からは必ず同じ結果が得られる設計になっている。

自動生成の内容:

項目方式
能力値(武力/知力/魅力)正規分布(Box-Muller法・平均60・標準偏差15)
初期忠誠均等分布(60〜90)
ボーナスポイント均等分布(10〜30)
兵科重み付き抽選(均等5種)
特技シード固定抽選(42種)

特技に兵科縛りがある6種(騎馬突撃・弓の名手・槍衾・剣聖・魔法集中・魔法陣)については、特技抽選後にUnitTypeを強制上書きする処理を入れている。

ボーナスポイントは各能力値に±ボタンで振り分けられる。元の生成値より下には下げられない制約あり。

確定後は変更不可・削除のみ可能という設計で確定した。

LoadGame画面実装

タイトルシーンのデータ読込画面を実装した。

オートセーブ1枠+手動3枠の計4スロット構成。各スロットにはシナリオ名・難易度・現在ターン(年・季節換算)・勢力名を表示する。エリア戦(青)・全土戦(赤)で背景色を色分けし、データなしスロットはグレーで読込ボタンを無効化する。

ターン数の変換は以下の通り。

エリア戦:最大40ターン(10年)
全土戦:最大80ターン(20年)
上限超過:「期限切れ」表示

■ 13日目(5/4):SlidePanelBase実装・パネル演出の共通化

SlidePanelBase

各パネルのスライドイン・スライドアウト演出を提供する共通基底クラスを作成した。

スライド方向(上下左右)・時間・距離はInspectorで設定可能。オプションでCanvasGroupによるフェードイン・アウトにも対応している。公開APIはShow() / Hide() / ShowImmediate() / HideImmediate() / SetInteractable()の5種。

この回から全パネルが継承対象となり、現時点では以下が対応済み。

Panel_Scenario / Panel_Difficulty / Panel_LoadGame / Panel_Collection / Panel_OfficerDetail / Panel_ForgeOfficer / Panel_CustomOfficerEdit / Panel_ImageImport / Panel_Option / Panel_Dialog / Panel_FactionInfo / Panel_FactionConfirm / Panel_FactionEdit / Panel_OfficerSelect

Panel_OptionとPanel_Dialogの配置方針変更

旧方針のDontDestroyOnLoad・Singletonパターンを廃止した。各シーンに直接Prefabを配置し、SerializeFieldで直接参照する方式に変更した。

ManagerOption・ManagerDialogという名称もPanel_Option・Panel_Dialogにリネームし、命名規則(Panel_*プレフィックス)に統一した。


■ 14日目(5/6):カスタム武将画面の修正・操作制御整備

ScrollView修正とCanvasGroup操作制御

カスタム武将一覧のScrollViewで、カードがContent配下ではなくScrollView直下に追加されて重なって表示される不具合を修正した。SerializeFieldのアサイン漏れが原因だった。

操作制御の方針をこの回で確定した。パネルが開いている間は他パネルの操作を一切不可とする。親子パネルが重なる場合はCanvasGroupのinteractable制御を使う。SetInteractable()をSlidePanelBaseの公開メソッドとして追加した。

最終更新日時機能

CustomOfficerDataにLastModifiedAtフィールドを追加した。ISO 8601形式で保持し、表示時は言語に応じたフォーマットで出力する。

日本語:yyyy/MM/dd HH:mm
英語:MMM dd, yyyy HH:mm

■ 15日目(5/7):CollectionCard・CustomOfficerEdit改修

CollectionCard改修

未登録カードの飾り枠が実行時に消える不具合を修正した。Sprite Frame Secretが未アサインのままspriteにnullが入っていたのが原因だった。

未登録用素材を分離した。変更前は顔・兵科共通の_spriteSecretを1枚使っていたが、_spriteSecretFace(顔用)と_spriteSecretUnitIcon(兵科用)に分離した。

ステータス表示(武力/知力/魅力)も追加した。登録済みは実数値、未登録は「??」表示。兵科アイコンカラーは#C8A84B(ゴールド)で統一した。

Panel_CustomOfficerEdit改修

兵科アイコン画像表示と特技説明文表示を追加した。特技説明文はGameEnumExtensions.GetDescription()で取得し、ClearParamDisplay / ApplyGeneratedData / LoadEditTargetの各タイミングで更新する。

GameEnumExtensionsにUnitType重み付き抽選メソッドGetWeightedUnitType(int seed)を追加した。スキル縛りなし時の兵科抽選に使用する。


■ 16〜17日目(5/8〜5/9):タイトルUI完成・スタートシーン本格実装

タイトルシーン3画面のデザイン確定

この段階でタイトルシーンを一旦完成とした。

ロード画面はセーブスロットの背景を色設定からSprite差し替え方式に変更した。エリア戦(青系)・全土戦(赤系)・データなし(グレー系)で別素材を使う。パネル上部に「Select Save Data」タイトルラベルを追加した。

シナリオ選択画面はエリア戦ボタンを青・全土戦ボタンを赤の別Spriteで色分けした。文字のシャドウはTMPのマテリアル制約をShadow用テキストオブジェクトの並置で回避した。

難易度選択画面はEasy(緑)・Normal(青)・Hard(赤)の横並びアイコンボタンに変更した。

ツールチップ実装

ホバーでテキストを表示するTooltipUI.cs・TooltipTrigger.csを新規作成した。

言語テキストはSystemLanguageエントリ方式で管理しており、言語追加時はInspectorにエントリを追加するだけで対応できる。CanvasGroupのinteractable=false時は表示しない制御を入れており、操作無効状態でのホバーにも対応している。

拠点データ拡充

エリア戦の拠点数が少なすぎると感じたため、各エリアに追加した。

エリア全国版拠点エリア専用追加合計
Area1(北部山地)104(B111〜B114)14
Area2(東海地方)84(B209〜B212)12
Area3(南部平野)125(B313〜B317)17

全拠点IDの管理を2桁(B)から3桁(B*)に統一した。BastionDataImporter.csのフォーマット指定をD2→D3に修正し、既存アセットもUnityエディタ上でリネームした。

接続設計はPythonスクリプトで地図上に可視化して確認した。一方通行チェックも全エリア・全土戦で実施済み。

勢力データ拡充

拠点増加に合わせて各シナリオの勢力数を増やした。

シナリオ追加勢力
S01アイゼンガルド辺境伯領 / ヴァルドレン王国
S02ティレニア海洋同盟 / コーラル諸島連邦
S03ヴェルディア王国 / サンフィールド伯爵領 / テラヴェルデ共和国

各勢力の識別カラーは既存15勢力と被らないよう選定した。

武将12名追加

コレクション画面が6ページきっちり埋まるよう武将を12名追加した。CSVインポートとシナリオ反映を確認済み。

スタートシーン:パネルのSlidePanelBase移行

Panel_FactionInfo・Panel_FactionConfirm・Panel_FactionEditをSlidePanelBase継承クラスに変換した。

SlidePanelBaseにSetSlideDirection()を追加し、パネルの左右スライド方向を動的に変更できるようにした。ただし今回のPanel_FactionInfoは固定方向(右)に統一し、コードからの動的制御をやめてInspector設定に一本化した。

ManagerStart.InitializeUI()でgameObject.SetActive(true)後にHideImmediate()を呼ぶ方式をManagerTitleから踏襲した。Hierarchyのアクティブ・非アクティブ状態に動作が左右されないよう徹底している。

Overlayによる操作ブロック方式を廃止し、CanvasGroupのSetInteractable()に完全移行した。StartSceneStateにFactionEdit状態を追加して全状態での制御を一元化した。

君主選択制御

スタートシーンの主要機能となる君主選択の可否制御を実装した。

条件選択可能な君主
全土戦unlockedOfficerIdsに登録されている君主
エリア戦・初回全国シナリオに登録されている君主
エリア戦・クリア後そのエリアシナリオの全君主

選択不可の勢力は城アイコンを暗色で表示し、地図上から視覚的に判別できるようにした。Panel_FactionConfirmでは選択不可時にStart等のボタンをinteractable=falseにし、理由を示すメッセージを表示する。全土戦とエリア戦でメッセージ内容を出し分けている。

勢力データはScenarioDataのマスタを直接書き換えず、ManagerStart起動時にFactionScenarioData.Clone()で複製したものを使う設計にした。

Panel_OfficerSelect 新規実装

全土戦の君主・配下変更用武将選択パネルを実装した。

CollectionCardを横8枚・縦スクロールで一覧表示する。コレクション武将→カスタム武将の順で続けて並べる設計のため切り替えボタンは不要になった。

フィルタ機能として兵科ボタン・能力値スライダー(武力/知力/魅力)・特技ドロップダウンを実装した。特技ドロップダウンはEnumのValueが飛び番(1〜6の後が11〜)になっているため、_skillEnumValuesリストでindex↔Value対応表を持つ方式にした。

カードをクリックすると即確定・パネルを閉じる。

IOfficerインターフェース導入

OfficerDataとCustomOfficerDataの共通化のためIOfficer.csを新規作成した。

GetName() / GetBiography()
Strength / Intelligence / Charisma / DefaultLoyalty
UnitType / SpecialSkill / Personality / Rarity
GetFaceSprite() / GetStandingSprite()
IsCustom

両クラスに明示的インターフェース実装で追加した。フィールドのプロパティ化はScriptableObjectのシリアライズを破壊するため禁止とし、IOfficer.Strength => Strengthの形で実装した。

これによりOfficerCard.Setup()・Panel_OfficerSelect・Panel_FactionConfirmの武将一時変更データをすべてIOfficer型で統一できた。メインシーンでの戦闘計算・AI処理でも型分岐が不要になる見込み。

Panel_FactionConfirmの武将一時変更設計

確定パネル上での武将変更は、開始ボタンを押すまで一時データとして扱う設計にした。

_tempMonarch(IOfficer):君主の一時変更
_tempSubordinates(IOfficer[]):配下の一時変更

Show()時にnullリセット、リセットボタンでnullに戻す。実データ(_factionListのClone)はキャンセルしても書き換わらない。開始ボタン押下時にGetTempMonarch() / GetTempSubordinates()で確定データを取得してGameStartDataを生成する設計になる。

カスタム武将の在野登録フラグ追加

CustomOfficerDataにIsWanderingInNational(bool)フィールドを追加した。

全土戦でカスタム武将を在野武将として登場させるかどうかを制御するフラグ。Panel_CustomOfficerEditにトグルを追加して編集可能にした。

武将選択画面ではこのフラグに関係なく全カスタム武将が選択対象になる。ゲーム開始後、選択されなかったカスタム武将のうちIsWanderingInNational=trueのものが在野武将として登場する。

スーパーゲ制デー(5/9)

毎月第2土曜日のスーパーゲ制デーに合わせてXに開発進捗動画を投稿した。

タグ(#スーパーゲ制デー)は長文投稿の折りたたまれた範囲に入ると検索インデックスに乗らないことを確認した。タグは投稿冒頭に配置するか、別リプライにタグのみ投稿する方式が確実。
Xに関してはフォロワーを増やす為だけの活動はアカウント品質低下を招くと判断し、内容のあるPOSTを心掛けて地道に展開したいと思う。実際、相互しますで増えたフォロワーはPOST内容に興味が無さそうでインプレッション率(POSTのインプレッション数/フォロワー数)の悪化しか招かない結果に(笑)
しかし、POSTに反応が増えてくるとやる気がアップしますね。


■ 現時点の開発状況

カテゴリ状況
データクラス全般✅ 完了
IOfficerインターフェース✅ 新規完了
GameStartData✅ 新規完了(実装は次回)
Scene_Initialize✅ 完了
Scene_Title✅ 一旦完成
Scene_Start(UI・操作制御)✅ 完了
Scene_Start(君主選択制御)✅ 完了
Scene_Start(武将変更パネル)🔶 デザイン調整中
Scene_Start(ゲーム開始処理)🔶 未実装
Scene_Main⬜ 未着手

■ 次回の作業予定

Panel_OfficerSelectのデザイン仕上げ後、Scene_Mainの実装に入る。

GameStartData.CreateFromScenario()の実装・OnClickStart()の本実装から始め、マップ表示・ターン制御・コマンド実装と進める予定。

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

■ 10〜11日目のまとめ

今回は2日分をまとめて記録する。

10日目はScene_Startの基本実装が中心。勢力選択から確定まで一通りのUIフローが動くようになった。11日目はそこに機能を追加しつつ、データ設計の抜け漏れを潰した。


■ 10日目:Scene_Start 基本実装

勢力選択・確定フロー

Scene_Startのメインとなる画面遷移を実装した。

世界地図上の拠点アイコンをクリックするとPanel_FactionInfoが表示され、勢力の基本情報を確認できる。そこから「選択」を押すとPanel_FactionConfirmに遷移し、君主・配下武将のカード表示、各種変更ボタンが並ぶ確定ウィンドウになる。

拠点表示モードと勢力図モードの切り替えも実装済み。勢力図モードはalphaHitTestMinimumThresholdで透過部分のクリック判定を除外している。

状態管理

6状態のEnumで一元管理している。

Idle / FactionInfo / FactionConfirm / OfficerSelect / FaceImageSelect / ErrorDialog

状態によって操作可否を切り替える設計で、後の機能追加時にも拡張しやすい構造にした。

OfficerCard Prefab

武将カードUIをPrefab化してCommonに配置した。勢力確定ウィンドウと武将選択ダイアログで共用する。顔絵・名前・兵科・特技・三能力値を表示する。


■ 11日目:機能追加とデータ設計

配下武将変更ボタン

Panel_FactionConfirmの配下武将カード下部にボタンを配置した。

ScrollViewの配下カード列と並列にPanel_SubChangeButtonsを置き、配下数に応じてボタンをInstantiateする方式にした。LayoutGroupの動的生成でいくつか試行錯誤があったが、ラッパー構造は使わず並列配置で解決した。後でデザインボタンに差し替える予定なので、ボタンはPrefab(OfficerChangeButton)から生成する設計にしている。

君主画像差し替え機能

顔変更ボタンから起動する画像取り込みウィンドウを実装した。

Panel_ImageImportはCommon配置のPrefabで、カスタム武将登録でも流用できる設計にしている。OSのファイル選択ダイアログにはStandaloneFileBrowserを使用した。取り込んだ画像は512×768にリサイズし、上部384×384を顔絵として自動切り出しする。

対応フォーマット:PNG / JPG / JPEG
最大ファイルサイズ:10MB
出力サイズ(立ち絵):512×768
出力サイズ(顔絵):384×384(上部中央クロップ)

画像処理はImageImporter.csとして共通化した。

勢力名・君主名の編集機能

Panel_FactionEditを新規作成した。勢力確定ウィンドウの「勢力編集」ボタンから開き、勢力名と君主名をその場で変更できる。

文字数制限は以下で確定した。

項目日本語英語
武将名15文字19文字
勢力名10文字25文字

この制限値は武将登録画面でも共通仕様となる。

SaveDataRecord の新規設計

アプリ通算の実績データクラスを新規に設計・実装した。

これまでセーブデータはSaveDataSystem(設定)とSaveDataGame(プレイ進行)の2種類だったが、コレクション解放状況やカスタム武将管理のためにSaveDataRecordを追加した。SaveDataCustomOfficerとして別管理を検討していたが、ファイルを増やしたくないという方針からSaveDataRecordに統合した。

フィールド内容
areaClearRecordsエリア戦クリア記録(シナリオIDごと)
nationalClearCount全国版クリア回数
unlockedOfficerIdsコレクション解放済み武将IDリスト
customOfficerSlotCountカスタム武将スロット上限
customOfficers登録済みカスタム武将リスト

バージョンマイグレーション機構も組み込んだ。アップデートでフィールドを追加した場合は、ロード時に旧バージョンのデータを自動補完する。

ManagerSaveData の拡張

SaveDataSystem・SaveDataRecordの両方を同じ初期化フローで管理するように整理した。初回起動判定はisInitializedフラグで行い、ファイルパスの参照はManagerSaveData内に集約している。

ユーティリティメソッドも追加した。

IsNationalScenarioUnlocked()  // 全国版解放判定
IsAreaCleared(scenarioId)     // 指定シナリオのクリア判定
CalcCustomOfficerSlotCount()  // スロット上限の算出

Scene_Title:状態管理の刷新

TitleSceneState EnumをManagerTitle.csに導入した。これまでboolを複数管理していたが、Enumに一元化して各ボタンイベントに状態チェックを入れた。状態の階層構造は以下の通り。

Opening → WaitingInput → MainMenu(起点)
                              ├ ScenarioSelect → DifficultySelect → StartScene遷移
                              ├ Collection
                              ├ ForgeOfficer
                              ├ LoadGame
                              └ Option

同一レベル間の平行移動はなし、戻るは常に1レベル上へ、という設計で統一している。

Panel_Scenario.cs 新規作成

シナリオ選択パネルの専用スクリプトを作成した。シナリオ名のテキスト表示(LocalizeText使用)と、全国版ボタンの有効/無効制御を実装している。全国版かどうかの判定はIsNationalScenarioフラグで行い、シナリオIDのマジックナンバーは使用していない。キャンセルボタンも追加した。

今回からパネルごとに専用スクリプト1本という方針を確立した。


■ 現時点の開発状況

カテゴリ状況
データクラス全般✅ 完了
SaveDataRecord✅ 新規完了
Scene_Initialize✅ 完了
Scene_Title(基本)✅ 完了
Scene_Title(Collection・ForgeOfficer・LoadGame)🔶 未実装
Scene_Start(基本UI)✅ 完了
Scene_Start(武将選択・遷移)🔶 未実装
Scene_Main⬜ 未着手

■ 次回の作業予定

タイトルシーンの残実装(Collection・ForgeOfficer・LoadGame)を優先して進める。Scene_Startのスタートボタン遷移はその後。

【開発[#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週間くらいで作れると思ってた」は、いつも嘘になる。

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

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

【個人ゲーム開発39日目】戦術SLG制作

「増えた。」

39日目は、プロジェクトが2本になった日でした。

鋼鉄の交響曲の開発を続けながら、別のゲームを作り始めました。
正確には「作り始める準備が整った」という方が正しいかもしれません。

画面はまだ真っ暗で、ボタンもタイトルも仮のものだけ。
でも、ちゃんとシーンが遷移して、音が鳴って、セーブデータの場所が決まった。

それだけで、もう「動いている」と感じます。


■ ふりーむへのDEMO版登録

国内向けのプロモーション展開として、ふりーむにDEMO版を登録しました。

BOOTHとitch.io、フリーゲーム夢現に続く4つ目のプラットフォームです。

登録にあたっていくつか注意点がありました。

ゲーム紹介文には外部URLを記載できません。
Steam版の存在を「正式版は現在開発中です」という一文で示すことにしました。
直接誘導はできませんが、言葉で印象を残す形です。

ReadMeについても、素材クレジット以外の外部URLは削除が必要でした。
BOOTH・ブログへのリンクをすべて取り除き、Xのアカウント名表記のみ残しています。

セルフ審査の質問が細かく、「戦争テーマは該当するか」と少し迷いました。
ただ、ふりーむのガイドラインには「SRPG・隣国戦闘」が明確にOK例として挙げられていました。
残酷描写を目的とした作品ではないので、問題なしと判断しています。

現在は審査中です。結果はメールで届く予定です。


■ 展開状況まとめ

プラットフォーム状態
BOOTHv1.0.1 公開済み
itch.iov1.0.1 公開済み
フリーゲーム夢現公開済み
ふりーむ審査中
SteamKYC承認済み・30日待機中

■ 新プロジェクト「王国創世記」始動

知名度を作る手段として、無料ゲームをもう1本開発することにしました。

タイトルは「王国創世記 -Kingdom Chronicle: Fantasy Conquest-」。
ファンタジー世界を舞台にしたターン制戦略SLGです。

自分で作った将軍と配下武将で、20の国を持つ10勢力が覇を競います。
ルールはシンプルです。 隣接する国を攻め、外交で同盟を結び、謀略で配下を引き抜く。 難しい操作は不要で、戦略の判断だけに集中できる作りを目指しています。 鋼鉄の交響曲が「戦術」を楽しむゲームなら、こちらは「戦略」を楽しむゲームです。

鋼鉄の交響曲がニッチな戦術SLGなら、こちらは間口の広い戦略SLGで入口を作る。
そういう位置づけです。


■ 39日目でやったこと

鋼鉄の交響曲の開発をメインにしながら、王国創世記の基盤を1日で構築しました。

Unityプロジェクトを作り、シーン構成を決め、共通基盤のスクリプトを実装しました。
セーブ・ロード、多言語対応、シーン遷移、入力管理、音量設定、確認ダイアログ。
ゲームを作るたびに同じものを作っていたので、今回はテンプレートとして複製できる形に仕上げました。

次回以降の新規プロジェクトは、この状態からスタートできます。
1日分の作業が、今後何日かを短縮します。


執筆後記

プロジェクトが2本になった。

管理が増えるのは事実だけど、気持ち的には少し楽になった気がします。

鋼鉄の交響曲が行き詰まった時に、王国創世記を触ればいい。
王国創世記に詰まれば、鋼鉄に戻ればいい。

どちらかが止まっても、もう一方は動いている。
そういう状態を作っておくことが、長期開発の継続には大事なのかもしれません。

【個人ゲーム開発38日目】戦術SLG制作

「負けた。」

38日目は、ゲームに負けた日でした。

MISSION FAILED。
自軍の拠点を敵に占領されて、敗北しました。

ユニットは4体全員生存。戦力は開始時と変わらず100%。
完璧な状態のまま、拠点を取られて終わりました。

実装してから初めて出た「負け」の画面です。
悔しいより先に、「ちゃんと動いてる」という安堵がありました。


■ DEMOバグ修正・v1.0.1リリース

Xのフォロワーから詳細なフィードバックをいただきました。

「初級をクリアしたら中級を飛ばして上級に進んだ」という報告でした。

再現を試みると、「保存せずに進む」を選択した場合にのみ発生することが判明。
原因を追うと、ProceedToNext() が2回呼ばれていました。

Unity Input Systemの仕様で、ボタン表示のタイミングによってクリックイベントが貫通することがあります。
セーブパネルが表示された瞬間に、前のボタンへのクリックが「保存せずに進む」ボタンにも届いていました。

修正は _isProceeding フラグを1つ追加するだけでした。
シンプルな解決策ですが、原因特定まではかなり時間がかかりました。

その他、READMEにマップスクロール操作(右ドラッグ)の説明と、初回起動時のWindowsセキュリティ警告の対処手順を追記し、v1.0.1としてBOOTH・itch.ioを更新しています。

フィードバックをくださった方には、修正報告のリプライを送りました。
「遊んで報告してくれる人がいる」というのは、開発の大きな励みになります。


■ フリーゲーム夢現に投稿しました

国内向けのプロモーション展開として、フリーゲーム夢現にDEMO版を投稿しました。

投稿後、当日中に審査が通りました。
思っていたより早かったです。

週1本の制限があるサイトなので、更新頻度には注意が必要です。
BOOTHを正式配布場所として案内するテキストを掲載し、導線を整えています。


■ 中立ユニット占領システム完成

Steam版開発で進めていた中立ユニットシステムが、本日で完成しました。

Step2:自軍化座標への通行制限

制圧前の自軍化座標は、占領能力を持つユニット以外が通行できません。
Pathfindingの移動コスト計算に IsActivationCoord() の判定を組み込みました。

また占領可能ユニットは、その座標に到達した時点で移動が強制停止します。
通過してしまわないよう、ZOCと同じ仕組みで探索をそこで打ち切っています。

敵ユニットで囲むことで座標への進入路を塞ぐ、といった防衛戦術が生まれます。

Step3:旗ビジュアルと点滅ホバー

自軍化座標に旗を立てました。
2枚のスプライトを交互に切り替えるぱたぱたアニメーションで、グループ識別のためにギリシャ文字(α・β)をテキストで重ねています。

旗にカーソルを乗せると、関連する中立ユニットが点滅します。
「この旗を制圧するとこのユニットが動く」という情報を、プレイヤーが直感的に把握できるようにしました。

制圧完了と同時に旗は消えます。

実装中にいくつかバグも出ました。
GetNeutralUnitsAt() がリストの参照をそのまま返していたため、ホバー処理の Clear() で内部データが消えてしまう問題がありました。
new List<>() でコピーを返すことで解決しています。

地味ですが、見落とすと再現性のないバグになります。


■ 敵AIの拡張

占領システムに連動する形で、敵AIを拡張しました。

新しいAIパターン CaptureFirst を追加し、占領優先の行動ロジックを実装しています。

Aggressive + canCapture=true
→ 自軍化座標があれば占領を優先。攻撃はしない。
→ 座標がすべて制圧済みになったら通常の突撃行動に切り替え。

CaptureFirst + canCapture=true
→ 占領優先は同じ。
→ 座標消滅後は、プレイヤーの拠点を直接目指す。

さらに、敵が自軍化座標を制圧した場合、そのターン内に中立から敵化したユニットが追加行動を取るようにしました。
「制圧した瞬間に増援が動き出す」という緊張感が生まれます。


■ スクリプト設計の整理

TurnManager.cs が肥大化していたため、敵AIロジックを EnemyAIController.cs として分離しました。

移管した処理:

  • CanAIStartAction()(AI行動開始判定)
  • ExecuteUnitAction()(1ユニット分の行動実行)
  • FindApproachPath()(接近経路探索)

TurnManager はターン制御とフェーズ管理に専念する構成になりました。
将来的にスコアロジックや複雑なAI判定もここへ集約していく予定です。


■ Steamworks開発者承認

本日夜、Valveからメールが届きました。

「おめでとうございます。あなたはSteamworks開発者になりました。」

KYC申請(4/17)から5日での承認でした。
30日間の待機期間(4/17起算)は変わりませんが、ストアページの作成や設定はこれから進められます。

最短で5/17以降にストアフロントが公開できる見込みです。


執筆後記

MISSION FAILEDを見た時、少し笑ってしまった。

全ユニット生存・戦力100%のまま拠点を奪われた。
戦争に勝って戦略に負けた、という感じです。

「拠点を守りながら中立ユニットを確保しつつ敵を倒す」
そういう判断を迫られるゲームになりつつある。

38日目にして、ようやくゲームらしくなってきた気がします。

【個人ゲーム開発37日目】戦術SLG制作

「動き出した。」

37日目は、次へ向かう日でした。

DEMOを出した翌日。
静かな余韻の中で、次のことを考え始めていました。
Blueskyを始めて、リポジトリを分けて、コードを書いた。
「公開」から「開発」へ、気持ちが切り替わった一日です。


■ Bluesky、始めました

SNS展開の一環として、Blueskyに新規アカウントを作りました。

@hakubyousai.bsky.social

Xが主軸なのは変わりません。
ただ、英語圏へのリーチを考えると、Blueskyは無視できない選択肢でした。

ゲーム開発者向けのスターターパックが充実していて、登録してすぐに同業者を見つけやすい環境になっています。
Xと違い、外部リンクへのペナルティもないため、BOOTHやitch.ioのURLをそのまま貼れる点も魅力です。

ひとつ失敗したのは、日本語ハッシュタグが文字化けすること。
#ゲーム制作 と書いたつもりが #ゲーム制◆◆ になってしまいました。
Blueskyでは英語タグのみ使用する、と覚えておきます。

#gamedev #indiegame #pixelart #tactics


■ リポジトリを分けた

DEMO版と Steam版、開発リポジトリを分離しました。

D:\GitHub\SteelSymphony          → DEMO版(バグ修正専用)
D:\GitHub\SymphonyOfSteel_Steam  → Steam版(機能追加・正式版)

DEMOをリリースした直後の状態をベースに、Steam版用のリポジトリを新規作成しています。
今後、DEMOへのバグ修正はDEMO版で、新機能の実装はSteam版で、と明確に分離できます。

混ぜてしまうと後で必ず混乱します。
このタイミングで分けておいて正解でした。


■ アーキテクチャ改善:UnitAffiliation enum導入

Steam版開発の第一歩として、コードの改善から着手しました。

これまでユニットの陣営は isPlayer(bool)で管理していました。
自軍か否かの2択です。
ところが中立ユニットの実装を検討した瞬間、この設計が破綻しました。

isPlayer = false → 敵軍?中立?

判断できません。

そこで UnitAffiliation enumを導入しました。

public enum UnitAffiliation
{
    Player,  // 自軍
    Enemy,   // 敵軍
    Neutral  // 中立
}

既存コードへの影響を最小化するため、isPlayer は後方互換プロパティとして残しています。
触るファイルが多かったので、今後は各ファイルを改修する際に合わせて順次対応していく方針です。


■ 中立ユニットシステム実装(Step1)

Steam版の戦術要素追加として、中立ユニットシステムを実装しました。

ネクタリスの工場システムに触発されたものですが、「格納」ではなく「合流」という形にしています。

仕様

マップ上に白色で配置された中立ユニットグループが存在します。
グループごとに「自軍化座標」が設定されており、占領能力を持つユニットがその座標へ移動・行動終了すると、グループ全体がその陣営に所属します。

自軍が先に到達すれば即戦力として合流。
敵が先に到達すれば、事前に設定したAIパターンで動き始めます。

自軍化座標は1グループに複数設定できます。
左右から進軍して取り合う、といった状況も設計できます。

工夫した点

中立ユニットが「敵としてカウントされてしまう」問題が発生しました。
原因は MapManager の初期化処理が、全ユニットに Initialize() を呼び出していたためです。
中立ユニットをスキップする条件を追加することで解消しました。

また、移動途中(キャンセル可能な状態)で自軍化が発動してしまうバグもありました。
OnMoveComplete() ではなく SetDone()(行動確定)のタイミングで判定するよう修正しています。

ステージエディタも対応

Sceneビュー上で中立ユニットと自軍化座標をドラッグ操作できるよう、エディタツールも拡張しました。

白い球:中立ユニットの初期配置
黄色い球:自軍化座標(ACT:0、ACT:1…と複数表示)

中立ユニットはステージ開始時に白色をしています。

目印が無いのでわかりにくいですが、自軍化する座標に歩兵が待機すると白いユニットが味方(青色)になります。


■ 次にやること

Step2として、自軍化座標への通行制限を実装する予定です。
制圧前は占領可能ユニット以外が通行できないようにします。

Step3では旗のビジュアルとアニメーションを追加します。
α・β・γと描かれた旗がぱたぱたと揺れて、占領されたら消える、そういうイメージです。


執筆後記

DEMOを出してから最初の開発日だった。

「次に何をするか」は決まっていた。
でも実際に手を動かし始めると、少し不思議な感覚がある。
目標が「リリース」から「より良いゲームにすること」に変わった瞬間というか。

中立ユニットのシステムを実装しながら、ステージデザインの幅が広がっていくのを感じた。
作っていて楽しい、と思えた一日でした。

【個人ゲーム開発36日目】戦術SLG制作

「出した。」

36日目は、リリースの日でした。

BOOTH、itch.io、X。
朝から動いて、気づいたら夜になっていました。

作ったものを世界に出す、という行為がこんなに緊張するとは思っていませんでした。
反応があるかどうかより、「出した」という事実の方が、今は大きく感じています。


■ 本日やったこと

BOOTH商品ページを公開した

サムネイル選定から商品説明テキストの作成(日英中3言語)、段落構成の整備まで、一から作りました。

こだわった点はひとつ。
制作環境については何も書かなかった。

「Unity製」「フルスクラッチ開発」と書きたい気持ちはありましたが、それはプレイヤーにとって関係のない情報です。
伝えるべきはゲームの中身だけ、と判断しました。

itch.ioにも公開した

海外向けに英語ページを用意しました。

ひとつ気づいたことがあります。
紹介文に「Nectaris」と書いていたのですが、海外では「Military Madness」として知られているタイトルでした。
両方を併記する形に修正しています。

Symphony of Steel is a turn-based hex strategy game inspired by the classic tactical SLG “Nectaris” (known as Military Madness in the West).

プレイ動画(Stage 1クリアまで)もYouTubeに限定公開し、ページへ埋め込みました。
動画があるとページの説得力が全然違います。


■ 36日間を振り返る

せっかくなので、今日は開発の変遷を画像で振り返ってみます。

戦術マップの変遷

開発初期、マップは本当に殺風景でした。
色のついた四角形がヘックスを示しているだけで、「これがゲームになるのか」と自分でも半信半疑でした。

以下は3月16日頃の画像。丸や四角がユニットです。

地形チップが増えるにつれて、少しずつ「戦場らしさ」が出てきました。
草原や森、都市。仮の地形画像を作成して配置するだけでゲームっぽさもアップ。
ユニットが置かれた瞬間に、はじめてゲームに見えてくるものです。
しかし素材がAIポン出しで統一感無いですね(笑)

現在のマップです。
地形チップはまだ全14種中5種しか完成していませんが、
それでも初期と比べると隔世の感があります。
異なる地形間の接続とか作れてないですが、質感はだいぶまとまってきたかなと。

戦闘画面の変遷

戦闘画面は、最も試行錯誤した部分です。

最初期は、まずユニットを表示する。次にただ数字が表示するといった感じで見た目も全然作り込んでません(笑)
ATKとDEFとHPが表示されているだけで、演出も何もない。
常時表示されているデバッグ用ボタンがなんとも。

以下の画像は3月17日から3月18日頃に撮影していました。

その後、戦闘背景・ユニットスプライト・エフェクトと順番に追加していきました。
爆発エフェクト、ヒットエフェクト、回復エフェクト。
音も付いた。
少しづつ現在の形に近づいていきます。

この辺で大まかなイメージが固まってきた感じです。画像は3月23日に撮影。

そして36日目の時点では、補正表示まで追加されています。
地形ボーナス、支援ボーナス、包囲ペナルティが色分けされてフェードインする。

「数字が並んでいた画面」が、ここまで来ました。

UIの変遷

UIはおそらく、最も変化が激しかった部分です。

初期のUIは仮置きの白いパネルばかりでした。
フォントも暫定、色も暫定、レイアウトも暫定。
「動けばいい」という段階です。

タイトル画面もテキスト直書きしてるだけのシュールさ。
3月19日のスクリーンショットですね。見た目はともかく動けばいいという感じ(笑)

戦術画面も早期に下部パネルは作りだしていますが、右側はすっかすかでターン終了のボタンだけ配置してただ動かせますといった状態。
以下の画像は3月25日に撮影してます。この辺の作業の2~3日で劇的にゲーム画面が変化しました。

現在のUIです。
タイトル画面は大幅に改修し、戦術画面もユニット情報パネル、フェーズ表示、各種ボタンなど賑やかになりました。
まだ統一感に課題はありますが、「ゲームのUI」として機能するものになりました。


■ 36日間でできたこと・できなかったこと

できたこと

  • ヘックスグリッドの戦術マップ
  • ターン制の戦闘システム
  • 地形効果・支援ボーナス・包囲補正
  • 熟練度システム(0〜20・星表示)
  • セーブスロット3つ
  • 日英中3言語対応
  • BGM・SE
  • 勝敗ファンファーレ
  • バトル画面補正表示
  • セーブデータバージョン管理基盤
  • DEMOビルド完成・公開

できなかったこと(正式版へ先送り)

  • 解像度1920×1080対応
  • ピクセルアートの統一感
  • 自動ターン終了
  • 画像系素材の準備(一部、DEMO完成優先で先送りなど。)

「できなかったこと」は、意図的に先送りにしたものがほとんどです。
完璧を目指してリリースしないより、動くものを出してフィードバックをもらう方が正しいと判断しました。


■ これから

Steam版の公開を5月17日以降に目指しています。

まずはSteamworks SDKの導入。
そしてストアページの素材準備。

DEMOへの反応を見ながら、正式版の完成度を上げていきます。

無料で遊べるDEMO版はこちらです。

BOOTH:https://atelier-ksg.booth.pm/items/8223410
itch.io:https://hakubyousai.itch.io/symphony-of-steel-demo


執筆後記

リリース日の記事を書くのは、思ったより難しかった。

「やったこと」より「感じたこと」の方が多い日でした。
出してしまえばこっちのもの、と思っていたのですが、出した後の方が静かで、少し怖い。

反応がくれば嬉しいし、こなくても続ける。
それだけです。

【個人ゲーム開発35日目】戦術SLG制作

「リリースの形が、ようやく見えてきた」日

35日目は、開発系の実装とリリース準備を同時に進めた一日でした。

バトル画面への補正表示追加。
セーブデータのバージョン管理基盤の導入。
ビルド作成、アイコン・カーソルの設定、README作成。

やることが多かったですが、気づいたら全部終わっていました。


■ バトル画面に補正表示を追加した

何が変わったか

戦闘前の準備フェーズに、発生した補正をパネルの下部へ積み上げ表示する演出を追加しました。

表示される補正は以下の4種類です。

  • 地形防御補正(EFFECT DEF+XX% / DEF-XX%):プラスは緑、マイナスは赤
  • 支援攻撃ボーナス(SUPPORT ATK +):シアン
  • ジャミング制圧ボーナス(SUPPORT DEF +):シアン
  • 包囲成立(FLANKED ATK/DEF -50%):オレンジ

補正が発生しない場合は表示されません。詰めて表示します。

演出のこだわり

ただテキストを出すだけでは面白くないので、出現時に少し工夫しました。

白くフラッシュしながら大きいサイズで出現し、指定の色・通常サイズへ収縮する。
0.2秒程度の短い演出ですが、「補正が乗った」感が出ていい感じです。

InspectorでフラッシュのdurationとスケールのStart倍率をチューニングできるようにしてあります。

包囲表示の文言について

包囲成立の表示に「×½」という表記を使おうとしたのですが、
使用フォントで「×」「½」の両方を表示できず断念しました。

ASCII文字のみで構成した「FLANKED ATK/DEF -50%」に落ち着いています。
英語圏のプレイヤーにも伝わる表現なので、結果的にこちらの方が良かったかもしれません。

最初は雑にTextオブジェクトにとりあえず正しく動いてるか確認できるレベルで実装テストします。


最終的には以下のようになりました。

■ ターンチェンジ回復SEを追加した

回復エフェクト(緑の+N表示)は実装済みでしたが、音が鳴っていませんでした。

HealEffectRoutine()の冒頭にSE再生を1行追加するだけで完了です。
既存の爆発SEと同じパターンなので、影響範囲はUnitController.csのみ。シンプルな修正でした。


■ セーブデータのバージョン管理基盤を作った

なぜ今やるのか

開発中にセーブデータの構造は頻繁に変わります。
フィールドを追加したり、削除したり、型を変えたり。

そのたびにユーザーに「セーブデータを削除してください」と伝えるわけにはいきません。
DEMO版のうちに仕組みを入れておくべき、と判断しました。

設計の方針

基本思想は「読めたら移行、読めなければ削除して初期化」の2段構えです。

起動時
 └─ SaveDataMigrator.Migrate()
      ├─ バージョン確認
      ├─ 旧バージョン → 移行処理(フィールド補完)
      ├─ 破損 → 削除して初期化
      └─ ダウングレード → 削除して初期化

各JSONファイルに saveVersion フィールドを追加し、アプリ側に現行バージョン定数を持たせます。

public static class SaveDataVersion
{
    public const int SAVE_DATA   = 1;
    public const int SYSTEM_DATA = 1;
}

将来の運用

構造を変えるたびに SaveDataVersion を +1 し、MigrateSaveDataFrom() に移行処理を追記するだけです。

累積適用パターン(if (oldVersion <= N))で書いておけば、v0のデータが来てもv1→v2→v3と順番に全部適用されます。
離れたバージョン間の移行を個別に考える必要がありません。

ちなみに今回、JsonUtility はフィールドが増えても減ってもデフォルト値で黙って読んでくれることを改めて確認しました。
つまりフィールドの追加・削除だけなら「バージョンアップして上書き保存」するだけで十分です。
本当に困るのは型が変わった場合や、JSONとして物理的に壊れた場合だけです。


■ ビルド作成と各種設定

Company Name / Product Name を英数字に統一した

ビルドを作る前に、Player Settingsを整理しました。

日本語のCompany Name・Product Nameをそのまま使うと、
中国語環境のWindowsで文字化けや起動失敗のリスクがあります。

設定項目変更前変更後
Company Nameスタジオ白猫斎・くそげ工房StudioHakubyousai
Product Name鋼鉄の交響曲 -Symphony of Steel-SymphonyOfSteel

Company Nameを変えるとpersistentDataPath(セーブデータの保存先)も変わります。
DEMO版初回リリースのこのタイミングで変えておかないと、
正式版リリース後に変えた場合、既存ユーザーのセーブデータが消えます。
今変えておいて正解でした。

アイコンとカーソルを設定した

どちらもChatGPTで生成しました。

アイコンは512×512のピクセルアート風戦車画像。
ヘックスグリッドの背景に戦車のシルエット、という構成で、ゲームの雰囲気が伝わりやすいデザインになっています。

カーソルは64×64のシェブロン(階級章)モチーフの矢印。
ミリタリー感があってゲームに合っています。

カーソルはPlayer SettingsだけではなくコードでもCursor.SetCursor()を呼ぶ必要がありました。
Unityあるあるですね。

以下はアイコン画像です。

ビルドサイズについて

ビルドフォルダの解凍後サイズは約679MB。
思ったより大きいと感じましたが、中国語フォントが130MB超あることが判明しました。

これはFont Assetの文字セットを使用文字だけに絞れば大幅削減できます。
ただしDEMO版はレイアウトが完成しており今から変更するのは手間なので、正式版で対応する予定です。

ZIP圧縮後は約254MBまで減りました。予想より圧縮が効いて良かったです。

README.txtを作成した

日本語・英語・中国語の3言語を1ファイルに収録しました。

記載内容は以下の通りです。

  • ゲーム概要・動作環境・起動方法
  • 操作説明(マウスオンリー、左クリック決定・右クリックキャンセルが基本)
  • 注意事項・免責事項
  • クレジット(BGM:PeriTune様、SE:効果音ラボ様、フォント、AI開発支援)

AI開発支援については Claude・ChatGPT・Gemini の3つを記載しています。
今やAIなしでの個人開発は考えられないので、きちんとクレジットしておきたいと思いました。


■ 現在の残タスク(35日目時点)

カテゴリ項目状況
配布準備BOOTH商品ページ作成未対応←次回最優先
SteamKYC審査審査中(〜7営業日)
Steam30日待機進行中(〜5/17)
配布準備エンディング告知差し替え公開直前でOK
正式版中国語フォント最適化5/17以降

執筆後記

今日は「実装」と「リリース準備」を同時に走らせた一日でした。

バトル画面の補正表示は、ずっと「余力があれば」と先送りにしていた機能です。
やってみたら思ったより工数がかからず、演出もいい感じに仕上がりました。
先送りにしていた自分を少し反省しています。

セーブデータのバージョン管理は、地味ですがリリース前に必ず入れておくべき仕組みでした。
ユーザーに「フォルダのファイルを消してください」と伝える未来を回避できました。

ビルドも出来た。READMEも書いた。
次はBOOTH商品ページを作れば、DEMO版のリリースが現実になります。
もう少しです。

【個人ゲーム開発34日目】戦術SLG制作

「配布準備が、全部動き出した」日

34日目は、リリースに向けた実務を一気に片付けた一日でした。

BOOTHショップの公開。Steamworksへの開発者登録。
どちらも「やらないといけないのはわかってるけど後回しにしてた」作業です。

気づいたら両方終わっていました。


■ BOOTHショップ公開

ショップのコンセプトを整理した

今回のBOOTHショップは、鋼鉄の交響曲専用ではなく「スタジオ白猫斎のくそげ工房」として設計しています。

将来的に複数のゲームを出す想定のため、特定タイトルに依存しない構成にしました。
親ブランド「くそげ工房」・子ブランド「スタジオ白猫斎」という関係で、ヘッダー画像にも両方のロゴを配置しています。

ショップ名:白猫斎のくそげ工房 / Studio Hakubyousai (Atelier-KSG)
URL:https://atelier-ksg.booth.pm/

特定商取引法に基づく表記を整備した

無料配布でも、特定商取引法の表記は整備しておくべきと判断しました。

個人・無料配布のみという条件では義務対象外ですが、表記があることで閲覧者への信頼感が上がります。
また将来有料販売を始めた際の対応コストを下げる意味でも、今のうちに整えておく方が合理的です。

特に重要だと感じたのが免責事項です。

フリーウェアを配布する以上、
「このゲームを使って生じた損害には責任を負わない」
という旨を明記しておかないと、万が一のクレームへの対応が難しくなります。

今回の表記には以下を含めています。

・本ソフトウェアの使用により生じたいかなる損害についても開発者は責任を負わない
・動作を完全に保証するものではない
・ご自身の責任においてご使用ください

無料で配って責任を取らされる事態は避けたいので、ここは慎重に対応しました。


■ Steamworks開発者登録

思ったより手続きが多かった

Steamでゲームを販売するためには、Steamworksへの開発者登録が必要です。
登録自体は無料ですが、ゲームを1本登録するたびに$100(Steam Direct料金)の支払いが必要になります。

今回の手続きの流れは以下の通りです。

  1. Steamworksアカウント登録
  2. NDA(秘密保持契約)署名
  3. SDA(Steam配信契約)署名
  4. $100支払い
  5. 銀行口座情報入力
  6. 税金情報(W-8BEN)提出
  7. 本人確認書類(KYC)アップロード

一日でここまで終わらせるつもりはなかったのですが、一つ終わるたびに次のステップが見えてくるので、結果的に全部やりきりました。

税金情報でつまずきそうなポイント

海外販売では米国の税務申告に対応したフォーム(W-8BEN)の提出が必要です。
日本在住の個人であれば、日米租税条約が適用されます。

マイナンバー(個人番号)を外国TINとして提供することで、源泉徴収税率0%が適用されました。

つまり、Steamの売上から米国税が引かれない状態になっています。
これは日本と米国が租税条約を結んでいるためで、日本在住の開発者には有利な条件です。

30日待機がスタートした

$100を支払った日から、ゲームをリリースできるようになるまで30日間の待機期間があります。
これはValveが取引相手の情報を確認するための期間です。

4月17日に支払いを完了したため、5月17日以降にストアページの公開(「近日登場」)が可能になります。
実際の販売開始はそこからさらに最低2週間後となるため、最短でも6月上旬の見込みです。

この待機期間中にストアページの作成・審査・「近日登場」ページの公開を進めることができるため、
実質的に準備を並行して進めることになります。

とりあえず$100払ったから後戻りはできないですね(笑)
絶対に何かは販売します。売れるかはわからないですが…。


■ 現在の残タスク(34日目時点)

カテゴリ項目状況
配布準備BOOTHショップ公開完了✅
配布準備Steamworks登録・$100支払い完了✅
配布準備KYC審査審査中(2〜7営業日)
配布準備BOOTH商品ページ作成未対応
Steam30日待機進行中(〜5/17)
Steamストアページ作成・素材準備未対応
判断待ちバトル画面補正表示(DEF+/ATK+等)余力次第

執筆後記

今日は「やらなきゃいけないけど面倒くさそう」な作業を全部片付けた日でした。

BOOTHショップは思ったよりシンプルに整えられました。
Steamworksは思ったより手順が多かったです。

ただ、どちらも「やり始めれば終わる」作業でした。
後回しにしている間の精神的負荷の方が、実際の作業コストより高かったかもしれません。

次の作業はBOOTH商品ページの作成です。
ビルドを作り、READMEを書き、説明文を用意する。
ここまで来たら、あとは手を動かすだけです。

【個人ゲーム開発33日目】戦術SLG制作

「DEMO版の中身が揃った」日

33日目は、積み残していたコンテンツ制作を一気に片付けた一日でした。

ステージストーリーテキスト、ブリーフィングイメージアート、AIバグ修正。
それぞれ個別には小さな作業に見えますが、これで「DEMO版として出せる中身」が揃いました。
残るは配布準備だけです。


■ ステージストーリーテキスト:全4ステージ完了

攻略ヒントを命令口調に溶け込ませる、という方針を継続

前回、ステージ1「初級演習」のテキストが完成していました。
33日目では残る3ステージ分を一気に作成し、全4ステージが完了しました。

各ステージのテーマは以下の通りです。

ステージタイトルテーマ
1初級演習包囲戦術・数的優勢・深追い禁止
2中級演習二方向対応・有利地形確保・防衛布陣
3上級演習三正面対応・自走砲活用・戦力1.5倍の不利
4卒業試験戦力2倍・指導教官車両ギミック・占領勝利

難易度が上がるにつれて、テキストの締めくくりも変化させています。

  • ステージ1:「速やかに敵を掃討せよ」(基礎の確認)
  • ステージ2:「それが今回の演習で問われる判断力だ」(応用)
  • ステージ3:「判断の質だ」(戦略的思考)
  • ステージ4:「卒業してみせろ」(総仕上げ)

単なる状況説明ではなく、指揮官としての成長を示す流れになっています。
日本語・英語・中国語の3言語で作成しています。


■ ブリーフィングイメージアート:全4枚確定

ChatGPTを使ったピクセルアート生成

ブリーフィング画面に表示するイメージアートを、ChatGPTで生成しました。

方針として「ゲーム本体のドット絵と世界観を合わせる」ことを優先し、
ピクセルアート調・俯瞰視点・くすんだ色調で統一しています。

ステージ構図・テーマ
1将校3人が地図テーブルを囲む・草原(新米指揮官の初演習)
2荒野・敵が分散して二方向から迫るイメージ
3制作済み素材を採用
4森林・圧倒的な敵戦力との対峙

試行錯誤のポイントとして、画像参照よりもテキストプロンプトで
スタイルを言語化する方が安定した結果になりました。
また矢印やUIっぽい要素が混入しやすいため、
「no arrows, no UI elements」の明示が必須でした。

DEMO版のクオリティとして十分と判断し、全4枚を確定としました。


■ 敵AIバグ修正:StationaryとDefensive

Stationary:射程内でも攻撃しない問題

待機型AI(Stationary)が、攻撃範囲内にプレイヤーユニットがいるにもかかわらず攻撃しない場合がある、というバグを修正しました。

原因はターゲット選択のスコア計算にありました。
ダメージ期待値が低いユニットに対してスコアが不安定になるケースがあり、結果として攻撃対象が選ばれないまま行動終了していました。

特に防御力の高い超重戦車に対して顕著で、経験値が上がって攻撃力が増すと攻撃し始めるという、意図しない挙動になっていました。

修正方針として、Stationaryは「射程内の最初のターゲットを即採用」する専用ロジックに変更しました。
「動かない砲台は射程内なら必ず撃つ」という直感的な挙動になっています。

影響範囲はTurnManager.csのEnemyRoutine内のみです。

Defensive:移動後射程での攻撃判定漏れ

防御型AI(Defensive)が、移動すれば攻撃可能な範囲にプレイヤーユニットが入っても攻撃してこない問題を修正しました。

判定が「現在地からの攻撃射程」のみで、「移動後に攻撃可能か」を見ていなかったことが原因です。

修正後は意図した挙動で動作することを確認しています。


■ X運用続報:フォロワー整理の結果

前回の推論を実行に移した

前回の記事で「無反応フォロワーの増加が初動インプレッションを下げる」という推論を書きました。

4月15日、急増したフォロワーの約10%を整理しました。
整理の基準は「フォロワー数の増加・インプレッション・収益化のみを目的とした発信しかしていないアカウント」です。

結果:インプレッションが明確に改善した

4月15日・16日のインプレッションが、直前の数日と比較して明確に改善しました。

グラフを見ると、4月9日の#ブルバ100実施後にフォロワーが急増し、数日後にインプレッションが落ち込む流れがはっきり確認できます。
フォロワー整理後の4月15〜16日は、この落ち込みから回復しています。

考察

今回の結果から言えることを整理します。

フォロワー整理はマイナスを減らす作業

フォロワー整理によってインプレッションが回復したのは、自分の投稿に関心を持つアクティブフォロワーの割合が増えたためと考えています。
Xは投稿直後の初期反応でリーチを決める構造のため、無反応フォロワーの割合が高いほど投稿が広がりにくくなります。

ただし、これはあくまで「マイナスを減らした」に過ぎません。
フォロワーを整理しても、反応してくれる層が増えるわけではないからです。

ブルバ100が悪いわけではない

念のために書いておくと、#ブルバ100という手法自体が良い・悪いという話ではありません。

フォロワー増加・インプレッション拡大・収益化を目的とした発信であれば、ブルバで集まる層とコンテンツのテーマが一致するため、非常に強い拡散力を持つ手法です。

私の場合、個人ゲーム開発が主なテーマのため、増えたフォロワーとのニーズにミスマッチが生じました。
それが今回の結果の原因です。

本質は地道な積み上げ

結論として、インプレッションを安定させるには「自分のコンテンツに関心を持つフォロワーを地道に増やす」以外に近道はないという考えに至っています。

数を追うのではなく、反応する層を丁寧に作っていく。
宣伝フェーズに向けて、この方針で運用を続けます。


■ 現在の残タスク(33日目時点)

カテゴリ項目状況
コンテンツステージストーリーテキスト(4ステージ)完了
コンテンツステージイメージアート(4枚)完了
コンテンツエンディングスクロールテキスト実質完了(告知部分のみ差し替え待ち)
配布準備BOOTHヘッダー画像未対応
配布準備特定商取引法に基づく表示未対応(公開前必須)

執筆後記

DEMO版の中身が揃いました。
33日間かけて積み上げてきたものが、ゲームとして形になっています。

残るは配布準備だけです。
BOOTHヘッダー画像と特定商取引法の表示を片付ければ、4月下旬のリリースが現実的な射程に入ってきました。

X運用の話は、ゲーム開発とは少し離れたテーマですが、宣伝フェーズで同じ失敗をしないための記録として残しています。
個人開発者がSNSで発信する場合、数より質という話は理屈ではわかっていても、実際にデータで確認すると改めて実感します。

リリースに向けて、最後の準備を進めます。