Unityに関連する記事です

 ローグライト系のゲーム(Sly The Spire、ファントムローズなど)に見られる、プレイヤーが1マスずつ移動してゴール地点へ向かいながら、
各マスごとに分岐(選択肢)があり、任意のイベントを実行しながら進行するタイプのゲームシステムの実装例です。

 ここでは各マス目に複数の分岐処理がある形で1マスずつイベントを進行させていく方法を実装します。
最初のマスは分岐なし、次のマスは2つの分岐がある、といったようなローグライト系のゲームでよくみられるイベントシステムです。

 ルートごとにイベントを登録し、マス目ごとに運用するためのスクリプタブル・オブジェクトを作成します。



設計


 前回につづき、合計4回の手順に分けて実装を行います。

〇1.UI 制作
〇2.イベント用のクラス制作
◇3.データベース制作
 4.管理クラス制作

 今回は【2.イベント用のクラス制作】を行います。

 マス目ごとのイベントの情報をデータベースとして管理できるようにしておくことで、情報の編集をまとめて行える環境を作ります。
また情報をデータベースに登録しておくことにより、スクリプトからの参照してもらった際に、必要な情報を提供出来るようにします。


クラスの考え方 ー複数のデータを関連して管理する方法ー


 例えば、プレイヤーの情報やアイテムの情報などデータを扱う場合に、複数のデータを1つのまとまりとして管理できる方法があると扱いが楽になります。

 以下のように、野球選手やサッカー選手1名分をデータとして扱うことを考えてみてください。

<野球選手の場合>
 ・背番号
 ・得意な守備位置
 ・打率
 ・走力
    など



<サッカー選手の場合>
 ・ポジション・役割(ゴールキーパー、ディフェンダー、ミッドフィルダー、フォワード)
 ・体格
 ・シュート力
 ・ドリブル力
 ・走力
    など

 このように、1つの選手のデータを管理するにあたっては複数の情報が必要ですが、それらはバラバラになっていては関連性が分かりません

 プログラムではこのようなデータを管理するためにクラスが用意されています。
 
 クラスの役割は変数の宣言とメソッドの宣言が行えることですが、変数の部分を、それぞれの選手の情報を扱う値として利用します。

 このような観点で選手用のデータを管理するためのクラスを作成し、その中に関連している複数のデータを変数として宣言して管理することで、
1つのクラスで選手の情報を表現することができます。

 野球選手を例にすると、このようなクラスになります。

public class BaseBallPlayerData {

    public int uniform number;          // 背番号
   public string defensivePositon;     // 得意な守備位置
   public float battingAverage;        // 打率   
   public float runSpeed;              // 走力

}

 このようにクラスを活用することで、1つの情報を構成するために必要な複数のデータを管理することが可能になります。

 この考え方をベースに、今回の場合にはイベントのデータを管理するためのクラスと、それを束ねてデータベースにする機能を作成していきます。
 

コレクション機能


 先ほど野球選手のデータを BaseBallPlayerData クラスとして表現しました。

 このクラスには選手1名分のデータを管理することができます。ですが、野球やサッカー、それ以外のものの多くは、1つのデータだけでは情報が足りません。
少なくても野球の場合には9名(相手も必要なので18名)分の BaseBallPlayerData が必要になります。
なぜなら、BaseBallPlayerData には1名分のデータしか管理出来ませんので、それを人数分用意しなければならない訳です。



 こうしたとき、同名のクラス群を1つのまとまりとして管理できる入れ物のようなものがあると扱いが楽になります。
9名分の BaseBallPlayerData クラスの変数を9個用意したのでは管理していることにはなりません。

 BaseBallPlayerData クラス9名分を1つの変数でまとめて管理してくれるものとして、C# ではコレクションという機能を利用することで実現できます。

 C# のコレクションには、List、Dectionary という機能が用意されています。(配列はコレクションではないので注意してください。)


<各クラスを1つずつ宣言 → これは1つの変数にまとまっていない>
 BaseBallPlayerData player0;
  BaseBallPlayerData player1;
  BaseBallPlayerData player2;

    :

  BaseBallPlayerData player8;
 
  ↓

<コレクション機能を使い、1つの変数で同クラスの異なるデータを表現する>
 List<BaseBallPlayerData> playerList;  // List



 Unity ではこのうち、ScriptableObject クラスと List の機能を活用して作成できるスクリプタブル・オブジェクトという機能が用意されています。
このスクリプタブル・オブジェクトの機能を利用することで、データベースを作成することができます。

 なお、コレクション機能はあくまでも複数の同クラスの情報をまとめて管理することがメインです。
そのため、コレクション機能を使えばそれがデータベースになる、ということではありません
あくまでも Unity の用意している ScriptableObject クラスと List を活用することでデータベースを作成しています。

 この部分の認識を間違えないようにしてください。


参考サイト
MicroSoft
コレクション


 知らない単語が出てきたときには積極的に、ネットに公開されている公式のマニュアル、わかりやすくまとめた記事などを見つけて調べてみてください。


スクリプタブル・オブジェクト


 スクリプタブル・オブジェクトを作成するためには、専用のスクリプトを作成する必要があります。その作成方法を学習します。

 今回作成するスクリプタブル・オブジェクトはレベル(ステージ)内のルートとルート内の分岐のデータを管理する目的で作成を行います。
そのため、スクリプト内にはルート関連のデータをまとめるための RouteData クラスを用意します

 RouteData クラスは、ルート関連のデータを1つにまとめている情報群です。
ルート内の分岐情報を1つのデータ群としてまとめて管理するためのクラスになります。

 この RouteData クラスは、レベル(ステージ)内に登場するの数だけ用意することになりますので、それを管理するために List 機能を利用します。

 この2つの情報を管理して完成するのがスクリプタブル・オブジェクトになります。
そのためにクラスとして、RouteCollection クラスを作成します。RouteDataSO といった名称でも問題ありません。

 どのような構成になっているかはスクリプト作成後に説明をしていますので、そちらをしっかりと学習しておいてください。
真似をして作ってみたり、復習を重ねていくことでプログラムは理解が深まり、処理のイメージがわくようになり、書けるようになります。


RouteData スクリプトの作成


 RouteData スクリプトを作成します。

 using の宣言は不要です。
またクラスは継承しませんので、MonoBehaviour クラスは削除してください。

 スクリプタブル・オブジェクトを作成した際、インスペクターから RouteData クラスの情報を設定できるように
[System.Serializable] 属性をクラスの上に付与してください。


RouteData.cs

<= クリックすると開きます。


 スクリプトを作成したらセーブします。


[System.Serializable(シリアライザブル)]属性


 入れ子になっているクラスの1行上には上記の宣言があります。[ ]で宣言された設定値は「属性」と呼ばれる情報になり、特別な意味を持ちます。

 今回利用している[System.Serializable]属性は、Systemに含まれている設定値であり、こちらを宣言することで入れ子クラスの情報をインスペクターに表示することが出来ます。
これを書き忘れてしまうと、インスペクターに RouteData が表示されず、データをインスペクターから登録することが出来ません
using System; を宣言している場合には [Serializable] とだけ記述すれば適用されます。
宣言していない場合には [System.Serializable] と記述する必要があります。


RouteCollection スクリプトの作成


 スクリプタブル・オブジェクトを作成するために必要な RouteCollection スクリプトを作成します。
スクリプタブル・オブジェクト専用の ScriptableObject クラスを継承し、[CreateAssetMenu] 属性を記述することで作成可能になります。
 
 スクリプタブル・オブジェクトでは、指定したデータを複数のデータとしてまとめて管理することが出来ます。
そのため、データベースとしての役割を果たすことが可能になっています。

 今回指定して管理したいデータはルート関連のデータです。
そのため、スクリプタブル・オブジェクト内に必要な情報は以下の2つです。

 1.情報単位でのデータ(ルート内のイベントのデータ群)を扱うクラス
 2.データをまとめる List(リスト)と ScriptableObject を継承したクラス

 このうち1は先ほど作成した RouteData が当たります。
ここでは2のスクリプトを作成します。



 RouteCollection スクリプトを作成します。
このスクリプトを利用することで、RouteData を束ねたスクリプタブル・オブジェクトをアセットとして作成することが出来ます。

 [CreateAssetMenu]属性の付与と、ScriptableObject クラスを継承することを忘れないようにしてください。


RouteCollection.cs

<= クリックすると開きます。


 スクリプトを作成したらセーブします。


RouteCollection スクリプトの構造について


 処理の内容について、順番に確認していきます。

 1.情報単位でのデータ(ルート内のイベントのデータ群)を扱うクラス
 2.データをまとめる List(リスト)と ScriptableObject を継承したクラス


1.情報単位でのデータ(ルート内のイベントのデータ群)を扱うクラス


 利点は、1つの RouteData クラス内には1つ分のルート内のイベント分岐が登録できることです。
RouteData の eventList という形で RouteData を参照して利用できる部分です。

 例えば、RouteData.eventList と記述すれば、それはその RouteData クラスに登録されている eventList の値を参照することになります。

 ここからはピリオドによる参照処理が増えていきますので、しっかりと処理を読み解いていきましょう

using System.Collections.Generic;

[System.Serializable]
public class RouteData {
    public List<EventBase> eventList = new();
}

 このように同じ種類のデータを1つのクラスとしてまとめておくことで管理と利用が容易になります

 また、管理する情報を増やしたい場合には、この RouteData クラス内に 型と変数を追記すれば、好きなだけ増やすことも出来ます。


2.データをまとめる List(リスト)と ScriptableObject を継承したクラス


 RouteData クラスには EventBase の情報をまとめて登録できるようにしました。
これは親クラスでの型指定になっているため、EventBase を継承しているサブクラスであれば、どのサブクラスであっても登録できます。
処理を抽象化することの恩恵の1つです。

 こういった1つの同じデータ群をまとまったものをコレクションといいます。
C# にはコレクションを管理する方法として、Dictinary(ディクショナリー)List(リスト) があります。



 List クラスは <T> にジェネリック型(任意の型)を指定して、同じデータ型をまとめて管理するコレクション機能を持つクラスです。
配列と異なり、要素を自由に追加・削除できます。(要素数が可変する)
List はサイズ(長さ)が可変可能な配列のイメージです。

 List を利用する場合には配列と同様に初期化が可能ですが、Listでは初期化時に要素数の宣言が不要です

<配列の初期化>
  RouteData[] routeDatas = new RouteData[3];       // <=  要素数の宣言が必要

<List の初期化 
  List<RouteData> routeList = new List<RouteData>();   // <=  要素数の宣言が不要

<List の初期化◆,海舛蕕任盻藉化できます>
  List<RouteData> routeList = new ();   // <=  要素数の宣言が不要

 そのため基本的には、予め要素数の確定しているデータを扱う場合には配列を、要素数が未確定であったり可変長であるデータについてはListを利用するように考えてください。


参考サイト
.net column様
【初期化の方法】C#で配列やリストを初期化するには?



 public 修飾子にて List を宣言することで、インスペクター上でサイズの変更が可能です

 例えばデータを3つ分作って登録したい場合には、インスペクターで List のサイズを 3 に設定すれば
RouteData クラスが 3 つ、Element 0 〜 Element 2 として作成されます。

 ここの中にさらに EventList 変数があり、そこにイベントのデータを1つずつ登録することが出来ます。


<RouteData クラスを扱う List>
    public List<RouteData> routeList = new ();


RouteCollection スクリプタブル・オブジェクトの作成


 RouteCollection スクリプトを元に RouteCollection スクリプタブル・オブジェクトを作成します。
RouteCollection スクリプトに用意してある RouteData 型の List である routeList 変数がデータベースの役割を持っています。

 ここで大切なことは、1つ1つの別の変数に個別に RouteData が存在していたのではまとめて管理していることにはなりません
RouteData のリストとはすなわち、RouteData をまとめて扱っているデータの集合体になりますので、ここにデータベースとして役割を成立させることが出来ます



 スクリプタブル・オブジェクト作成前に、Project 内に Datas などのフォルダを作成しておくと管理しやすくなります。

 Datas フォルダ内で右クリックをしてメニューを開き、Create → Create RouteCollection を選択します。
フォルダ内に RouteCollection スクリプタブル・オブジェクトのアセットが作成されます。名前はそのままで問題ありません。


メニュー



Datas フォルダ


 このアイコンの形が違うファイルがスクリプタブル・オブジェクトになります。
これはアセットとして取り扱われるようになる情報であることを示しています。


登録


 作成された RouteCollection スクリプタブル・オブジェクトを選択してインスペクターを確認します。
RouteCollection スクリプトにて宣言した routeList 変数がインスペクターに表示されて、 Sizeが 0 になっています。
これがスクリプタブル・オブジェクトの中身です。

 Size に任意の数を入力すると、同数の Element が作成されます。これが List で管理する RouteData クラスの情報群になります。

 RouteCollection スクリプタブル・オブジェクトのアセットを選択し、インスペクターから RouteData に情報を登録します。
RouteData 内には EventList 変数があります。これがマス目の分岐の数です。



 まずはルートデータを4つ分登録しておきたいと思います。
routeList 変数の Size を 4 に変更してください。Element 0 〜 3 が下に作成されます。

 Element とは List の要素(中身)のことです。
そのため、Element 1つが RouteData 1つになります。Element の番号は 0 から始まります。

 以上のことから、1つの Element には1つの RouteData クラス(マス目ごとの分岐)の内容を設定できるようになっています。
このとき、RouteData クラスの上に [Serializable] 属性を宣言しているので、RouteData クラスの内容がインスペクターに表示されています。
[Serializable] 属性を活用することによって、インスペクターから情報を1つずつ、RouteData 単位で登録出来るようになっています。



 次に、各 RouteData ごとの EventList の数を設定します。
1にすれば分岐なし、2 にすれば分岐が作成されます。

 ここには EventBase クラス、あるいは、EventBase を継承しているサブクラスがアタッチされているゲームオブジェクトやプレハブをアサインすることが出来ます。

 プレハブになっている SearchEvent や BattleEvent をドラッグアンドドロップして、イベントを登録してください。


インスペクター画像(サンプル。この画像のようにする必要はありません)



 この例の場合、最初と4つめのマス目には分岐はなく、2つ目と3つ目に分岐がある状態になります。



 以上でこの手順は終了です。

 => 次は 【2D】マス目ごとにイベントが発生するシステムの実装例 です。

コメントをかく


「http://」を含む投稿は禁止されています。

利用規約をご確認のうえご記入下さい

Menu



技術/知識(実装例)

2Dおはじきゲーム(発展編)

2D強制横スクロールアクション(発展編)

3Dダイビングアクション(発展編)

2Dタップシューティング(拡張編)

レースゲーム(抜粋)

2D放置ゲーム(発展編)

3Dレールガンシューティング(応用編)

3D脱出ゲーム(抜粋)

2Dリアルタイムストラテジー

2Dトップビューアドベンチャー(宴アセット使用)

3Dタップアクション(NavMeshAgent 使用)

2Dトップビューアクション(カエルの為に〜、ボコスカウォーズ風)

VideoPlayer イベント連動の実装例

VideoPlayer リスト内からムービー再生の実装例(発展)

AR 画像付きオブジェクト生成の実装例

AR リスト内から生成の実装例(発展)

private



このサイト内の作品はユニティちゃんライセンス条項の元に提供されています。

管理人/副管理人のみ編集できます