UnityでRPGを作る時にスムーズにいきそうな作業順序を考えてみる
- 2024.12.08
- RPGチュートリアル
- Unity, ゲーム開発, チュートリアル
「UnityでRPG作りてぇ!」と別のページで必要な作業をリストアップしてまとめてみたのですが、UnityでRPGを作るにはたくさん作業が必要そうです。
そのため、数々の機能を自力で作っていく必要があるのですが、どんな順番で作業を進めていくとスムーズに進んで、かつモチベーションも尽きなそうか考えてみたいと思います。シンプルなRPGを作る過程をチュートリアルとしてこのブログにまとめる目論見で進めていて、そのチュートリアルの流れにもできそうなので頑張って考えます。
流れだけ考えれば良かったのですが、ついつい個別の項目について何をするかまで考えてしまったため、このページはとても長いです。
制作環境
MacBook Pro 2023 Apple M2 Max
Unity6 (6000.0.26f1) Silicon
Unityを使ってシンプルなRPGを作ってみたいと思います。
どこから手をつけよう……
UnityでRPGを作る時に「さぁUnityHubで新規プロジェクトを作ってエディタを開いたぞ!」と意気込んだはいいものの、いつもの空を眺めながら「どこから手をつけよう……」と悩むのはよくあることです。
なので、前回書いたメモを参考に、作業順序を考えてみます。方針としては、
- 素材の作り込みは後に回したい(モック版に必要なものだけ作る)
- データ編集用のエディタは完成後にしたい
- 移動する機能を先に作りたい
- 戦闘は時間かかりそうなので早めに着手したい
といった感じでしょうか。この方針を適度に踏まえつつ、作業順序を考えてみたいと思います。
前回のメモはこちら。
作りたいもの
超シンプルなRPGをUnityで作りたいと思っています。初期のドラクエのようなものを作りたいので、2Dで進めていきます。
RPGのストーリーとしては、勇者の旅立ちの前日譚みたいな感じで、村の少年が洞窟に住み着いたゴブリン一族を懲らしめて帰ってきたらお城に呼ばれて終わり、僕の戦いはこれからだ! くらいにしておきましょう。
必要なマップは、村、フィールド、洞窟、の3種類にしておきます。戦闘も複雑なものにはせず、1vs1のシンプルなバトルになるようにしたいと思います。アイテム類も回復アイテムと装備品くらい、お店は1軒、宿も自宅なので無料で泊まれるようにします。
これだけのシンプルなものにしても作業は多くなると思うので、追加したい機能、拡張したい機能については完成後に入れていきたいと思います。
チュートリアルとしてまとめることも考えているので、基本的にはアセット類やライブラリ類を使わずに自力実装で進めていきます。自力実装だなんて、自分でも無茶なことを言っているなーと思いますが、この過程が誰かの役に立って、将来的に面白いRPGを作ってもらえたら嬉しいです。
作業順序
大きな流れとしては、
- プロジェクトのセットアップ
- 移動用のマップの作成
- データ類の作成
- 戦闘に関する機能の作成
- イベント系の作成
- 全体の制御動作の作成
- 全体の動作確認
- パラメータ類の調整
- 素材の作り込み(グラフィック)
- 最終確認
になるかと思います。
そしてそれぞれ細分化してみると以下のようになります。
- プロジェクトのセットアップ
- プロジェクトの作成
- Universal RPの設定
- 解像度の設定
- 2D Pixel Perfectの設定
- フォントの設定(TextMesh Pro)
- 移動用のマップの作成
- 表示するマップ用画像の作成(モック版)
- UnityのTilemapでマップを作成
- 操作キャラクター用画像の作成(モック版)
- NPC用画像の作成(モック版)
- アニメーションの実装
- 移動の実装
- データ類の作成
- キャラクターのパラメータ設定
- 敵キャラクターのパラメータ設定
- アイテムデータの作成
- 装備品データの作成
- 魔法データの作成
- 戦闘に関する機能の作成
- 敵キャラクターの画像作成(モック版)
- 戦闘用UIの作成(モック版)
- ダメージ計算式の作成
- 戦闘の流れの動作を作成
- レベルアップ処理
- イベント系の作成
- 会話の処理
- お店の処理
- 宿屋の処理
- マップ移動の処理
- ゲーム内のフラグ管理の実装
- 宝箱の処理
- BGMや効果音の再生処理の実装
- 全体の制御動作の作成
- エンカウントの仕組みを実装
- メニュー画面の実装
- セーブ機能の実装
- タイトル画面の実装
- ゲームオーバー時の処理の実装
- 全体の動作確認
- パラメータ類の調整
- 素材の作り込み(グラフィック)
- ビルド
- 実機確認
ウボァー。
ざっくりとまとめてみましたが、本当に作業が多そうですね。チュートリアルにするとしても、結構な長期戦になりそうです。
前半では仮置きの素材を使って作業を進めていきます。この時、キャラクターの画像サイズやタイルの画像サイズについては決めておいて、後半の素材作り込みのフェーズで画像を差し替えるだけにできればと思います。
ビルドするタイミングは定期的に入れておくのが良いのですが、チュートリアルの流れを考えて後半に入れています。おそらくそこで見つかるエラーなどもあるかと思いますので、実機確認のフェーズで修正などを入れていきます。
やっていくうちに、この作業順序に載っていない作業なども発生するかと思います。その際は最終盤の「全体の動作確認」の部分で色々と直すことになるでしょう。ここはバッファとして想定しているため、高度な柔軟性を維持しつつ、臨機応変に対応していきましょう。
ここからは、それぞれの項目について詳細に考えていきます。
プロジェクトのセットアップ
まずはプロジェクトを作って設定を行なっていく部分です。今回は多少Unityを触っている人向けにチュートリアルを作ろうと思っているので、基礎的な部分はあまり触れないかもしれません。
プロジェクトの作成
まずはプロジェクトを作成します。使うのはUnity6で、Mac版の画面ショットを掲載していく想定です。作成時にはレンダーパイプラインとして「Universal RP」を選択予定です。これは画面の見た目だったり、エフェクト関係でメリットがあるので、チュートリアルの範囲が終わった後に拡張していく際、コンポーネントなどを使い回しやすくする狙いがあります。
実際にRPGを作る場合はリリースするプラットフォームに合わせてレンダーパイプラインを選んでいくとグッド。スマートフォン向けならUniversal RP、PC向けで3DのRPGを作るならHDRP、みたいな感じです。HDRPでRPG作るのは楽しそうですが、規模的に個人だと大変で複数人で作るのが良いかもしれません。
Universal RPの設定
Universal RPでプロジェクトを作るのでその設定を行います。といっても特にいじるところもなさそうですが、設定ファイルの中身を確認しておく感じにしましょう。
解像度の設定
ドット絵のゲームにしたいので、HD画質ではなく半分くらいにしておきたいと思います。縦横比は9:16を想定しています。ピクセルパーフェクトで表現するため、後述の「2D Pixel Perfect」を使用する予定です。
2D Pixel Perfectの設定
今回は2Dのドット絵系RPGを作りたいので、「2D Pixel Perfect」を使ってみます。通常、Unityで画像を表示する際、画像の表示位置はfloatで表現されます。このとき、位置によってはドット絵の一部が潰れてしまうこともあるため、「2D Pixel Perfect」を使って参照解像度として設定したピクセル単位でスナップするようにします。
「2D Pixel Perfect」に関しては以下のドキュメントもご参照ください。
フォントの設定(TextMesh Pro)
ゲーム内で使用するフォントをインポートして、TextMesh Pro用のフォントマテリアルを作成します。今回はお馴染みの「ピクセル・エムプラス」にしたいと思います。個人開発のスマホ向けゲームでよく見るファミコン風のフォントです。
まずはRPGを完成させるのが目的なので、フォントのサブセット化は行いません。サブセット化とは、フォントファイルに格納される文字を減らして容量を減らすことです。メッセージ表示の際に、うっかりサブセット化で省いた文字を使ったりするケースもあるので、RPGではサブセット化しない方が良いかも?
移動用のマップの作成
キャラクターを移動させるマップを用意します。近年のゲームだと、キャラクター自体を移動させずに目的地を選択して、そのマップの中で動き回る形式が多くなっている印象ですが、ここは初期ドラクエ風味を目指すのでキャラクターの足で各マップを移動させるようにします。
表示するマップ用画像の作成(モック版)
モック版として動作を確認できるレベルの画像を用意します。私はドット絵作成用ツールとして「Aseprite」を安い時期に買ったため、それを使って作りたいと思います。フリーソフトなら「EDGE」あたりが良いかもしれません。モック版なのでOS備え付けの「ペイント」的なツールでも良いかと思います。スマホで「dotpict」を使って指で描いてエクスポートして使う方法もあるので、使いやすい方法を選ぶのがグッド。
チュートリアルの中では超シンプルに描いたモック版を用意するつもりでいます(最低限タイルの違いを判別できるレベル)
なんなら漫画のネームのように、文字で「壁」「床」「入口」のように描いた画像でも良いかと思います。
UnityのTilemapでマップを作成
作ったモック版のタイル用画像を使ってTilemapで表示していきます。インポート時にスプライトを分割して、タイルとして設定していきます。
今回は32ピクセルをUnity世界の1に設定するため、インポート設定ではPixel Per Unitの値を32にします。使うドット絵の大きさに合わせて32や64と、はたまたレトロ風に16、といった感じで設定していくとグッド。昔RPGツクール2000でドット絵を作っていた時には1マスあたり16ピクセルだったことを考えると、1マスあたり32ピクセルは情報量的にかなり大きい印象があります(インターネット老人会)
操作キャラクター用画像の作成(モック版)
操作キャラクターに関してもモック版として作成していきます。キャラクターのサイズとしては、横はマップの1マスの幅と同じ、縦はマップの2マス分の高さと同じ、とするのがよくある方法です。これによってマップ上のオブジェクトとキャラクターの前後関係を表現しやすくなるため、より立体感が出てきます。
そう言いつつ、今回はキャラクターに関しても1マスに収まる範囲で作っていきたいので、古のRPGに則って、32*32のサイズで作成します。
NPC用画像の作成(モック版)
NPCに関しても同様に1マスに収まる範囲で作ります。長老、主人公の母親、アドバイスをくれる村人、ボスキャラあたりがあればモックとして動作を確認する上で足りそうです。
アニメーションの実装
キャラクターのアニメーションとして4方向*3パターンの歩行アニメーションを実装します。これも踏まえて操作キャラ、NPCの画像を作成します。ちゃんと作ろうとすると地味に時間がかかるので、モック版ではパターンの違いが分かる範囲で進めていきます。
この段階でUnity側のAnimatorの設定もある程度進められるかと思います。切り替えの条件に使う変数名や値についてもここで定義してしまいます。作業順としては、操作キャラクターのアニメーション設定、AnimationControllerOverrideで他のNPC用に設定を使い回す、という順番になりそうです。
移動の実装
簡易マップ上で操作キャラクターの移動処理を行います。今回、位置の移動はコルーチンで実装します。グリッド状のマップの中心に移動するように、Tilemap上の座標を取得して、TransformのPositionを設定する予定です。NPCの移動に関しては、一旦無しにしてその場で足踏みをさせるようにしたいと思います。(あれ、歩行アニメーションは正面だけでいいのでは……?)
移動できる場所の判定については、Colliderの有無で確認予定です。
データ類の作成
ゲーム内で使用するデータ類を作成していきます。一番妄想が捗る部分ですが、なるべく簡易に済ませたいと思います。なお、各種データはScriptableObjectで保持させるようにしたいと思います。
実際に作る場合はJSONなどで定義するのも良いかと思います。JSONUtilityならシリアライズの処理が入るため処理時間的に若干コストがありますが、MessagePack for C#などを使えば高速に処理できそうですね。
キャラクターのパラメータ設定
操作キャラクターのステータスに使用するパラメータを設定していきます。シンプルにいくので、レベルは1から10までとして、その間のパラメータを定義していきたいと思います。そのレベルに到達するのに必要な経験値などもここで定義していきます。
上述の通りScriptableObjectを使うので、クラスを作成して定義を作っていきましょう。
敵キャラクターのパラメータ設定
こちらも同様にScriptableObjectで定義を作成します。レベルアップによるパラメータ変動がない分、操作キャラよりは楽かもしれません。そう言いながらも、経験値やゴールドの設定など、味方キャラには存在しない項目もあったりして、敵キャラの数が多いと地獄を見るのはRPGツクールで経験済みです(1敗)
敵キャラの行動パターンについても定義を作っておくと良いかと思います。通常攻撃のみ、魔法や特技を使う、HPが50%を切ったらパターンが変わる、などです。行動の優先度などを設定しておいて、戦闘時に優先度の計算を行うことで最終的にどの行動を選択するのかを決めていきます。優先度は数字の大きい方が優先される、なんて感じが分かりやすいかと思います。複雑なRPGになると、ボスも複雑な行動パターンになることが多いので、条件に合致する行動が複数あるときにどれを選ぶのか、ユーザから見て一貫性があるとより良くなると思います。
また、ドロップするアイテムデータや使う魔法のデータなども必要になってきますが、これは対応するデータが揃ってから、敵キャラの定義に戻るのが良いかと思います。まずは敵キャラに必要なパラメータを定義して、アイテムや魔法が敵キャラに与える影響を考えてみて、その上でドロップするアイテムや魔法の定義を行なっていくのが良いかと思います。
そんなことを言いつつ、今回作るシンプルRPGでは敵キャラのアイテムドロップなどは実装しない想定です。完成後の拡張範囲として個別にやるかも……? と内心では思っています。手が回るかは別として。
アイテムデータの作成
こちらもScriptableObjectで実装します。アイテムとしては消耗品のポーションだけを実装していきます。大きな括りでは装備品もアイテムに含めて、アイテムのカテゴリで分けていくのが良いかと思います。
カテゴリ分けはEnumで定義しちゃいましょうか。int型で対応するIDを定義して……とやるとコード内で「3ってどのカテゴリだっけ?」となりがちなので、文字列で名前を判別できて、かつ値の範囲も決まっているEnumが扱いやすいかと思います。switch文の分岐にも使えて便利ですもんね。
今回は実装しませんが、アイテムに関しては、
- 戦闘中に使用できるもの
- 移動中に使用できるもの
といった感じでフラグを持たせておくのも便利です。例えばドラクエでは戦闘中に使用できる装備品などもあるため、戦闘時にアイテム欄を開いた時にフラグを見て使用可能かどうかを確認できます。
また、対応する魔法を作っておくことで、それを呼び出すのもよくありますね。ドラクエだったら、いかづちの杖を使ってベギラマと同じ効果、なんてアイテムがいくつかあります。
魔法を呼び出す際は、使用者のパラメータを参照するかどうかも検討しておくと良いかと思います。魔力の高いキャラが使ったら高威力になるパターンであればパラメータを参照しますし、誰が使っても同じ威力になるならパラメータを参照しない形で実装します。この点もアイテムの定義データに盛り込んでおくことで、戦闘中にどのダメージ計算式を使って算出するかを判断できます。
装備品データの作成
アイテムと同様です。カテゴリによる分類は、後で対応するメニュー画面の装備機能でも使います。
装備品は操作キャラクターのパラメータを補正するものなので、操作キャラクターのパラメータに対応します。そのため、先に操作キャラクターのパラメータを定義しておくと楽ちんですね。定義データ内では、増加するパラメータ、減少するパラメータなどを定義していきます。固定値で変動するか、割合で変動するか、ゲームによって選びたいものが変わるかと思いますので、定義データでもそれを表現しておくと良いかと思います。固定値か、割合か、といった点もEnumで選べるようにしても良いかもしれません。
今回は固定値で変動させたいので、各パラメータに対応する補正値のフィールドを用意します。
また、誰が装備できるかのリストも用意しておくとグッド。キャラクターのID、装備可否フラグを持たせるクラスを用意して、それをリストとして保持すると良いかと思います。ドラクエ3以外のようにキャラクターが固定ならキャラクターのIDをキーに、ドラクエ3のようにユーザ側でキャラクターを作成できるなら職業(クラス)のIDをキーにすると良いですね。
魔法データの作成
魔法もScriptableObjectで定義します。魔法のカテゴリもEnumで定義しておくと良いかと思います。
攻撃魔法、回復魔法、補助魔法など、枠組みを用意しておくと、開発中に理解しやすくなります。また、ゲーム内で魔法やスキルの並べ替えを行うことで、目的の魔法をすぐに見つけやすくするためにも便利です。
また、魔法の影響範囲も定義できるとグッド。味方ひとり、味方ランダム、味方全体、敵ひとり、敵ランダム、敵全体、といった感じでこれもEnumで用意しちゃっても良いかもしれません。敵にはダメージ、味方には回復、なんて感じで複合的な効果を表現したい場合は、魔法の定義で複数のカテゴリを保持できるようにしておくと良いかと思います。データとしてはListで保持して、ゲーム内ではListの順番に沿って処理していく仕組みを入れておくのが良いですね。
味方の使う魔法と、敵の使う魔法で威力を変えたい場合などは、それぞれ別データとして定義しておくと良いかと思います。例えば敵と味方でHPの上限値が異なっていると、同じ魔法を敵が使った時に非常に脅威になりバランスを取るのが難しくなったりします。
戦闘に関する機能の作成
定義データが揃ってきたら、RPGの重要部分である戦闘に関する機能を作っていきます。細かいバランス調整は後のフェーズで行うので、まずは必要な機能を入れていくようにしたいと思います。
敵キャラクターの画像作成(モック版)
敵キャラクター用の画像を作成します。今回のシンプルRPGでは戦闘中にアニメーションさせず、一枚絵で実装します。モック版では丸とか四角など、記号的な画像でも良いかと思います。敵とエンカウントした→敵が表示された、の動作を確認できる程度の画像があれば良いかと思います。
ゲーム全体を通して、敵キャラの画像サイズがどの程度になりそうか、この段階でざっくり決めておくと後の調整が楽になるかもしれません。これは敵キャラの画像サイズに応じてUIの配置なども変わってくるためです。最小だとこのくらいのサイズ、最大だとこのくらいのサイズ、といった部分を想定しておくとグッド。
戦闘用UIの作成(モック版)
敵キャラの画像サイズが見えてきたら、その他のUIについてもモック版を作成していきます。作り込みは最後に回して、画面内にどんなUIが配置されるかの洗い出しがメインになるかと思います。一部うろ覚えになってますが、昔のRPGで戦闘画面のUIがどこに表示されていたのかを思い出してみると、以下のようになっていたかと思います。
作品 | HP/MPなどの表示 | コマンド選択 | メッセージ |
ドラクエシリーズ | 画面上部 | 画面下部 | 画面下部 |
FFシリーズ | 画面下部 | 画面下部 | 初期は画面下部、SFC時代は画面上部 |
女神転生シリーズ | 画面下部 | 画面下部 | 画面下部 |
ウィザードリィシリーズ | 画面下部 | 画面下部 | 画面下部 |
メッセージ表示中にHPやMPを確認できるようにするなら、表示領域を分けておくとグッド。あるいは、味方や敵の行動時にメッセージ表示を消して、そのタイミングでのHP/MPを確認できるようにするのも良いかと思います。9の頃までのFFシリーズでは画面上部にメッセージを表示するケースが多かったかと思います。
今回はドラクエに倣ってHP/MPなどの表示を画面上部に、メッセージやコマンド選択を画面下部に表示していきます。
ダメージ計算式の作成
ダメージ計算式もこの段階で作成します。個別にクラスを作って、その中で判定用メソッドを作成していきます。戦闘中に毎回インスタンス化すると地味に負荷も上がっていくので、staticで作っちゃいましょう。
今回作成予定なのは、
- 攻撃時のダメージ計算
- 魔法やアイテムの回復量の計算
- 逃走成功率の計算
- 行動順の計算
です。他にも必要そうな項目があれば、この作業の際に追加していきます。流れを作成してみたり、全体を動かしてみて「あれも必要だ!」となるのはよくあることなので、ぐるぐるとサイクルを回していくのがグッド。事前に全部洗い出さなきゃ! となると着手が遅れた上にやっぱり必要なことが出てきたりするので、ざっと思いつく範囲で必要な仕組みを作れたら次に進んでいきましょう。
戦闘の流れの動作を作成
エンカウント、敵出現のメッセージ表示、コマンドの選択、敵味方の行動、次ターンのコマンド選択、あるいは勝敗の処理、といった一連の流れを作成していきます。主にコマンド選択の部分で動作を作っていくことになるかと思います。
コマンドの種類に関しては今回はEnumで定義します。戦闘中に各コマンドを選んだ際に、このEnumによって次の処理を判断していきます。
HPを減らしたタイミングでHPが0になった場合、勝利またはゲームオーバーの処理に分岐します。なので、メッセージを表示した後は味方、敵の状態を確認するフェーズを入れておきましょう。今回は導入しませんが、ステータス異常を実装するなら、行動後にHPを減らしたり、ターン終了後にHPを減らしたりと、敵や味方の行動以外にもHPが減る要因があるので、そちらも忘れずに入れておくとグッド。
モック版ではエフェクトを入れる場所だけメモしておいて、後で仕上げていくとスムーズに進んでいくかと思います。まずはアニメーションやエフェクトのない簡素なテキストだけの戦闘になりますが、流れを作っておけば後で味付けしていくのが中心になるのでモチベーション的にも維持しやすくなります。
レベルアップ処理
レベルアップ処理でまとめていますが、経験値やゴールドなど、敵に勝利したことで得られるものをまとめてユーザに伝えるフェーズも入れておきます。レベルアップ時に成長したパラメータを伝えたり、キャラクターがアニメーションで動いたりと、喜びを表現していくのがグッド。モック版では経験値やゴールドの入手数、レベルアップの情報をメッセージで表示します。
レベルアップ時に専用のUIを表示するなら、それに関してもこのタイミングで配置場所を決めておくと良いでしょう。
ゲームによっては敵キャラを倒した数だったり、戦闘の勝利/敗北数を記録していることもあります。もし実績として使いたかったり、ゲーム内情報として表示したい場合は記録しておくと良いかと思います。
イベント系の作成
キャラクターを移動させているパートにて発生する、NPCとの会話やお店の処理などを総称して、RPGツクールに倣ってイベントと呼ぶようにしましょう。ボス戦などでは戦闘中にもイベントを発生させたりすることがありますが、今回は実装の範囲外とします。
イベントの開始は基本的に決定ボタンで話しかけた時に発生させます。他にも、あるマップに入ったら自動的に発生するなど、発生条件の仕組みを用意しておくと表現できることの幅が広がります。
イベントの起点は共通のクラスで行い、どのイベントを発生させるのかはEnumなどでカテゴリーを定義しておいて、対応するクラスを呼び出す形にしたいと思います。今回はシンプルなRPGを目指すのでゴリ押し的に作っていきますが、規模が大きくなりそうならイベントを簡単に設定できるエディタなどを作ると後の作業が楽になります。複数人で作っているなら、コードを書かない人でもエディタを使ってイベントを作れるようにすると効率も上がります。
会話の処理
RPGではとても多く目にする会話の処理。画面上に表示するUIや、テキスト送りの処理、文字サイズなど、ゲームをプレイする上で快適に遊べるように調整しておくと良いかと思います。
会話中にYes/Noのようにユーザが意思表示できるような仕組みも入れておくとグッド。文章内で表示する場合は、選択肢を表示する命令をテキスト内に入れておくのもひとつの方法です。[$select]のように、ゲーム内の文章としては表示しないであろう記号を使ってタグにして、メッセージ表示機能の中で判別して対応する処理を行なっていきます。
今回はシンプルにいくのでタグの数もそこまで多くないはず……(白目)
お店の処理
RPGで大切なお店の処理です。お店で販売しているアイテムの一覧などは、ScriptableObjectなどで定義しておくと良いかと思います。お店IDなどで品揃えデータを特定して読み込むことで、場所によって異なる品揃えを表現することができます。
お店に関してもUIが必要で、今回はシーン内に配置しておいて、必要なタイミングで表示するようにしたいと思います。お店では表示する情報も多いので、テキストやアイコンなどをうまく配置しましょう。
宿屋の処理
全回復するいわゆる宿屋の処理を作成します。こちらはメッセージ表示と選択肢の表示があれば追加のUI作成は要らなそうです。ゲーム的には金額を判定する処理なども入れたほうが良いのですが、今回は主人公の自宅で泊まる形にするので無料で回復させます。
マップ移動の処理
村、フィールド、洞窟のマップ間を移動させる処理を作成します。移動元のマスに関しては、Colliderを使って判定したいと思います。衝突させるのではなく、トリガーの用途ですね。移動が発生するマスへの移動が完了したら、Triggerによる呼び出しがあったか確認して、あれば画面をフェード→別のマップに移動、とします。
移動先の位置などもインスペクターウィンドウで設定できるようにしておくと便利そうです。
ゲーム内のフラグ管理の実装
ゲームの進行状況に応じて、イベントの発生条件などが変わったりすることがあります。どのイベントを発生させるかのフラグを管理する機能も入れておきたいと思います。例えば、宝箱を初めて調べたらアイテムを入手、アイテム入手のフラグがTrueだったら「からっぽ!」とメッセージを表示する、なんて感じです。
ゲーム実行中はフラグ名(string)と状態(True/False)を保持させます。この状態を確認して、イベントを分岐させていきます。今回はフラグ名を定数クラスで管理して、特にデバッグ用の機能は作らないようにします。
RPGを作る際には、現在各フラグがどのような状態になっているのか、一覧で確認できると便利です。「イベントを設定してあるけど、何故か始まらないなー」と混乱するケースはよくありますからね。そのため、なにかあった時に、デバッグ用のキーを押してフラグ名と状態の一覧が表示できるようにしておくと、デバッグ面で有利です。(確認用のUIを作ったり)
問題はその一覧をどう作るかですが、ゲーム実行前にフラグ名一覧が分かっている状態を作るには、
- フラグ名の定数クラスを作ってReflectionで名前を取得する
- 取得した一覧をリストとしてScriptableObjectに保存する
- ゲーム開始時に上記のScriptableObjectを読み込む
- セーブファイルに保存されたフラグの状態を読み込む
あたりが必要そうです。1, 2に関してはEditor拡張で実行し、ランタイムでは3, 4を実行するイメージです。Reflectionを使うことから、実行時のクラッシュの可能性を考慮するとビルドの中に含めるのは避けた方が良いため、ScriptableObjectにリストを保存するワンクッションを入れています。フラグ一覧の定数クラスを更新するたびにScriptableObjectの更新処理を行う必要があるので、メニューバーから更新処理をすぐに呼び出せるようにすると良いですね。
(参考リンク)
宝箱の処理
宝箱を調べた際の、
- グラフィック変更
- アイテム入手処理
- フラグ設定
を実装します。マップをロードする際に、フラグに応じて宝箱のグラフィックを切り替える機能も入れておきましょう。
上記のフラグ管理と関連して、将来的にはフラグをカテゴリーごとにまとめておくと便利そうですね。例えば、宝箱の回収率を算出する際に、宝箱関連の全体フラグ数と、Trueになっているフラグ数を使うことで簡単に確認できます。フラグを管理するクラスは、ストーリー進行のフラグ、宝箱のフラグ、といったようにカテゴリーごとに各クラスに分けるか、あるいはフラグ名にカテゴリーを含めると良いかもしれません。宝箱に関しては、エリアごとの回収率を出すために、フラグ名の文字列の中にエリア名まで含めておくと判別しやすくなりそうです。
BGMや効果音の再生処理の実装
各マップや戦闘時のBGMや効果音の再生処理を実装していきます。フェード機能やクロスフェード機能、チャンネル管理など、色々と入れたい機能はありますが、まずは簡易的に再生/停止を行うSoundManagerを作ります。このSoundManagerはDontDestroyOnLoadを使って各シーンで使っていきましょう。
全体の制御動作の作成
ゲーム全体を動かす上での制御を作っていきます。個別の機能同士を繋げていくので、さまざまな問題が出たり、入れてなかった機能に気づくことが多いため、見た目の進捗が遅くなりやすいパートでもあります。その分土台がしっかりしていく点は意識しておくとモチベーションの低下を防げます。
エンカウントの仕組みを実装
フィールド上や洞窟を歩いている際のエンカウントの仕組みを作ります。今回はドラクエ風で進めたいので、シンボルエンカウントではなくランダムエンカウントで実装します。
ランダムエンカウントでは、移動のたびにエンカウント判定を行い、敵と遭遇した判定になったら、出現する敵キャラを抽選していきます。ゲームによっては敵パーティを事前に定義しておくこともあります。今回は1vs1の戦いのため、抽選テーブル内の敵キャラ1体を選択します。
どの敵が出るのか、抽選テーブルをマップ単位、あるいはマップ内のエリア単位で定義しておくと良いかと思います。マップ単位で保持するのが簡単かもしれません。マップ内エリアを定義するなら、ColliderのTriggerの判定を使って判別するのが良さそうです。今回はマップ単位でいくので、マップごとの定義ファイルから、敵キャラの抽選テーブル定義ファイルを参照させます。どちらもScriptableObjectで実装予定です。
メニュー画面の実装
移動中に開くメニュー画面を実装していきます。作りたいメニューは、
- アイテムの使用
- 装備の選択
- ステータスの確認
- ゲームの終了
です。上に加えて、メニュー画面を閉じる項目も入れておきます。
各画面で必要なUIを作成していくので、地道な作業が発生しそうですが頑張りましょう。
セーブ機能の実装
ゲームの進行状況やキャラクターの状態などを保存する機能を実装します。今回は主人公の村の中でセーブできるようにします。現代的なゲームを作る場合は、どこでもセーブできる機能や、中断セーブ、オートセーブなども入れておくと丁寧かと思います。
セーブファイルに関してはJSONで保存するようにします。キャラクターの各ステータス、経験値、レベル、フラグの情報、セーブした場所、といった内容を保存していきます。保存した内容を使ってロード時に同じ状況を再現できるかも確かめておきましょう。
今回は特に暗号化の機能は入れたりしませんが、リリースするゲームの場合はセーブファイルを暗号化しておくのも大切です。知識のある人ならセーブファイルを書き換えて色々と悪さできてしまうので、多少なりともめんどくさいと思わせることで防ぐ目的です。暗号化してあっても分かる人なら復号できちゃうのが辛いところですが、何もしないよりはマシかと思います。ネットワークを使って遊ぶゲームなら特に大切で、そもそもローカルにデータを保存しないなども対策になります。
タイトル画面の実装
ゲームのタイトル画面を実装します。リリース時には自分の会社やチームのロゴ、協力会社さんのロゴを表示するフェーズなどもありますが、今回は直でゲームのタイトル画面を表示して、以下のメニューを表示します。
- ゲーム開始
- 続きから
- ゲーム終了
ゲーム開始は初期状態から、続きからはセーブデータの読み込み、ゲーム終了はそのままゲームの実行を終了します。正直ゲーム終了はいらないかな? という気もするので、リリース時には「オプション」などに置き換えるとグッド。続きから、ではセーブデータの一覧を表示するUIが必要になります。もしセーブデータ数の上限があるなら事前に決めておくのが良いかと思います。スーパーファミコン時代なら大体3つくらい、PS時代では7から15個、それ以降は無制限になっていることが多いような印象です。
セーブデータのロード時には、どのセーブデータがどんな状態なのか分かると良いかと思います。セーブしたマップ名、キャラクターのレベル、プレイ時間などの情報を画面上に表示することで、どこまで進んだかの判別がしやすくなります。
ゲームオーバー時の処理の実装
RPGでは戦闘で負けることでゲームオーバーになります。ゲームオーバーになった後、経験値などを保持したまま特定のポイントでやり直すか、最後のセーブデータからやり直すかはゲームの難易度に応じて選ぶと良いかと思います。ドラクエシリーズでは最後にセーブした場所に戻り、ゴールドが半減した状態で再開します。この時、経験値などはそのまま保持されるため、負けた戦闘の前までは保持されることになります。
FFシリーズであれば、ゲームオーバーになったら最後のセーブファイルからやり直しになります。セーブした箇所がずっと前なら、そこからやり直しになるので難易度的には高くなる傾向にあります。その代わり、スーパーファミコン時代のFFシリーズならフィールドマップでセーブできますし、後年のFFシリーズならセーブポイントも多いので、そこまで難易度が上がる感じでもないかもしれません。(ただしFF3、テメーはダメだ)
今回はドラクエ方式を踏襲しつつ、デスペナルティはなしでそのまま最終セーブポイントの位置まで戻すようにします。
全体の動作確認
ここまでの実装内容を通して確認していきます。おそらく何かしら足りない部分が見つかるので、このフェーズで対応していきましょう。実際の開発では多分一番長くなると思います。
RPGではフラグの状態によって処理が変わってくることから、意図した形でイベントが進むかどうか、細かくチェックしていきましょう。上で触れたフラグ管理については、デバッグ用の画面でフラグの切り替えもできると良いかもしれません。テストプレイ時のフラグの切り替えは時間短縮に非常に有効ですからね。
今回はチュートリアルの形式にもしたいので、この点はさも今気づきましたよ、というていで進めたいと思います。
パラメータ類の調整
全体の動作ができたら、RPGで重要なパラメータ類の調整を行います。敵キャラとエンカウントした際、何ターンで倒せるようにするのか、強くなったらどれくらい楽に倒せるようにするのか、といった部分を調整しましょう。今回は敵キャラの数が3体、内2体が雑魚敵で1体がボスなので、あまり調整するような部分もないのですが、ボスを倒せるレベルを想定した上で、そのレベルで何度か戦って無理なく勝てるかどうかを試していきます。
RPGの場合は補助魔法の存在も重要で、ボスを倒す際に補助魔法を使うことを前提とするのか、それともゴリ押しで倒せるようにするのか、といった部分を自分の感覚と照らし合わせながら調整していきましょう。この辺りの調整は自分ひとりでやっていくと自分のゲーム体験が影響するため、他の人にプレイしてもらってフィードバックをもらっていくのがグッドです。
素材の作り込み(グラフィック)
ここまでやったら素材を作り込んでいきましょう。私の過去の経験から、序盤に素材を作り込んだとしても、ゲームとして完成させるのは五分五分くらいだったため、作り込みに関しては後に回した方が良いかと思います。システム的な部分での作業がどうしても多くなるため、序盤に作り込みの楽しい作業を持ってきてしまうと、開発部分で辛くなって「システム部分を頑張るのは明日にしようか……」と永遠に来ない明日を待つことになります。
今回のシンプルRPGでは作り込みの部分は少ないため、作業量としてはそんなに多くならない想定です。実際にRPGを作る場合はおそらく膨大な作業になるため、分担するのがセオリーかと思います。全部自分でやりたい場合は、後半に必要な素材数が判明してから着手すると作業量の見積もりもしやすくなり、モチベーションを維持しやすくなります。
ビルド
実際に遊べる形にするため、ビルドしていきましょう。正直なことを言えば、最後に初めてビルドするのではなく、機能を作った節目節目でビルドしていくことで、Unityエディタ上では発生しないけど実機では発生するバグなどを検知しやすくなります。
大体ビルドしたタイミングで新たなバグが発生しがちなため、早め早めに潰していけるとグッド。慣れてくると「ビルドした時にここが問題になりそう」といった点の検討がついてくるので、ビルド時のエラーやバグについては最初は戸惑うかもしれませんが、経験として蓄積されていくため恐れずに対処していきましょう。
実機確認
ビルドした後は実機で確認していきましょう。今回はWebGLで遊べる形を目指します。Unity6でスマホのブラウザでもWebGLが対応したそうなので、PCとスマホの両方で動作確認をしたいと思います。スマホで遊ぶとなると、解像度的に問題ないかも確認しないとですね。
今回は2D Pixel Perfectを使用してドット絵らしさを残すことから、解像度的にはそんなに高くないものを目指しています。スマホの画面でも画像が潰れないか、文字は読めるか、といった点を確認していきましょう。スマホの場合、縦横の向きも大切になってくるので、端末の向きに影響されない形で表示できるようにしたいと思います。
チュートリアル的には、実機ビルドして「あ、ここは修正しないといけませんね」という形で直していきたいと思います。
まとめ
シンプルなRPGを作る際の自分の作業順序の目安として、上記のように挙げてみました。これは正解を提示しているのではなく、ひとつの進め方のサンプルとして提示しているので、慣れている方からすると「なるほど、そういう感じか。『上』で待ってるぜ!」みたいな感じかと思います。チュートリアルとして、最後まで通しやすくするための流れも意識していますが、個人個人でやりやすい進め方も異なるかと思いますので、今回紹介したやり方はあくまでtodoちゃんがそうやってました、くらいの感覚で捉えていただければと思います。というかいいやり方教えてください(切実)
ブログのネタとしてもこの流れでチュートリアルを進めていきたいと思いますので、いつ完成するかはさておき、気長にお付き合いいただければと思います。
ゲーム開発の攻略チャートを作りました!
-
前の記事
【Unity】簡単なRPGを作る場合に必要な作業を考えてみよう 2024.11.22
-
次の記事
【Unity】RPGを作るチュートリアルその1 プロジェクトのセットアップ 2024.12.09
コメントを書く