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

「ゲームを組み上げる」作業に入った日

32日目は、目に見える成果物が少ない一日でした。

マップを組んで、ユニットを配置して、テストプレイをして、「なんか違う」と感じて直す。
その繰り返しです。
コードもアセットも増えていないのに、時間だけが溶けていく感覚があります。

ただ、これは「進んでいない」のではありません。
ゲームとしての面白さを直接作っている作業です。
素材を揃えてきた31日間の答え合わせが、ここから始まっています。


■ ステージデータ作成:マップ・ユニット配置 4本完了

まず「箱」を全部作った

DEMO版4ステージ分のマップデザインとユニット配置が完了しました。

項目進捗
マップデザイン4/4 完了
ユニット配置4/4 完了
ストーリーテキスト1/4(ステージ1完了)
イメージアート方向性検討中

マップとユニット配置が終わったことで、各ステージの「骨格」は揃いました。
ここからストーリーテキストとイメージアートを乗せていく作業になります。

地形チップで道路ができたので早速ステージ1に配置。他に防壁や都市なども配置してステージ1のDEMO版マップが完成しました。


■ ステージ1「初級演習」ストーリーテキスト確定

攻略ヒントを命令口調に溶け込ませる

ブリーフィング画面に表示するストーリーテキストの方針として、
単なる世界観の説明ではなく「攻略に繋がるヒントを命令口調で伝える」という形を取っています。

ステージ1で盛り込んだ要素は次の通りです。

  • 包囲戦術のレクチャー(複数方向から囲む)
  • 数的優勢・分散禁止の指針
  • 道路沿い進軍への対処(有利地形への布陣)
  • 深追い禁止(逆撃リスクの示唆)
  • 評価基準の示唆(犠牲最小・速やかな掃討)

確定テキストは以下の通りです。


新米指揮官に告ぐ。これより初級軍事演習を開始する。
 現状の戦力分析では我が軍が優勢だ。しかし敵の一部はすでに自陣深くまで浸透している。複数方向から包囲して各個撃破せよ。孤立した敵を囲み、確実に仕留めろ。
 撃破後は速やかに前線を構築せよ。敵は道路沿いに進軍してくる――周囲の地形を把握し、有利な地形に布陣せよ。部隊は分散させず、常にこちらが数的優勢となるよう展開して迎え撃て。単身での深追いは禁物だ。敵に逆撃の好機を与えることになる。
 貴官の采配で犠牲を最小限に抑え、速やかに敵を掃討せよ。


日本語・英語・中国語の3言語版を作成・確定しました。


■ X(Twitter)運用:フォロワーの質とアルゴリズムを整理した

「フォロワーが増えたのにインプレッションが落ちた」を解剖する

ブルーバッヂ取得後、フォロワーが急増しました。
しかしそれに比例して、インプレッションが伸びているわけではありません。
むしろ投稿の初動が以前より鈍くなった感覚があります。

宣伝フェーズに備えて、3種の生成AIを使ってこの現象の原因を整理しました。

※以下はAI複数ツールを使って整理した考察です。正確性は保証できませんが、自分なりに納得感のある仮説として記録しておきます。

Xのアルゴリズムの仕組み

Xは投稿直後、まずフォロワーとその周辺層に表示します。
ここでの反応(いいね・滞在時間など)が良ければ拡散され、悪ければそこで止まります。

つまり、フォロワーが反応しなければ「面白くない投稿」と判定される仕組みです。
フォロワーの数より、フォロワーの質(反応するかどうか)の方が重要です。

ブルバ100で「一時的に爆発する」仕組み

「#ブルバ100」などのタグを使ったフォロワー増加は、状況によって効果がまったく異なります。

ブルバ系タグで集まるユーザーは、フォロワーを増やしたい・インプレッションを伸ばしたいという共通の目的を持っています。
そのため、フォローし合い・いいねし合い・リポストし合うという行動が自然に発生します。
結果として、短期間で相互に評価を押し上げる相乗効果が生まれます。
これが「ブルバで伸びた」と感じる正体です。

なぜその後に失速するのか

問題はここからです。

ブルバで増えたフォロワーは、基本的にあなたのコンテンツに興味があってフォローしているわけではありません。
ゲーム開発アカウントであっても、増えるのはゲーム開発に興味のない層です。

その結果、投稿がタイムラインに流れても反応しない・滞在時間が短い・いいねが発生しない、という状態になります。
投稿直後の初期評価が下がり、拡散されないまま終わります。

よくある誤解として「フォロワーが増えればインプレッションも増えるはず」というものがあります。
しかし実際は、反応するフォロワーが増えない限り意味がありません。
無反応フォロワーが増えることで、フォロワー増加がむしろマイナスに働くケースすらあります。

ブルバが「効く」ケースとの違い

ブルバでも効果が出るケースは存在します。

それは、投稿内容自体がブルバ層に最適化されている場合です。
フォロワーを増やすノウハウ・インプレッションの話題・収益化情報といった、ブルバ参加者が興味を持つ内容を投稿している場合は、フォロワー増加・投稿内容・反応する層が一致するため、非常に強い拡散力を持ちます。

ゲーム開発アカウントとして、インディーゲーム開発クラスタ以外の層を増やしても効果が薄いのはこの構造が原因です。

整理した対策

フォロワーを整理する場合は「ブロ解(ブロック→解除)」が基本です。
フォロー解除では相手のフォロー関係は変わらず、ブロック維持は完全遮断になるため、フォロー関係をリセットしたいだけならブロ解が適切です。
一気にやらず、1日10〜30人程度を目安に、投稿と並行して行います。

ただし、フォロワー整理はあくまで「マイナスを減らす作業」です。
本質的に重要なのは、反応してくれる層を作ることです。

具体的には、投稿を完成品・制作途中・比較(before→after)の3パターンで出し、反応率(いいね÷インプレッション)を見ながら刺さるコンテンツを特定する方法が有効です。
反応が良い投稿に反応しない層を少しずつ整理していく、という進め方になります。


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

カテゴリ項目状況
コンテンツステージストーリーテキスト(4ステージ)1/4
コンテンツステージイメージアート(4枚)方向性検討中
コンテンツエンディングスクロールテキスト未対応
配布準備BOOTHヘッダー画像未対応
配布準備特定商取引法に基づく表示未対応(公開前必須)

執筆後記

マップとユニット配置が4本揃ったのは、地味に大きな節目です。
「ゲームが4本ある」状態になったわけで、あとは中身を整えるだけです。

X運用の整理は、ゲーム開発とは少し離れた話ですが、
宣伝フェーズで失敗しないための準備として必要な作業だと思っています。
ブルバで数を増やしても、コンテンツと層が一致していなければ逆効果になる。
この構造を理解しているかどうかで、宣伝フェーズの効率がかなり変わってくると思います。

ストーリーテキストとイメージアートの制作を進めます。
ゲームの顔を作る作業です。

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

「素材が終わった日」と「コードを直した日」

31日目は、素材制作とプログラム改修が混在した一日になりました。

地形チップの最後の1種を仕上げながら、並行していくつかの機能改善とバグ修正を進めました。
量でいえば多くはありません。
ただ、地形チップが全種完了したことで、ステージデータ設定に着手できる状態になりました。
残タスクの性質が「素材を作る」から「ゲームを組み上げる」へ、確実に移っています。


■ 地形チップ 14/14 完了

道路チップで手こずったが、完走した

31日目の最後の素材作業は道路チップです。

道路は直線・斜め・カーブと形状のバリエーションがあり、
さらに背景となる地形(草地・荒れ地・泥地・砂漠)との組み合わせで枚数が一気に増えます。
T字路・十字路まで対応しようとすると、それだけで30枚超になる計算です。

DEMO版では割り切りました。
直線・斜め・カーブのみ対応し、T字路・十字路はDEMO対象外とします。
「ゲームに必要な分だけ揃える」という判断は、この開発を通じて何度も繰り返してきた判断です。

これにより、地形チップ14/14が完了しました。
ステージデータ設定のブロッカーがなくなりました。

道路はとにかくパターンが多くて(笑)


■ サイズ回避補正の数値調整

「計算通りに展開できない」を直す

本作の戦闘計算には、ユニットサイズによる回避補正があります。
小型ユニットほど被弾しにくく、大型ユニットほど当たりやすいという設計です。

以前実装した数値では、サイズ2〜3(中型ユニット)の回避率が過剰で、
乱数による撃ち漏らしが頻発していました。
「戦力差があるはずなのに思った通りに削れない」という展開が続き、調整することにしました。

変更後の補正値は以下の通りです。

ユニットサイズ命中率補正
5(最大)補正なし
4-2%
3-5%
2-10%
1(最小)-20%

サイズ1は「小さくて当てにくい」感覚を残したいため、-20%のままにしています。
サイズ3〜4は「ほぼ当たる」レベルに寄せました。
テストプレイの感触はかなり改善されています。


■ ターン開始時の回復演出

大戦略系の定番演出を実装した

ターン開始時に回復地形(拠点・都市など)の上にいるユニットがHPを回復する処理は
以前から実装済みでした。
今回はそこに演出を追加しました。

実装した内容は次の通りです。

  • 回復が発生するユニットへ、1体ずつカメラがフォーカスする
  • ユニットの頭上に緑の「+N」テキストが上昇・フェードアウトする
  • HP満タンのユニットは演出・カメラフォーカスともスキップする
  • 表示される回復量は実際の回復量(MAX超えなし)に合わせる
  • プレイヤーターン・敵ターンどちらも演出あり

「回復が起きていることが一目でわかる」という大戦略・ファミコンウォーズ系の定番演出です。
カメラが順番に飛んでいくことで、ターン開始のリズムが生まれます。

また、地形情報パネル(画面下部)にも回復情報を追加しました。

DEF: +20%
HEAL: +2~3

回復量の定義はTileDataに一元管理しています。
表示と実計算で同じ値を参照する設計にしたため、
数値を変更したい場合はTileData側の1箇所を直すだけで済みます。


■ バグ修正 4件

ユニットの白点滅が残り続ける問題を根本から直した

今日修正したバグのうち、最も影響範囲が大きかったのはユニットの白点滅残留です。

本作では、選択中のユニットや敵ユニットホバー時に白点滅(フラッシュ)エフェクトが出ます。
ターン終了時やウィンドウ操作後にこの点滅が消えず、敵ターン中も白く光り続けるという
見た目上の不具合が複数のパターンで発生していました。

修正した内容は4件です。

① ターン終了時に移動範囲ハイライトが残る
ターン終了ボタンを押した際に選択状態の解除処理が走っていなかった問題。
ターン終了処理の冒頭で強制解除メソッドを呼ぶように修正しました。

② 敵ホバー・自軍選択の点滅が敵ターン中も残る
強制解除メソッドが選択ユニットの点滅しか止めておらず、
敵ホバー中のユニットの点滅が残り続けていた問題。
強制解除時に全敵ユニットの点滅も一括停止するよう修正しました。

③ 敵詳細ウィンドウを閉じた後に点滅が残る
詳細ウィンドウが開いている間はカーソル処理が止まるため、
ウィンドウを閉じた後に古いホバー状態の点滅が残る問題。
ウィンドウを閉じる処理にホバー状態のリセットを追加しました。

④ 複数の隣接敵ユニットを順にホバーすると全員点滅し続ける
ホバーが素早く切り替わった際に、途中で通過したユニットの点滅停止処理が
呼ばれないケースがあった問題。
ホバー切り替え時に全敵ユニットの点滅を一括停止してからリセットする方式に変更しました。

原因はいずれも「点滅開始の管理は各所でやっているが、停止の管理が漏れやすい構造」でした。
根本対処として、全敵ユニットを一括停止するメソッドを用意して、
解除が必要な場面で確実に呼ぶ設計にしています。


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

カテゴリ項目状況
コンテンツステージデータ設定(4ステージ)0/4・着手可能になった
コンテンツエンディングスクロールテキスト未対応
配布準備BOOTHヘッダー画像未対応
配布準備特定商取引法に基づく表示未対応(公開前に必須)

素材作業は全完了です。
次の主戦場はステージデータ設定4本です。


執筆後記

地形チップが終わった瞬間、正直ほっとしました。
道路は「最後にこれが来るか」という作業量でしたが、
T字路・十字路を切る判断ができたのは、以前の自分より少し賢くなった気がします。

バグ修正4件は、「なぜ消えないのか」の原因を順番に掘っていく作業でした。
ユニットの白点滅が残り続ける問題は、再現条件がいくつかあって、
1件直したと思ったら別のパターンで再現して、という繰り返しでした。
最終的に「全敵ユニットを一括停止する」という単純な解決策に落ち着いたのが、
やや拍子抜けでもあり、プログラムらしい結末でもあります。

ステージデータ設定に入ります。
ここからはゲームとしての「面白さ」を作る作業です。
素材を揃え

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

この2日間は「素材を終わらせる」と決めた日々だった

29日目・30日目は、2日間まとめての記録になります。

この2日間のテーマは一言で言えば「素材の完走」です。

ユニットマップ画像・戦闘用スプライト・戦闘背景。
プログラムの実装は既に完了していて、あとは素材さえ揃えばDEMO版が出せる状態でした。
「ここを乗り越えれば見える」という感覚のまま、ひたすら画像作業を進めた2日間です。

結果的に、主要な素材がほぼ出揃いました。
いよいよDEMOリリースが、現実的な射程圏内に入ってきました。


■ ユニットマップ画像 全25種完了

ついに全車種が本素材に

前回(28日目)の時点で25種中14種が完了していたユニットマップ画像。
駆逐戦車・自走砲・野砲系が残っていました。

砲身系のユニットはピクセル変換で白飛びしやすく、手修正が多い車種です。
特に野砲は車輪・砲架・砲身と直線パーツが多いため、
Clip Studio Paintでの手引き直し作業が他の車種より多めになりました。

それでも1種1種、削れすぎたドットを復帰させ、はみ出しを削り、白飛びを直していくと
最終的に全25種が出揃いました。

加工フローは前回と同じです。

  1. AI生成元絵を2×2に拡大
  2. 濃い色バイアス強めで4ドット中最多色を採用(ドット感を強調)
  3. Clip Studio Paintで手修正
  4. 縦方向に引き延ばしてデフォルメ(マップ上での視認性向上)

「並べたときに一目で区別できる」ことを最優先にしたデフォルメは変わっていません。
野砲と自走砲が横並びになったときに、ちゃんと別の兵器に見える。それだけを意識しました。


■ 戦闘用スプライト 全25種アングル見直し完了

基準アングルを決めて全種を統一

戦闘画面で左右に並ぶ戦闘用スプライト(各ユニット左向き・右向きの2枚セット)。
こちらも25種すべてのアングル見直しが完了しました。

今回、基準となるアングルとして採用したのは UnitBattle_010(IV号戦車)です。
真横に近い弱俯瞰・サイドビューのアングルで、
砲身が水平に伸びて見え、車体側面のシルエットがはっきり出る構図です。

戦闘画面は左右対称に並べる構図なので、
側面シルエットの明確さが「映え」の決め手になります。
俯瞰が強くなるほど車体上面が見えすぎて、シルエットが潰れる傾向があります。

全25種をこの基準に合わせて見直した結果、
一部のユニット(自走砲・駆逐戦車系)で俯瞰角度のわずかなばらつきが残りました。
微妙な角度調整は相当難航したため、DEMO版では妥協する判断をしました。
正式版でのリテイク候補として記録しておきます。

また四号戦車H型(PZ-IV-K)については、
マップアイコン(UnitMap_010)との整合性を重視し、
俯瞰やや強めのアングルを採用しました。
マップ画像の上面図に近いシルエットと揃えることで、
同じ車両だと認識しやすくなります。


■ 戦闘背景 DEMO版完了

「全種別に用意する」から「使い回し前提で絞る」へ

当初、戦闘背景は地形種別ごとに全種類用意する想定でした。
しかし現実的に考えると、DEMOの4ステージに登場しない地形(雪原・水域・砂浜など)まで
対応するのは時間的にも効率的でもありません。

方針を切り替えました。

  • DEMOで使用する地形に絞る
  • ある程度の地形は共通背景で使い回す
  • 雪原・水域・砂浜等はDEMO対象外として未対応

結果、9種を新規制作・1種を既存と統合し、DEMO版の戦闘背景が完了しました。
残り2種はDEMO対象外の地形のため、正式版対応に先送りします。

「完璧を目指してリリースが遠のく」より「割り切ってDEMOを出す」。
個人開発における実用主義的な判断です。


■ X(旧Twitter)への初投稿

ネクタリスへのリスペクトを前面に出して発信

開発開始から30日目、ついにX(旧Twitter)への初投稿を実施しました。

本作「鋼鉄の交響曲」はNectaris(Military Madness)へのオマージュ作品です。
「あのゲームへの愛から作った」ということを、正直に、堂々と発信することにしました。

投稿文はこちらです。


⚙️ Day 28 of solo dev — Military Madness never left my head.
So I built my own tribute.

“Symphony of Steel” — hex strategy, turn-based tactics.
Title to mission complete, full playthrough in the video.

Free DEMO — April 2026
Steam release — 2026

スーパーゲ制デー


動画はタイトル画面からステージクリアまでの通しプレイ映像です。
実際のゲームプレイの流れをそのまま見せるのが、一番誠実なアピールだと思っています。

投稿に際して2026年現在のXのアルゴリズム事情も調べました。

  • タグは1個まで(複数タグは大幅なリーチ減)
  • 外部リンクは本文に入れない(無料アカウントはほぼゼロエンゲージメント)
  • 動画はXにネイティブアップロード(YouTubeリンクはNG)

フォロワー実数は現在90〜100人規模なので、初期インプレッションは限定的です。
ただ「種まき期間」として割り切り、継続的に発信していくつもりです。


■ 地形チップ 対応範囲を確定

DEMOに必要な14種に絞って進行中

地形チップについても方針を確定しました。
DEMOで登場する地形に絞り、14種を対応予定とします。
現在5/14が完了しています。

茂み・林・森林の3種については、遠目での視認性・シルエットの差別化を確認しました。
林と森林はズームアウト時にやや近く見えますが、
下部パネルに地形名が表示されるため、ゲーム上は問題ないと判断しています。


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

カテゴリ項目状況
素材地形チップ5/14完了、残9種
コンテンツステージデータ設定(4ステージ)0/4・地形チップ後に着手
コンテンツエンディングスクロールテキスト未対応
配布準備BOOTHヘッダー画像未対応
配布準備特定商取引法に基づく表示未対応(公開前に必須)

プログラム実装は全完了。主要素材もほぼ完了。
残件はコンテンツ設定と配布準備に集約されてきました。


執筆後記

2日間、ひたすら画像作業でした。
コードを書くわけでも、設計を考えるわけでもなく、
ドットを直して、アングルを確認して、背景を描いて。
地味と言えば地味ですが、こういう作業の積み重ねがゲームになっていく感覚があります。

戦闘背景を「絞って使い回す」と決めたのは、
自分の中でちょっとした転換点でした。
「全種揃えなきゃ」という完璧主義から、「DEMOに必要なものを出す」という現実主義へ。
個人開発は、この切り替えができるかどうかがリリースできるかどうかに直結すると思っています。

X投稿は正直、緊張しました。
「Military Madness never left my head. So I built my own.」
この一文に、作り始めた理由が全部詰まっている気がします。
反応がどうであれ、作ってきたものへの誇りは変わりません。

地形チップ残9種。ステージデータ設定4ステージ。
ゴールは見えています。

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

今日は「見やすさ・わかりやすさ」を追求する日

今日は実装面とグラフィック面、両方を進めた日になりました。

実装は主にUI操作性の向上です。
「今何が起きているのか」がプレイヤーに伝わるかどうか。
それを意識しながら、下部パネルの動作・カーソル追従・ユニットの視認性を整えていきました。

後半は素材作業に移り、ユニットのマップ画像を本格的にドット絵化する作業を進めました。
気づいたら25種中14種まで完了していました。


■ 下部パネル・グリッドカーソルの動作仕様を確定

「最後に表示した情報が張り付く」問題を解消した

これまで下部の情報パネルは、状況が変わっても最後に表示した情報がそのまま残る仕様でした。
戦闘中に敵ユニットの情報が表示されたままになったり、
敵ターンが終わっても敵の情報が残り続けたりと、情報の鮮度が保てていませんでした。

今回、以下の仕様として確定・実装しました。

状態下部パネルグリッドカーソル
カーソル移動中地形・ユニット情報を表示プレイヤー操作
戦闘中(プレイヤー攻撃)情報をクリア現位置固定
敵ターン・移動中行動中の敵ユニット情報を表示敵ユニットに追従
敵ターン・攻撃中情報をクリア敵ユニット位置固定
戦闘終了後カーソル位置の情報に戻す元の挙動に戻す

実装上はシンプルで、戦闘開始時にClearInfoAll()を呼び、
終了後にOnCursorMove()でカーソル位置の情報を再取得するだけです。
プレイヤーターン側はCursorManager.cs、敵ターン側はTurnManager.csEnemyRoutine()内でそれぞれ対応しています。


■ 敵ターン中のカーソル・カメラ追従

「敵がどこに移動したか見えない」問題を解消した

これまで敵ターン中、グリッドカーソルはプレイヤーが最後に置いた位置に固定されたままでした。
敵ユニットにカメラが追従しても、カーソルだけが別の場所に残るため、
ズームインしているときに「敵がどこに消えたのか」わからなくなることがありました。

今回の対応は2点です。

① 行動開始時にカーソルを敵ユニット位置へ移動

FocusCameraOn()でカメラを追従させた直後に、
CursorManager.ForceMoveCursorTo()でカーソルも同じ座標へ飛ばします。
これでカーソルと情報パネルが常に行動中の敵ユニットを指すようになりました。

② 移動完了時にカメラを移動先へ再フォーカス

移動アニメーション中のリアルタイム追従は対応コストが高いため、
移動完了(while (e.State == UnitState.Moving) yield return null;の直後)に
もう一度FocusCameraOn()を呼ぶ方式にしました。

移動アニメーション中は見えなくても、完了時点で正しい場所にカメラが飛ぶことで
プレイヤーの混乱を防ぐことができます。ズームインしているときの体験が大幅に改善しました。


■ ユニット選択時の視認性向上

「自分が何を選んでいるか」が一目でわかるようになった

移動範囲ハイライトが選択ユニット自身のマスに重なるため、
「どのユニットを選んでいるか」が視覚的にわかりにくい問題がありました。

2点の改善を行いました。

① 選択ユニット自身のマスをハイライト除外

reachableからShowMoveRange()に渡す際、
moveHighlightというコピーを作成し、そこからユニット自身の座標をRemove()して渡します。
reachable自体は経路探索・攻撃範囲計算に使うため、元のSetは変更しません。
味方選択時・敵ホバー時の両方に適用しています。

② 点滅フラッシュ演出

選択中・ホバー中のユニットが元の色と指定色の間でグラデーション点滅するようになりました。

UnitControllerStartFlash()StopFlash()を追加し、
コルーチンでMathf.Sin()を使ったなめらかな色補間を実装しています。

private IEnumerator FlashRoutine()
{
    Color origin = (State == UnitState.ActionWait) ? actionWaitColor :
                   (State == UnitState.Done) ? doneColorMultiplier : baseColor;
    while (true)
    {
        float t = (Mathf.Sin(Time.time * flashSpeed * Mathf.PI) + 1f) * 0.5f;
        if (spriteRenderer != null)
            spriteRenderer.color = Color.Lerp(origin, flashColor, t);
        yield return null;
    }
}

flashColorflashSpeedはInspectorで調整可能です。
flashSpeedの数値が小さいとゆっくり、大きいとチカチカした点滅になります。

既存のUpdateUnitAppearance()spriteRenderer.colorを上書きする設計だったため、
_isFlashingフラグを追加してフラッシュ中は色の上書きをスキップする処理も加えています。

実装後の画面です。選択・ホバー対象のユニットが光っているので一目でわかります。


■ ユニットマップ画像の本素材化(14/25種完了)

AIで用意した仮素材をドット絵風に全面改修

これまでのユニットマップ画像はAI画像生成で用意した仮素材でした。
描き込みの細かさや粒度にばらつきがあり、ゲーム画面上での統一感に欠けていたので、
全25種を本格的にドット絵スタイルへ改修する作業を開始しました。

加工フロー

  1. AI生成元絵を2×2に拡大
  2. 濃い色バイアスを強めにして4ドット中の最多色を採用(ドット感を強調)
  3. Clip Studio Paintで手修正(削れすぎたドットの復帰・はみ出し削除・白飛び修正)
  4. 縦方向に引き延ばしてデフォルメ(マップ上の視認性向上)

戦車・砲身系は直線部分がピクセル変換で白飛びしやすく、手修正が多めになりましたが、
ティガーⅠとティガーⅡはフォルムの差をしっかりつけることができました。
「並べた時に一目で区別できる」ことを優先したデフォルメを意識しています。

本日は25種中14種が完了。残り11種は駆逐戦車・自走砲・野砲系です。
少しズングリしたフォルムになってドット感強めに調整しました。


■ シーン完成状況

シーン状況
タイトル✅ 完成
ブリーフィング✅ 完成
戦術(メインゲームプレイ)🔧 素材対応継続中
結果✅ 完成
エンディング✅ ほぼ完成

執筆後記
今日は「実装のための実装」ではなく、「プレイヤーが感じる体験」を起点にした改善が多かったです。
下部パネルの情報張り付き、カーソルが迷子になる問題、選択ユニットの見づらさ。
どれも「動いてはいるけど、なんかおかしい」という感覚から始まった改善です。

特にズームイン時に敵の移動先が見えなくなる問題は、自分がテストプレイして地味にストレスを感じていた箇所でした。移動完了時にカメラを飛ばすだけで体験がここまで変わるというのは、改めて「カメラ演出の重要性」を実感しました。

素材作業はひたすら地道です。戦車の砲身が白飛びするたびに手で引き直す作業を繰り返しています。
でもティガーⅠとⅡが並んだ時に「あ、ちゃんと違う車両に見える」となった瞬間は素直に嬉しかったです。
残り11種、明日には完走したいところです。

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

今日は「戦闘の深み」を追求する日

今日は実装量が多かった。
ユニットの詳細表示拡充から始まり、戦闘バランス調整、そして経験値システムの設計・実装まで。
気づいたら夜になっていました。

「敵ユニットをクリックしたら詳細が見たい」「育てたユニットが強くなる実感が欲しい」
プレイヤーとして当然感じる欲求を、ひとつひとつ形にしていく日でした。


■ ユニット詳細表示の拡充

敵ユニットも、自ユニットも、クリックで詳細が見えるようになった

これまで詳細ウィンドウはユニットリストウィンドウ経由でしか開けませんでした。
マップ上のユニットを直接クリックして確認する手段がなかったのです。

本日、以下の2パターンを追加しました。

  • 敵ユニットを左クリック → 詳細ウィンドウを表示
  • 味方ユニット選択中(移動範囲表示中)に自ユニットを左クリック → 詳細ウィンドウを表示

閉じ方は閉じるボタンか右クリックです。

実装上の課題として、右クリックによる閉じる処理の競合がありました。
UnitDetailWindowManagerCursorManagerの両方が右クリックを監視していたため、
「ウィンドウを閉じた直後に未行動ユニットへのフォーカスが発火する」という現象が起きました。

解決策は右クリック処理の一本化です。
CursorManager.Update()の冒頭で詳細ウィンドウの開放を確認し、
開いていれば閉じてそのままreturnする構造にしました。
右クリックの監視は一箇所に限る、という昨日の教訓をまた活かすことになりました。


■ 戦闘バランス調整

射程と機体サイズが命中率に影響するようになった

テストプレイ中に「攻撃側支援あり・防御側包囲済みの圧倒的優勢なのに攻撃側の方が被害が大きい」という
理不尽な結果が出ることがありました。乱数の振れ幅が大きすぎた問題もありましたが、
今回は以下の2つの補正を追加しました。

射程距離による命中下方補正

  • 距離1〜3:補正なし
  • 距離4:-5%
  • 距離5:-10%
  • 距離6:-15%
  • 距離7:-20%
  • 距離8以上:-25%(下限)

長距離砲が万能にならないよう、距離に応じた命中ペナルティを設けました。
最初は10%刻みで実装しましたが、長距離ユニットが全然撃破できなくなったので5%刻みに調整しています。

ユニットサイズによる回避補正

  • サイズ5(最大):補正なし
  • サイズ4:相手命中率-5%
  • サイズ3:相手命中率-10%
  • サイズ2:相手命中率-15%
  • サイズ1(最小):相手命中率-20%

小型ユニットは当てにくい。シンプルですが戦術の幅が広がります。
歩兵や偵察車両の生存性が上がりました。


■ 経験値システムの実装

戦い続けたユニットが強くなる

今回最も大きな実装です。
ネクタリスオマージュとして戦術的深度を高めるため、経験値システムを設計・実装しました。

基本仕様

  • 経験値範囲:0〜20(ステージ開始時は全員0)
  • 攻撃力・防御力が経験値1につき5%向上(最大で基礎値の2倍)

取得ルール

  • 攻撃側:ダメージを与えたら1、撃破したら2
  • 防御側:攻撃されたら1(距離・ダメージ問わず確定)、反撃で撃破したら2

防御側は「攻撃されるだけで経験になる」設計です。
遠距離から一方的に撃たれ続けるユニットが経験値ゼロのままというのは理不尽なので、
攻撃された時点で1獲得するルールにしました。

設計上のポイント

経験値の計算はCalculateCombat()内で戦闘結果と同時に確定させています。
HPと同じく「戦闘前の値」と「戦闘後の値」をCombatResultに格納し、
実際の付与はApplyExp()で行う設計です。

これにより戦闘画面が開いている時点で「この戦闘後の経験値がいくつになるか」がわかっており、
演出タイミングを自由に制御できます。

表示箇所

経験値は勲章画像で表現しています。味方は青、敵は赤のバナーデザインで、
0〜20の21段階、敵味方合わせて42枚の画像を用意しました。
表示箇所は戦闘画面・詳細ウィンドウ・下部パネルの3箇所です。

画像の管理はExpSpriteDataというScriptableObjectに一元化しています。
3箇所で使うたびに42枚をアサインするのは苦行なので、1つのアセットを共有参照する形にしました。

経験値の画像です。星の数と大きさで段階を表現しています。
ここまで育てるには相当な激戦をくぐり抜ける必要があります。実際のプレイでそうそう見られる段階ではないですが、
育てたプレイヤーへのご褒美として用意しました。

以下のように戦闘画面では表示されます。


■ 戦闘画面の数値精度向上

経験値による能力向上が正確に反映されるようになった

経験値システムの実装に伴い、攻撃力・防御力の内部型をintからfloatに変更しました。

経験値1、基礎ATK30のユニットの攻撃力は30 × 1.05 = 31.5です。
これをintで持つと32に丸められ、HP10のユニットの戦闘画面表示は320になります。
正しくは315のはずです。

計算過程は全てfloatで保持し、表示時のみMathf.RoundToInt()で整数化する設計に統一しました。
地味な修正ですが、数値表示の精度はゲームの信頼感に直結します。


■ その他・UI整理

ConfirmDialog(確認ダイアログ)をSystemWindowCanvas配下から独立したCanvasに移動しました。
Sort Orderを50に設定し、どの画面が開いていても最前面に表示されるよう整理しています。
あわせて全CanvasのSort Orderを整理し、描画順序の競合を解消しました。


■ シーン完成状況

シーン状況
タイトル✅ 完成
ブリーフィング✅ 完成
戦術(メインゲームプレイ)🔧 実装中
結果✅ 完成
エンディング✅ ほぼ完成

執筆後記
今日は実装量が多かったです。特に経験値システムは設計から始めたので時間がかかりました。
「戦闘結果をCombatResultで一元管理する」という既存の設計思想を経験値にも適用できたのは良かったです。HPと同じパターンで実装できると、コードの一貫性が保てます。

苦労したのは戦闘演出のタイミング制御です。「経験値付与」「画面更新」「撃破演出」の順序が噛み合わず、戦闘画面が閉じた後に経験値が更新されたり、撃破演出と戦闘画面が重複したりと、しばらく格闘しました。
最終的にIsPlayingをfalseにするタイミングを調整し、Coroutineで適切に待機を挟むことで解決しています。

デモ版リリースまで残りタスクは着実に減っています。素材制作が本丸ですが、実装面はだいぶ形になってきました。

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

今日は「操作していて気持ちいい」を追求する日

午前中は、美容院へ行ってきました。
そろそろヘアドネーションできるくらいに髪が伸びまくってます(笑)
色入れてポニテにして帰宅してからの作業となるので午後から開発再開。

今日は戦術シーンの操作性向上を中心に、UI改善・敵AI調整・バグ修正と、 地味だけど確実にゲームの完成度を上げるタスクを集中的に片付けました。

派手な新機能ではないですが、「これがないと遊びにくい」という部分です。 実際に触ってみると操作感が全然違う。こういう積み重ねがゲームの質を決めると思っています。


■ 敵AI行動順の改善

移動力が高いユニットが先に動くようになった

これまで敵ユニットの行動順は移動力の低い順(昇順)でした。 鈍重なユニットが先に動いてしまい、後から高機動ユニットが動こうとしても 道が塞がれている、という状況が発生していました。

本日、行動順を以下のルールに変更しました。

  1. 行動優先度(aiPriority)の高い順
  2. 移動力の高い順
  3. ステージデータのリスト順(SpawnIndex順)

これにより高機動ユニットが先に展開して道を空けてから、 鈍重なユニットが続く、という自然な動きになりました。

StageDataEnemySpawnInfoaiPriorityフィールドを追加したので、 ステージデザイン時に特定のユニットを優先的に動かす制御もできます。 デフォルト値は0で既存ステージへの影響はありません。

基本的に0にして特に先に動かしたいといった戦術的な意味が出た時に使用する予定。


■ ユニット表示順の統一

リスト順・巡回順・表示順がすべて一致するようになった

これまでユニットリストウィンドウの表示順はモデル番号順でした。 後述する右クリックフォーカス巡回を実装するにあたり、 「ステージデータのリスト順」と「ユニットリスト表示順」が一致していないと 直感的に使いにくいと判断して統一しました。

敵・味方ともに生成時にSpawnIndexを連番付与するようにして、 ユニットリストウィンドウの並び順もSpawnIndex順に変更しています。

結果として以下の3つが完全に一致するようになりました。

  • ステージデータ(Inspector)のリスト順
  • ユニットリストウィンドウの表示順
  • 右クリックフォーカスの巡回順

■ 右クリックで未行動ユニットへフォーカス

ユニットを探し回らなくてよくなった

ターン制SLGで地味にストレスなのが、「あれ、まだ動いてないユニットどこだっけ」です。 マップをスクロールして探すのは手間です。

本日、右クリックの短押しで未行動ユニットへ自動フォーカスする機能を実装しました。

仕様は以下の通りです。

  • 短押し判定:押下から0.2秒以内、かつマウス移動量5px以下
  • 初回:現在のカメラ位置に最も近い未行動ユニットへ
  • 2回目以降:SpawnIndex順に巡回(末尾まで行ったら先頭に戻る)
  • 左クリックするとインデックスがリセットされ、次の右クリックで近いユニットから再スタート

カメラ移動は瞬間移動にしています。 なめらかなスクロール移動は敵AIの行動確認には便利ですが、 自分でユニットを探す際はテンポが悪い。用途で使い分けています。

また画面内に十分収まっているユニットへのフォーカスはカメラを動かさず、 グリッドカーソルだけを飛ばす仕様にしました。 マップ表示エリアの10%マージン内に収まっていればカメラ移動なしです。


■ 右クリックでターン終了(確認ダイアログ)

全ユニット行動済みなら右クリックでターンを終える

右クリックフォーカスの自然な拡張として、 未行動ユニットがゼロになった状態で右クリックするとターン終了確認ダイアログが表示されるようにしました。

「巡回するユニットがなくなった=全員行動済み=ターン終了の意思」という流れが 右クリックだけで完結します。

あわせてターン終了ボタンも確認ダイアログを経由するように変更しました。 未行動ユニットの有無でメッセージが分岐します。

  • 未行動ユニットあり:「未行動のユニットがいます。ターンを終了しますか?」
  • 未行動ユニットなし:「ターンを終了しますか?」

テスト中に「うっかりターン終了ボタンを押してしまう」ことが何度かあったので、 この確認ステップは実用上かなり助かります。 3言語対応済みです。

とりあえず英語版です。


■ 敵ユニットホバーで移動・攻撃範囲表示

敵の脅威範囲が一目でわかるようになった

敵ユニットにマウスを0.3秒ホバーすると、移動範囲と攻撃範囲がハイライト表示される機能を実装しました。

表示内容はユニットの特性によって変わります。

  • 移動後攻撃可能なユニット(戦車・装甲車など):移動範囲(青)+移動範囲外の攻撃範囲(赤)
  • 移動後攻撃不可のユニット(野砲・自走砲・駆逐戦車など):現在地からの攻撃範囲(赤)+移動範囲(青)

野砲など射程の長いユニットの脅威範囲は広く、 「ここに入ると即攻撃される」という判断をプレイヤーが事前にできるようになりました。 特に高機動・長射程ユニットの把握が格段に楽になっています。

0.3秒の遅延を入れているのはカーソルを動かすたびに表示が切り替わる 「うるさい」状態を避けるためです。

これないと高機動ユニットや長距離砲の範囲がわかりにくいので慌てて実装という感じです。詰将棋的なマップをいずれ作る予定なのでちまちまマス目数えてらんないかなと。


■ ズームボタン・倍率表示のデザイン更新

長年の「芋ボタン」がついに卒業

ずっと仮置きのプレーンなボタンだったズームボタンと倍率表示をデザインしました。

「+」「-」ボタンはメタル感のある画像に差し替え、 倍率表示は7セグメント風のデジタルフォントスタイルに変更しています。 サイドパネルの世界観と統一感が出ました。


■ グリッドカーソル消失バグの修正

地味だけど気になっていた問題が解消

ランダム配置される特定の地形チップ上でグリッドカーソルが見えなくなる現象がありました。 条件が不定で再現性が低く、ずっと原因不明でした。

調査した結果、GridCursorObjectのレイヤー順序が0になっており、 特定のタイルチップの下に隠れてしまっていたことが原因でした。

レイヤー順序を0から4に変更して解消しています。 ユニット(1〜3)より前面、UIウィンドウ(4〜10)と同レベルに設定しました。


また動画を作成したのでここで公開しておきます。
前回からブリーフィングや結果画面など強化されているので是非ご覧ください。

■ シーン完成状況

シーン状況
タイトル✅ 完成
ブリーフィング✅ 完成
戦術(メインゲームプレイ)🔧 実装中
結果✅ 完成
エンディング✅ ほぼ完成

執筆後記
今日は地味な日でした。でも地味な改善が一番大事だと思っています。
特に右クリックフォーカス→巡回→ターン終了という一連の流れが繋がったのは大きいです。 キーボードに手を伸ばさず、右クリックだけでターン管理ができる。 操作の流れがスムーズになると、ゲームに集中できます。
実装中に「右クリック処理を複数のスクリプトで監視してはいけない」という教訓を得ました。 CameraControllerCursorManagerの両方が右クリックを監視していたせいで、 しばらくバグに苦しめられました。入力の一元管理は徹底します。
また本日Xの青バッジを取得しました。 今後は開発進捗の発信も積極的にやっていきます。 完成度が上がってきたので、プレイ動画などもそろそろ出せるかなと思っています。

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

今日は「ゲームとしての完成度」を上げる日

今日は戦術シーンを中心に、演出・AI改善・ヘルプ機能・エディタツールと、 幅広いタスクを一気に片付けました。
数をこなした日というより、それぞれが「ゲームとしての完成度」に直結する実装ばかりで、 やりごたえのある一日でした。


■ ミッション結果演出の実装

バナーがバーンと出てくる

これまでステージ終了時は、演出も何もなくそのまま結果シーンに飛んでいました。 いわゆる「シュール」な遷移です。
さすがにこれはまずいと思い、本日ようやく手を入れました。

実装したのは4種類のバナー演出です。

  • 敵全滅 → MISSION COMPLETE
  • 敵拠点占領 → BASE CAPTURED
  • 味方全滅 → MISSION FAILED
  • 味方拠点奪取 → BASE LOST

バナーは大きいスケールからEaseOutQuadで縮みながらフェードインします。 勝利時はファンファーレSE、敗北時は重厚なSEが鳴り、 2.5秒ほど余韻を残してから結果シーンへ遷移します。

BASE LOSTの髑髏バナーはなかなか気に入っています。 プレイヤーへのプレッシャーとして十分機能してくれそうです。

実装上の工夫として、GameOverReason enumを新設して終了理由を管理しています。 CheckGameOver()からDelayedEndGame()に理由を渡すことで、 どのバナーを出すかを正確に制御できます。

CanvasはPhaseCanvasと独立したMissionClearCanvasを新規作成しました。 PhaseDisplayManagerがPhaseCanvasのCanvasGroupをalpha=0にする処理があるため、 同じCanvasに乗せると一緒に消えてしまうことが判明したためです。 Canvasを独立させるという判断は、今後も使えるパターンだと思います。

出来上がりはこんな感じ。


■ エンディングシーン強化

スタッフロールが「ちゃんと動く」ようになった

昨日仮実装したエンディングシーンですが、 スクロールが途中で止まる、一瞬テキストが見える、といった問題がありました。
本日はこれを全部潰しました。

スクロール高さの取得にはendingText.preferredHeightを使用しています。 ContentSizeFitterの更新待ちによる高さ取得失敗を回避するための措置です。
初期の一瞬チラ見えはCanvasGroup.alpha = 0で対応しました。 SetActive(false)にするとレイアウト計算が止まってしまうため、 alphaだけ0にする方式が正解でした。

スクロール完了後はFinalViewがフェードインして表示されます。 THANK YOU背景画像にはHLSLシェーダーで周辺減光効果(ビネット)を実装しました。 上下は狭く、左右は広めに黒くフェードする設定です。

FinalViewのお知らせパネルにはデモ版である旨の告知と、 ブログ・X(旧Twitter)の宣伝を入れています。 Steamストアページは近日公開予定として記載しています。


■ ヘルプウィンドウの実装

ゲームのルールを説明する場所ができた

戦術シーンのヘルプウィンドウに、ついに中身が入りました。
デモ版でヘルプが空のままというのはさすがにまずいと思っていたので、 本日対応しました。

実装したセクションは6種類です。

  • 基本ルール(勝利・敗北条件・占領)
  • ユニットタイプ(歩兵・装甲車・戦車・駆逐戦車・自走砲・野砲)
  • ZOC(Zone of Control)
  • 戦闘効果(地形・支援・包囲)
  • 地形について
  • ステージ評価(C〜SSの5段階)

日本語・英語・中国語の3言語に対応しています。
テキストはHelpContentManagerスクリプトで言語判定して流し込む方式で、 GameSessionManager.SystemData.languageを参照しています。
設定画面で言語を切り替えると、次回ヘルプを開いたタイミングで自動的に反映されます。

ヘルプウィンドウ上でマウスホイールを操作するとマップのズームも動いてしまう問題があったので、 CameraControllerIsZoomLockedフラグを追加して対応しました。


■ 敵AI改善

渋滞が解消されて動きが自然になった

敵ユニットが通路で一列に並んで渋滞する問題を修正しました。

根本原因は経路探索の方式にありました。 従来は探索した経路のステップ数最小で経路を選んでいましたが、 地形コストを考慮した移動コスト最小の経路で選ぶGetPathMinCost()を新設しました。
直線距離ベースの選択は地形を無視して山に突っ込む副作用があったため、 A*で地形コストを正確に計算する方式としています。

また経路上の最遠マスに同陣営ユニットがいる場合のフォールバック処理も追加しました。 移動可能範囲内から目標への移動コストが最小のマスを探して移動します。 これにより渋滞を回避しつつ、適切な位置へ散開するようになりました。

あわせてStationaryパターンのバグも修正しました。 攻撃範囲にプレイヤーユニットが来ると移動してしまう挙動があったため、 移動実行前にStationaryチェックを追加しています。


■ 爆発エフェクトの3段階化

大きいユニットが派手に爆発するようになった

戦闘画面の爆発エフェクトとSEを、ユニットサイズに応じて3段階に分けました。

  • サイズ1 → Small(小爆発)
  • サイズ2〜3 → Medium(中爆発)
  • サイズ4〜5 → Large(大爆発)

UnitDataには以前からサイズ情報(unitSize、1〜5)を持たせていたので、 そこを参照して分岐するだけで済みました。
先行して設計しておいた恩恵が出た形です。

爆発画像はSmall・Medium・Largeの3種を新規作成しました。 Largeは大きなキノコ雲が立ち上がる迫力のある演出になっています。


■ マズルフラッシュ位置調整エディタツールの作成

ドラッグするだけで位置が決まる

マズルフラッシュの発生位置(muzzleOffset)の調整が、 これまでは数値を手入力して実行確認を繰り返す作業でした。
ユニット数が25種あることを考えると、かなりの手間です。

そこでUnityEditorの拡張ウィンドウとしてMuzzle Offset Editorを作成しました。

  • メニューの Tools → Muzzle Offset Editor で起動
  • ProjectウィンドウでUnitDataを選択すると自動で対象ユニットが切り替わる
  • プレビューエリア上でドラッグするだけでマズルフラッシュ位置を調整できる
  • 「保存」ボタンでUnitDataに書き込み(Undo対応)

スプライトのPixels Per Unit(100・200・300と混在)を自動補正しているため、 どのユニットでも正確な座標で設定できます。
実際に使ってみると、1ユニットあたり数秒で調整が完了します。 こういうツールを先に作っておくと後がずっと楽ですね。


■ その他の修正

  • 行動終了ユニットの色をDoneColorのみ適用に変更(チームカラーが出すぎていた)
  • タイトルシーンのアニメーション中にボタンが連打できてしまうバグを修正(CanvasGroup.blocksRaycasts制御)
  • HPテキストがユニットスプライトの裏に隠れる問題を修正(Order in Layer調整)
  • Pathfinding.cs・TurnManager.csのコードを整理(コメント日本語化・セクション分け)

■ シーン完成状況

シーン状況
タイトル✅ 完成
ブリーフィング✅ 完成
戦術(メインゲームプレイ)🔧 実装中
結果✅ 完成
エンディング✅ ほぼ完成

執筆後記
今日は本当に盛りだくさんな一日でした。
特に印象に残っているのはマズルフラッシュ位置調整ツールです。 「ちょっと作るのに時間かかるけど後が楽になる」という判断で作ったのですが、 実際に使ってみたら一発で「作って正解」と確信しました。
ツールに投資する判断ができるようになってきたのは、 個人開発の経験値が積み上がってきた証拠かもしれません。
敵AIの渋滞解消も地味ですが、マップを眺めていて気持ちよくなりました。 敵がちゃんと散開して攻めてくる。それだけでゲームの緊張感が全然違います。
デモ版完成まで残りのタスクを一つずつ潰していきます。

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

結果&ブリーフィングシーン演出完成

画面が「ゲームらしく」なってきた日

今日は演出強化に集中しました。
結果シーン・ブリーフィングシーンの両方をポリッシュして、それぞれ「完成」と言える状態まで持っていけました。
数値が勢いよくカウントアップされたり、要素が順番にスライドインしてきたり、
画面を見るたびに「これはゲームだ」という感覚が強くなっています。


■ 結果シーンの演出強化

カウントアップ演出の実装

これまで一瞬で表示されていた数値に、カウントアップ演出を追加しました。
ターン数 → 残ユニット数 → 残戦力値の順に順次カウントアップします。

工夫した点が一つあります。
ターン数やユニット数のカウント間隔は、実際の数値に比例して自動計算しています。
ターン数が5なら5回、ユニット数が3なら3回きっちりSEが鳴るイメージです。
一方、戦力値は桁が大きいので固定間隔でピロピロと鳴り続ける形にしました。
この使い分けが地味に効いています。

カウントアップにはSEも実装しました。
カウント中のピロ音と、完了時の確定音の2種類です。
SceneSEControllerのキー文字列で管理しているので、素材が揃ったらいつでも差し替えられます。

ランク画像のフェードイン演出

カウントアップが全部終わったタイミングで、ランク画像がドーンと登場します。
スケール大→等倍へ縮みながらフェードインするEaseOutQuadのアニメーションです。
テキストで「A」と出るより、ずっと達成感が出ますね。

勝敗表示のイメージ化

「MISSION COMPLETE」「MISSION FAILED」のテキスト表示を廃止して、
専用ラベル画像に切り替えました。
金属プレート風のデザインで、勝利時と敗北時で雰囲気が変わります。

完成した結果シーンはこんな感じです。

デバッグ機能の追加

戦闘結果データを得てからでないと動作確認できない、というのが地味に不便だったので、
ResultScene単体で再生したときに自動でダミーデータをセットする機能を追加しました。
#if UNITY_EDITOR で囲んでいるので、ビルド時には完全に消えます。
こういう小さな開発体験の改善が積み重なって効いてきます。


■ ブリーフィングシーンの演出強化

段階的登場演出の実装

これまで一瞬で全部表示されていたブリーフィング画面に、段階的な登場演出を追加しました。

  1. タイトル:上からスライドイン
  2. ステージイラスト:左からスライドイン → フェードイン
  3. ストーリーテキスト:右からスライドイン → フェードイン
  4. 戦力情報枠:フェードイン → カウントアップ
  5. ボタン類:出撃ボタンは右下から、戻るボタンは右上から斜めにスライドイン

左右から交互に入ってくる動きが、ちょっとした緊張感を演出しています。

戦力カウントアップ演出

ブリーフィング画面の戦力情報でもカウントアップを実装しました。
こちらは少し凝った仕様になっています。

敵味方を同時にカウントスタートして、戦力値に比例した時間でカウントが終わるという動きです。
つまり敵が強いステージほど、敵側の数字がなかなか止まらない。
「こいつら強いぞ…」という緊張感が自然と演出できます。
数字を調整してみたところ、初級ステージと最終ステージで
全然違う雰囲気になって良い感じです。

完成したブリーフィングシーンはこんな感じです。


■ バグ修正

Stage1のベストランクが表示されない

ステージ選択画面でStage1だけランクが「-」になるバグがありました。
原因はSystemSaveData.GetRank()内の判定ロジックです。

// 問題のあったコード
if (record.stageNum == 0) return "-";

FirstOrDefaultでレコードが見つからない場合、structのデフォルト値が返りstageNumが0になります。
ところがStage1のstageNumも0始まりで0なので、記録があっても「未記録」と判定されていました。
Stage2以降(stageNum 1〜)は影響なし、という実に分かりやすいインデックスのワナです。

// 修正後
if (!bestRecords.Exists(r => r.stageNum == stageNum)) return "-";

存在チェックを先に行う形に変更して解決しました。

ConfirmDialogがヒエラルキー非表示時に動作しない

編集中に邪魔なのでヒエラルキーでConfirmDialogプレハブを非表示にしておくと、
実行時にダイアログが表示されない問題がありました。
原因はプレハブのルートごと非アクティブにするとAwakeが呼ばれないため、
Instanceがnullのままになること。

解決策はシンプルで、ルートは常にアクティブにして、子オブジェクト(DialogContent)を非アクティブにする構成に変更しました。
他のパネル類が同じ構成で問題なく動いていたので、これに合わせた形です。


■ エンディングシーンの仮実装

結果・ブリーフィングが完成したので、エンディングシーンにも着手しました。
Animationによる仮実装を全面的にコルーチンスクロール方式に書き直しています。

エンドロールの内容はこんな構成を予定しています。

  • MISSION RESULTS:全ステージのベスト成績をセーブデータから自動取得
  • STAFF:制作者・BGM/SE提供元・AI活用(Claude/ChatGPT/Gemini)クレジット
  • SPECIAL THANKS
  • FIND US:ブログ・Steamページ等
  • Thank you for playing. ― FIN ―

スクロール完了後にタイトルへ戻るボタンが表示される仕様です。
デザインと内容の肉付けは後日行います。

AI活用についてクレジットに明記するのは、今の時代の誠実な作り方かなと思っています。


■ シーン完成状況

シーン状況
タイトル✅ 完成
ブリーフィング✅ 完成(本日)
戦術(メインゲームプレイ)🔧 実装中
結果✅ 完成(本日)
エンディング⚠️ 仮実装

執筆後記
今日は「演出を作る楽しさ」を久しぶりに味わえた気がします。
数値がカウントアップされる、要素が順番に登場する、
そういう小さな演出の積み重ねでゲームの「体験」が大きく変わりますね。
特にブリーフィングの戦力カウントアップは、
仕様を考えている段階から「絶対面白くなる」と確信していた部分で、
実際に動かしてみてその通りになったので満足しています。
残るは戦術シーンの仕上げとエンディングの肉付け。
デモ版完成まで、もうひと踏ん張りです。

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

ブログ整備と、多方面バグ修正祭り

今日はまたいつものペース(1日10時間以上)で開発再開です。
昨日は私用で半日作業だったので、その分、今日は盛りだくさんな一日になりました。


■ 本日の開発状況

1. ブログ・Web環境の整備

ゲーム本体の作業に入る前に、ブログ周りの整備を進めました。

サイドバープロフィール追加

開発ブログにプロフィール小窓を設置しました。
アイコン画像・名前・bio・Xフォローボタンをまとめたウィジェットです。
WordPressのカスタムHTMLウィジェットとCSSで実装しています。

実装中にちょっとしたトラブルがありました。
Xへのリンクを含むHTMLを保存しようとすると「保存された」とは出るのに
実際には反映されない、という現象が発生。
WAFかセキュリティプラグインを疑って調査しましたが、
最終的な原因は「X(エックス)」のUnicode文字でした。
サーバーのフィルターが不審なバイト列として検知していたようです。
テキストを「X でフォローする」に変えたら一発で解決しました(笑)

仕上がりはこんな感じです。

ステージ1のプレイ映像(3分36秒)を限定公開でアップしました。
ブログへの埋め込み用です。
デモ版リリースのタイミングで公開に切り替える予定です。


2. 結果シーンの改修

ステージ選択モード対応

ステージ選択でクリアした場合、「次のステージへ」ボタンを非表示にする対応を行いました。
ステージ選択はハイスコア更新専用の機能なので、そのまま次ステージへ進めてしまうのは仕様上おかしいためです。
GameSessionManager.CurrentModeの判定を1箇所追加するだけで済みました。

ランク画像の実装

評価ランク(C/B/A/S/SS)をテキストではなく画像で表示するように変更しました。
ミリタリー×スチームパンク調のランクバッジを新たに作成しています。
錆びた金属・歯車・月桂樹をモチーフにしたデザインで、ゲームの雰囲気に合わせました。

表示項目の追加

残ユニット数(終了時 / 開始時)と戦力(終了時 / 開始時)の表示を追加しました。
リザルト画面で何がわかるか、が増えると達成感も出てきますね。

多言語対応

「次のステージへ」「作戦終了」のボタンラベルが日本語固定になっていたので、
英語・中国語にも対応しました。
LocalizeText.SetDynamicText()を使う方式で統一しています。


3. 戦闘演算のバグ修正

地形効果の適用順序が誤っていた

地形防御ボーナスの計算順序にバグがありました。

誤った順序:(基本DEF + 支援DEF)× 地形倍率
正しい順序:(基本DEF × 地形倍率)+ 支援DEF

地形効果はユニット固有の能力値に対して乗算するものですが、
誤った実装では支援効果も含めた値に地形倍率が掛かっていました。
結果として地形効果の高い場所で支援ありで守ると防御力が過大になる問題が発生していました。

この修正はゲームロジック側(UnitController.cs)と戦闘演出側(BattleManager.cs)の
両方に適用しています。演出の数値表示も実際の計算と一致するように直しています。


4. 戦力計算式の統一

式がコード各所にバラバラに記述されていた

戦力計算式が複数のスクリプトに分散して記述されており、しかも式が統一されていませんでした。

  • BattleFieldEvaluatorHP × (ATK + DEF)
  • GameSessionManagermaxHP × ATK × DEF(← 誤り)
  • TurnManagerCurrentHP × ATK × DEF(← 誤り)

UnitController.GetBattlePower()という共通メソッドが既に存在していたので、
全箇所をこのメソッド経由に統一しました。
これでSITREPウィンドウの損耗率が開始直後から95%になっていた謎が解けました(笑)

どうも以前AIにコード生成を依頼した際に別の式が混入したようで、
発見が遅れましたが今回の整理で綺麗になりました。


5. ステージ評価基準の拡張

残ユニット数・損耗率をランク評価基準に追加

これまでSSランクの基準はターン数のみでしたが、
残ユニット数と損耗率も評価基準として追加しました。

StageDataの評価基準構造体に以下のフィールドを追加しています。

  • targetRemainingUnitsSS:SSランク基準残ユニット数
  • targetLossRateSS:SSランク基準損耗率

ランク算出は3項目の平均で決まる方式です。
ターン・損耗率・残ユニット数それぞれが評価され、総合的にランクが出ます。


6. 敵AI改善

渋滞で動けない敵ユニットの問題

複数の敵ユニットが同じ経路で移動しようとして、先行ユニットが詰まっていると
後続が移動できずその場に留まる問題がありました。

根本原因は「経路を1本探してその上を辿る」という実装で、
経路上が塞がれた場合の代替ルート探索がなかったことです。

FindApproachPath()にフォールバック処理を追加しました。
最短経路上を一歩も進めなかった場合、移動可能マスの中から
経路ゴールに最も近いマスを選んで移動する、という動作になっています。


■ 進捗メモと今後の課題

【現在の進捗状況】

  • ブログ整備: プロフィールウィジェット・Xリンク設置 ✅
  • プレイ動画: YouTube限定公開アップ済み ✅
  • 結果シーン: ランク画像・多言語対応・各種修正 ✅
  • 戦闘演算: 地形効果適用順序バグ修正 ✅
  • 戦力計算: GetBattlePower()に一本化 ✅
  • 敵AI: 渋滞時フォールバック追加 ✅
  • 次回予定: 動作確認、地形チップ作成継続、ブリーフィングシーンデザイン着手

執筆後記
今日は「バグ修正の日」でした。
地形効果の適用順序、戦力計算式の混在、SITREP損耗率95%問題と
立て続けに問題が出てきましたが、どれも原因が明確で気持ちよく直せました。
中でも戦力計算式の混入はAIコード生成の落とし穴で、
「動いてるように見えるけど計算が違う」という一番厄介なパターンです。
こういうバグを踏むたびに、ちゃんとコードを読む習慣の大切さを痛感します。
デモ版完成まであともう少し、引き続き頑張ります。

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

スタジオロゴ完成と、評価システムの設計見直し

今回はゲーム開発とは少し毛色の違い作業が多い1日でした。
午前中から夕方まで私用があり作業時間は限られていましたが、
やれることをやれるだけ、という感じで進めています。


■ 本日の開発状況

1. スタジオロゴ完成・起動演出を実装

スタジオのロゴを2種類作成し、ゲーム起動時に表示する演出を実装しました。

AtelierKSG
ヘルメットをかぶった黒猫が「KUSOGE」と書かれた箱から絵筆を振り回しているデザインです。
クソゲーを自称しながら作るスタイル、これが私の流儀です(笑)

スタジオ白猫斎(Studio Hakubyousai)
招き猫×筆×歯車を組み合わせたモノクロのロゴです。
「アート×エンジニアリング」をコンセプトにしています。

ゲーム起動時はこの2つのロゴが黒背景にフェードイン・フェードアウトで
順番に表示されてからタイトル画面へ遷移します。
実装自体はシンプルなコルーチンで、GameInitializer.cs に組み込んでいます。

以下はそのロゴ画像です。
開発元:スタジオ白猫斉、パブリッシャー:くそげ工房という感じで作りましたが、どちらも自分一人なので雰囲気だけ(笑)


2. Web・BOOTH環境の整備

デモ版のリリースに向けて配布環境の整備を進めました。
地味な作業ですが、リリース直前に慌てないよう早めに手を打っています。

atelier-ksg.com のSSL化

開発ブログのSSL証明書を設定し、https化が完了しました。
エックスサーバーの無料独自SSLを使用しています。
途中、WordPressのプラグイン障害で管理画面に入れなくなるトラブルが発生しましたが、
ファイルマネージャーから直接プラグインを無効化して復旧しています。
「保護されていない通信」が消えた時の安堵感はひとしおでした(笑)

BOOTHショップ準備

デモ版の無料配布先となるBOOTHショップを準備中です。
ショップ名は「白猫斎のくそげ工房」、URLは atelier-ksg.booth.pm になります。
商品ページの作成はデモ版完成後に行う予定です。

※尚、ショップURLは現時点でまだ非公開なのでアクセスできません。


3. リザルト評価システムの設計見直し

今日一番の技術的な作業です。

リザルト画面で損耗率が100%になったり0%になったりと
数値が不安定になる問題を抱えていたので、根本から設計を見直しました。

問題の原因

原因は2つありました。

1つ目は開始時データの取得タイミングです。
これまでセッション初期化時(ステージロード時)に開始時戦力を集計していましたが、
この時点ではまだユニットがシーンに配置されていないため、
値が0のまま計算に使われるケースがありました。

2つ目は「ランク」という評価結果をデータとして保持していたことです。
実数値とランクを別々に持つと両者がズレることがあり、
「たまたま正しく出る」「なぜか0%になる」という不安定な挙動の原因になっていました。

改善した設計

変更点内容
開始時データ取得タイミング1ターン目開始直前(TurnManager.Start())に変更
ランクの保持廃止実数値を保持→必要な時に都度計算する方式に変更
ユニット数の追加開始時・終了時の生存ユニット数を新たに記録
セーブデータの変更セーブスロット・システムデータも実数値ベースに統一

「データと表現を分離する」設計原則に立ち返った改修です。
ランクの計算式を後から変えたくなっても、実数値さえ持っていれば再計算できるので拡張性も上がっています。

実装の過程で StageResultstruct から class に変更する作業が発生し、
これに引きずられて複数のスクリプトで連鎖的にエラーが発生しました。
切り貼り修正で対応したところ余計こんがらがるという、よくある展開です(笑)
最終的にはファイルを丸ごと差し替える方針に切り替えて解決しています。


■ 進捗メモと今後の課題

【現在の進捗状況】

  • ロゴ演出: 起動時ロゴフェードイン/アウト実装 ✅
  • Web環境: atelier-ksg.com SSL化完了 ✅
  • リザルト評価: 実数値ベース設計に刷新 ✅
  • 次回予定: リザルトシーンの動作確認、操作性改善の実装

執筆後記
私用の都合で作業時間は実質半日程度でしたが、
懸案だった評価データの設計問題に手をつけられたのは収穫でした。
「たまたま正しく出る」バグが一番厄介で、
原因が静的フィールドの値が前回セッションから残り続けるせいだと
気づいた時は「なるほど」と膝を打ちました。
ゲームロジックの安定性は地味ですが、デモ版の品質を左右する重要な土台です。
引き続き頑張ります。