【RTS + カードゲーム】ゲーム制作日誌 #10
本日の進捗報告です。そこそこ動くモックができてきたので、そろそろサーバ側も書いていきたいと思います。サーバ側のフレームワークは何を使おうか検討中です。
- カードのドロー
とりあえず5秒ごとにデッキからカードを引くようにしました。(本当は30秒や1分などもっと間隔を空ける予定です)
カードがドローされるまでの時間は分かりやすくするためにプログレスバーが欲しくなりました。 - 手札の位置管理
カードのドローを行って手札にカードを加えた場合や、手札からカードをプレイして手札からカードがなくなった場合に、手札のカードの配置をアニメーションしながら左上に詰めるような処理を実装しました。こういったグリッドの処理はそこそこいろいろなところで使えそうな気がします。 - 戦力の表示
信長の野望シリーズのようにユニットの戦力を数値表示するようにしました。
Unity の処理としては、カードをプレイした時点でカードのオブジェクトを破棄し、その場所にユニットのオブジェクトをインスタンス化するようにしました。ユニットはアイコンの横に戦力をテキストとバーで表示するようにしました。ユニットが密集した場合に表示をどうするか悩ましいです……。
バーの色はプレイヤーごとに分けようかなと思います。色はゲーム開始前に選べるようにしたいですね。
- フィールドの座標管理
今までは Unity Inspector で適当にフィールドのオブジェクトの幅・高さを設定していましたが、厳密にサイズを定数で管理することにしました。当初はレスポンシブにフィールドのピクセルサイズを変更しようかと思っていましたが、固定サイズにすることにしました。
また、Model側でのみ使用するFieldの座標とUnityで扱う画面の座標の変換処理も実装しておきました。UnityEngine.Vector3 と System.Numerics.Vector3 の変換を書くのが若干面倒でした。
- 建物の配置
建物を配置できるようになりました。ひとまず本拠地としてプレイヤーごとに1つずつゲーム開始時に配置するようにしてあります。
本拠地用のイラストを用意しました。
カードはプレイした場合に丸いアイコンで表示していましたが、建物は四角いアイコンでフィールドに表示しようと思います。 - ユニットの移動
Unity非依存のフレーム管理処理を書きました。1フレームごとにフィールドに配置された行動可能なユニットをすべてチェックして、それぞれ行動を進めるようなロジックになっています。とりあえずの行動として、移動・攻撃のみ実装してあります。ユニットごとの行動はAOEシリーズのように行動が予約できるようにしてあります(移動の中継地点の設定など)。移動処理では目標地点・または目標ユニットを設定できるようにしました。現状だとユニットがぶつかったときに干渉しないので、同じ目標地点を指定した場合に重なってしまいます。解決策として、ユニットごとに他のユニットが入れないようにする占有領域を設定しようと思います。
ひとまずのテストとして、カードをプレイした場合に相手の BaseField (最上段)に移動し、次の行動として相手の本拠地に向かうように設定してみました。
落ち着いたら移動方向が変わったときにアイコンの向きを変えたりしたいと思います。
【RTS + カードゲーム】ゲーム制作日誌 #9
今日は開発を始めようと思ったら3日ほど前からシーンを保存していない状態で Unity が落ちていて焦りました……。自動保存の設定をしていなかったので仕方なく手動で復元しましたが、30分くらいで戻せたので不幸中の幸いでした。
本日の進捗です。マウスオーバーによるカードの詳細表示ができるようになったのと、手札からフィールドに出せるようになりました。若干でもアニメーションが付くと触り心地がとても良くなりますね。
- カードの詳細表示はとりあえずいったん左下に配置しています。マウスオーバーしてから詳細表示まで若干時間を空けることで画面がチカチカせず、良い感じに表示させることができました。
- カードを右下の手札領域からフィールドに配置できるようになりました。
手札からカードを掴んだ際は、カードを丸型のアイコン表示にアニメーション変化させるようにしました。画像を丸型に表示するのには Sprite Mask を使用していますが、Imageコンポーネントとの相性が悪かったのでカードの表示用コンポーネントは Sprite Renderer に変更しました。このコンポーネントの変更でマウスのドラッグイベントが思ったように取れなかったりと若干手こずりました……。結局、Sprite Renderer に加えてインタラクティブにした透明な Image コンポーネントを張っておくという暴挙に出ています。このあたりは落ち着いたら改善しようと思います。
また、ドラッグを開始したときに画像とマウスカーソルとの間隔が空いてしまうのも少し気になります。このあたりも要改善です。
【RTS + カードゲーム】ゲーム制作日誌 #8
本日の進捗です。UI の実装は時間がかかります…。
- マリガンを行った後に手札の位置へカードを移すようにしました。手札は2行×5列のグリッドに区切って、グリッドの位置の管理は自前で実装しました。(GridLayoutGroup だとやはり扱いにくいです)
- カードをドラッグしてフィールドにドロップする処理を書きました。
今後フィールドの座標の管理が若干面倒になっていく気がします。早いうちにロジックでのみ使用する座標とUnityでの座標の変換コードを書いておこうと思います。
ドロップしたカードはカード表示のまま行動させるのではなく、丸いアイコンにして行動させようと思います。イラストのどの位置をクリッピングするかはマスタで持たないといけないので要実装です。
また、カードへのマウスオーバー時にカードの詳細を表示する処理もそろそろ書いていきたいと思います。
【RTS + カードゲーム】ゲーム制作日誌 #7
本日の進捗報告です。マリガンができるようになりました。明日からはようやくインゲームのメインループの実装に入っていきたいと思います。
- デッキからカードを引く処理のアニメーションを追加しました。
手札のそれぞれのカードの位置決めは HorizontalLayoutGroup で行っていましたが、ちょっと扱いずらいので将来的に自前で実装しようと思いました。
現状デッキはすべて表向きの状態で置いていますが、あとで裏向きにしようと思います。 - マリガン処理を実装
いったん引いたカードをデッキに戻す → デッキをシャッフル → もう一度引く
という一連の流れを View に反映させようとしたところで若干実装に手こずりました。View側でのアニメーション開始直後ではModel側ではマリガンの一連の流れが全て終わっているので、どうやって View でデータの流れを保持しようかなと悩みました。そこでModel側でシャッフル時点でのデッキの並び順の情報を持つシャッフルイベントを発火するようにしました。デッキにカードを戻す・デッキから引く操作に関してはModel側のデッキのカードのリストの変化を Subscribe し、アニメーションTaskの待ち行列に Enqueue することで実現しました。
ただ、クライアント側でカードを引く前にデッキのカードの並び順を持たせたくないので、View側でのデッキのシャッフル処理は将来的に省く予定です。今はデバッグ用にデッキのカードを全表示しています。カードを引くタイミングでサーバから次のカードのインスタンスIDが送られてくる設計を想定しています。 - 新規イラスト作成
カードイラストが3枚だけではテストしていて味気なかったので、+3枚して6枚にしました。StableDiffusion で1000枚ほど生成して、3枚選びました。
最近まであまり StableDiffusion を使っていませんでしたが、ようやくプロンプトの指定にも慣れてきた気がします。ただやはり指の生成は苦手で、今日は最大で8本指になりました。近いうちに指だけ修正する方法を試してみたいと思います。
【RTS + カードゲーム】ゲーム制作日誌 #6
今日も対戦画面の実装を進めていました。カードのマリガン機能を実装する予定でしたが、ゲームのメインループの記述に入るまでで手一杯でした。設計にそこそこ時間をかけた甲斐もあり、いまのところの実装では Model と View が綺麗に分離できていて良い感じです。とりあえず直近の目標ではオフラインで動かす想定でいますが、将来的にModel側のロジックはクライアントに何も持たせずに完全にサーバで計算させる予定なので、それを意識した実装をしていきたいと思います。明日はUnity非依存のコードを中心に書いていこうと思います。今週中にデッキから引いたカードをプレイして、勝敗判定ができるまで進めたいです。
以下進捗です。
- そこそこソースの分量が多くなってきたのでUnityプロジェクトとその他設計ドキュメントを全てgit管理する設定をしました。
gitの設定をすると Visual Studio で差分行の表示をしてくれるのでありがたいです。規模が大きい開発になる想定だったので開発1日目からgit管理すれば良かったです。
そういえば エディタは Visual Studio 2022 を使っていますが、VSCode や Rider を使っても良かったかもしれません。Unity開発ではどちらも使ったことがありますが、最近 .NET の仕事をしすぎていてずっと Visual Studio ばかり使っていたせいか、何も考えずに Visual Studio を使うことになってしまいました。定期的にエディタの移行は検討していきたいです。 - AutoHotKey の見直しをしました。直近フォーカスしている作業でウィンドウのアクティブ化のキーバインドを変えるのですが、現在は以下のような設定になっています。Atl + Tab より5000兆倍速いです。
- 無変換キー + U: Unity
- 無変換キー + G: Google Chrome
- 無変換キー + V: Visual Studio
- ログ表示の仕組みの実装を行いました(左下)。Unity の LayoutGroup と ContentSizeFitter の設定が良く分からなくて若干時間が溶けてしまいました……。
ログの要件としては以下の3つが挙げられます。1. に対応するために、ゲーム中の時間管理の仕組みも実装しました。2. と 3. に対応するために、ログを Enum で分類することにしました。- 対戦の経過時間とメッセージを表示する
- ログの種類(カードプレイログ、イベントログなど)ごとに絞り込みできるようにする
- 重要なメッセージは色を変えられるようにする
- ゲームの状態管理を行う仕組みを取り入れました。
とりあえず以下の4状態を遷移するようにしました。こういう状態の命名は進行形にするかどうか迷います。- Starting
- Mulligan
- Playing
- End
【RTS + カードゲーム】ゲーム制作日誌 #5
今日から対戦画面の実装を始めました。が、今日は View と Model の分離方法についてモダンな考えを調べていたのと、Tween系ライブラリの最近の動向について調べていたら1日が終わっていました。結局 UniRx と DOTween を導入することにしました。
余談ですが、ライブラリの評判なんかを見ていると「最新技術は ChatGPT で聞いても答えが返ってこない」という意見が多数目に入りました。旧来は、「枯れた技術のほうがドキュメントが豊富」のように表現されていた事象が、最近だとこう表現されるようになってきているのでしょうね。
今日でプログラムのアーキテクチャ部分の方針は決まったので、明日からはゴリゴリ実装進めていきたいと思います。
【RTS + カードゲーム】ゲーム制作日誌 #4
今日から対戦画面を作り始めました。ひとまず大まかな方針が決まったので、明日は実装していきたいと思います。
- 対戦画面の画面構成を検討しました
表示したいものを挙げると以下のようになります
- ユニットを配置・行動させるためのマップ
旗取りゲームにしたいのでプレイヤーごとにフィールドを分割する
画面中央に固定表示・視点移動はしない
→ ミニマップは必要がない - 自分の手札(相手の手札は表示しない)
- 自分の資源情報・デッキ枚数
- ログ(カードプレイログ・戦闘ログ・行動ログ)
ログ表示は本作でこだわりたい - カード詳細表示領域
- ホットキー設定(キーグループ設定)
- ユニットの現在のアクション
- 実行可能なアクション一覧
- 経過時間(一定時間ごとにカードをドローするのを想定しているため、見やすさが非常に重要。プログレスバーをつける)
- ユニットを配置・行動させるためのマップ
- ひとまず上記を画面に突っ込むと以下のようになりました(Figma で作成)
右下の手札(Player Hand)の表示領域が狭すぎて大問題です。かといって、ほかにスペースもなさそうで困ってしまいました……。
同じ RTS + カードゲーム の VALIANT TACTICS ではどうなっているかというと……
やはり似たような位置に手札が表示されていますが、本当にこの大きさで大丈夫か心配になってきます。
カードゲームとRTSの融合を目指した意欲作「VALIANT TACTICS」プレイレポート。戦略と知識とスキルがぶつかり合う“ガチ”の対戦ゲーム
デュエルアリーナ や MTGA などのよくあるカードゲームでは画面下部をめいっぱい使って手札を表示できるのですが、手札よりマップが大事な RTS では画面下部を占有してしまうのがもったいなさすぎるので、どうしても手札の表示領域が小さくなってしまうのは仕方がないのでしょうね。
ただ、カードゲームの醍醐味として手の中からカードを出している感を出したいので、欲を言えばカードをプレイするときは手札が手前にあってほしいです。手に持っている手札を場に出すような操作感を実現したいです。
そこで、本作ではキーボード操作でこれを実現することにしました。以下はその流れです。
- マップを含めたゲームデザインを進めました。
マップには下図のようにベースフィールド(仮称)と3つの資源フィールド(仮称)があり、ベースフィールドでユニットの召喚などを行い、資源フィールドでそれぞれ資源を集めるようなデザインにします。
- 緑の資源フィールドでは木材が集まりやすいなど、フィールドごとに各種資源の生産ボーナスに調整を行います。
- デッキによってどの資源をたくさん消費するかが変わると、自分のどの資源フィールドを守らなければいけないか。相手のどの資源フィールドを押さえなければいけないかの判断が必要になります。
- ゲーム勝利条件として、相手のベースフィールドを攻め落としたら勝ちのルールにしようと思っています。フィールドを攻め落とす条件は、フィールドの重要拠点の建物が破壊されることとします。