Unityに関連する記事です

 複数回の手順に分けて、お使いの成果として褒賞を獲得できるようにします。

 この手順では褒賞のデータベースを利用し、お使いの難易度に応じた褒賞のデータをランダムで抽出する機能を実装します。
そのためにもう1つスクリプタブル・オブジェクトを作成して、お使いの難易度による希少度ごとの提供割合を登録するデータベースを作成します。
 
 抽出結果とその過程については Debug.Log メソッドを活用して、お使いの難易度と、褒賞の提供割合を元に褒賞がランダムに抽選されるか、確認を行います


<実装動画 ,使いの難易度(JobType)が Common の場合>
動画ファイルへのリンク


<実装動画◆,使いの難易度(JobType)が Normal の場合>
動画ファイルへのリンク




手順19 −お使いの難易度に応じた褒賞のデータをランダムで抽出する機能の実装−
31.お使いの難易度をデータベースとして登録するためのスクリプタブル・オブジェクトを作成するための準備を行う −JobTypeRewardRatesData スクリプトと JobTypeRewardRatesDataSO スクリプトを作成するー
32.JobTypeRewardRatesDataSO スクリプトを利用して JobTypeRewardRatesDataSO スクリプタブル・オブジェクトを作成し、データを登録する
33.GameManager スクリプトを修正し、2つのスクリプタブル・オブジェクトを運用して、お使いの難易度に応じた褒賞のデータをランダムで抽出する機能を実装する



 新しい学習内容は、以下の通りです。

 ・スクリプタブル・オブジェクトをゲーム内で利用できるようにする方法
 ・Linqの機能の実装例  Where メソッド、ToList メソッド、Sum メソッド、Select メソッド、ToArray メソッド〜



31.お使いの難易度をデータベースとして登録するためのスクリプタブル・オブジェクトを作成するための準備を行う −JobTypeRewardRatesData スクリプトと JobTypeRewardRatesDataSO スクリプトを作成するー

1.設計


 お使いが完了した際に生成されるキャラのゲームオブジェクトをタップすると、今回のお使いの成果として褒賞を獲得できるシステムを設計して実装します。
今回はお使いの難易度に応じた褒賞のデータをランダムで抽出する機能の設計と実装を行っていきます。

<褒賞獲得までの手順>
 〇獲得した褒賞の情報を表示してプレイヤーに伝えるための褒賞表示用ポップアップ・ゲームオブジェクトと、そのゲームオブジェクトを制御するスクリプト
 〇キャラをタップした際に、褒賞表示用のポップアップ・ゲームオブジェクトを生成する処理
 〇褒賞の内容を登録するためのデータベースの作成(今回の手順で作成)
 ◆お使いの難易度に応じた褒賞のデータをランダムで抽出する機能
 ・褒賞表示用ポップアップ・ゲームオブジェクトに、ランダムで抽出された褒賞のデータを送り込んで表示させる機能
 ・セーブしてあるお使いのデータと、 OfflineTimeManager スクリプトの List 内から削除する機能


2.JobTypeRewardRatesData スクリプトを作成する


 お使いの難易度による褒賞の希少度ごとの出現率(提供割合)データを登録するための変数群を束ねるクラスを作成します。
このクラスも MonoBehaviour クラスの継承がないクラスですので、ゲームオブジェクトにはアタッチできません。
オブジェクトとしてインスタンスを行って利用していくクラスになります。


JobTypeRewardRatesData.cs

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


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


3.JobTypeRewardRatesDataSO スクリプトを作成する


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

 今回指定して管理したいデータはお使いの難易度による希少度ごとの出現率のデータです。
そのため、JobTypeRewardRatesData 型の List を作成して、管理を行える状態として作成を行います。



JobTypeRewardRatesDataSO.cs

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


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


32.JobTypeRewardRatesDataSO スクリプトを利用して JobTypeRewardRatesDataSO スクリプタブル・オブジェクトを作成し、データを登録する

1.JobTypeRewardRatesDataSO スクリプトを利用して JobTypeRewardRatesDataSO スクリプタブル・オブジェクトを作成し、データを登録する


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

 Project フォルダ内の Datas フォルダにて Unity の左上のメニューより、Assets => Create => Create JobTypeRewardRatesDataSO を選択します。
新しく JobTypeRewardRatesDataSO というファイルが作成されます。名前はそのままで構いません。

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


<フォルダ管理>



2.JobTypeRewardRatesDataSO スクリプタブル・オブジェクトの設定を行う


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

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



 お使いの難易度に合わせて、データを3つ分登録しておきたいと思います。
jobTypeRewardRatesDataList 変数の Size を 3 に変更してください。Element 0 〜 2 が下に作成されます。

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

 以上のことから、1つの Element には1つの JobTypeRewardRatesData クラスの内容を設定できるようになっています。
このとき、JobTypeRewardRatesData クラスの上に [Serializable] 属性を宣言しているので、JobTypeRewardRatesData クラスの内容がインスペクターに表示されています。



 下記の画像のように設定を行ってみてください。
jobType 変数には異なる種類を登録し、rewardRates 配列変数は Size を 3 に設定して、希少度ごとの提供割合を登録します。
この rewardRates 配列変数の合計値は 100 になるようにすることで確率として扱うことが出来ます。


インスペクター画像



 以上で登録完了です。


33.GameManager スクリプトを修正し、2つのスクリプタブル・オブジェクトを運用して、お使いの難易度に応じた褒賞のデータをランダムで抽出する機能を実装する

1.設計


 新しく抽選処理を行うメソッドを追加し、キャラをタップした後に呼び出される ResultJobs メソッド内の TODO に処理を実装します。

 抽選処理のメソッドは非常に複雑な処理になっているので、しっかりと読み解けるようにしましょう。



 まずはお使いに設定されている難易度(JobType)を元にして、JobTypeRewardRatesDataSO スクリプタブル・オブジェクトを参照して、その難易度における希少度の提供割合を照合してデータを取得します。
例えば、難易度が Easy である場合、JobTypeRewardRatesDataSO スクリプタブル・オブジェクトの Element 0 が照合して該当しますので、
その配列の値を希少度として利用し、それぞれ、Common の提供割合、Normal の提供割合、Rare の提供割合として準備します。

 次にランダムな値を1つ取得し、上記の提供割合のどの部分に該当するかを照合します。
ランダムな値の最大値は提供割合の合計値とし、その範囲内で値を取得するので、これらの提供割合の値を上回ることはありません。

 ランダムな値によって希少度が決定したら、次は、その希少度に含まれる褒賞の種類と、その出現割合を準備します。
例えば、希少度が Common に決定した場合、Common の褒賞は3種類ありますので、この3種類のいずれか1つを提供するために、それらの出現割合を準備します。

 再度ランダムな値を1つ取得し、褒賞の出現割合から、どの褒賞に該当するのかを照合します。
こちらのランダムな値も出現割合の合計値とすることで、出現割りを上回ることがないようにします。

 この手順を1つのメソッド内に順番に記述していきます。
処理のイメージをつかんでから始めてください。また処理には Linq という機能を複数利用しています。解説がありますので、そちらも参考に読み解いてください。

 ここで褒賞を決定することで、次の手順で褒賞表示用のポップアップに、情報を送りこむことが出来るようになります。


2.GameManager スクリプトを修正する


 スクリプタブル・オブジェクトを登録して管理するための変数を RewardDataSO 型と JobTypeRewardRatesDataSO 型でそれぞれ宣言しておきます。
スクリプタブル・オブジェクトと同じ型にすることで代入が可能になります。

 このとき、SerializeField 属性付きで宣言しておくことによって、インスペクターよりスクリプタブル・オブジェクトの代入が可能になります。

 抽選処理については、TODO 機能の部分に処理を実装していきます。


GameManager.cs

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


 スクリプトを修正したらセーブします。


3.<Linq の機能の実装例  Where メソッド、ToList メソッド、Sum メソッド、Select メソッド、ToArray メソッド〜>


 Linq(リンク)とは、コレクション(Dictionary や List など)の要素を操作して、検索したり集計する処理を簡潔に記述することができるライブラリ(複数の機能をまとめたもの)です。

 Linqを使用するためにはusing の宣言が必要になります。今回作成したメソッド内に登場している処理ですので、復習して読み解けるようにしていきましょう。

using System.Linq;



 Linqを記述する際にはラムダ式の記述を用います。ラムダ式についてはこちらをご確認ください。
SamuraiBlog様
【C#入門】LINQの使い方総まとめ(Select、Where、GroupByなど)
https://www.sejuku.net/blog/56519

 Linqには多くの機能がありますが今回利用している機能についてまとめておきます。
そのほかの機能については記事がたくさんありますが、こちらのサイトも参考になります。
地平線に行く様
LINQの拡張メソッド一覧と、ほぼ全部のサンプルを作ってみました。
https://yujisoftware.hatenablog.com/entry/20111031...


1.Where メソッド

 配列や List などのコレクションに対してフィルタリング処理を行い、指定した条件を満たす要素のみを取得することができる機能です。
引数にはフィルタリングを行う条件式を指定します。

  // 今回対象となる希少度のデータだけのリストを作成
  List<RewardData> rewardDatas = new List<RewardData>(rewardDataSO.rewardDatasList.Where(x => x.rarityType == rarityType).ToList());

 今回の実装例では Where メソッドの条件式に x.rarityType == rarityType を指定しています。
これは List 型のコレクションである rewardDatasList 変数の要素を1つずつフィルタリングし、上記の条件に合う要素のみを取得しています。
x には rewardDatasList 変数の要素である RewardData 型の情報が1つずつ順番に代入され、RewardData クラスの持つ rarityType と引数で届いている rarityType とを照合しています。

 この処理は IEnumerable<T> の戻り値を持つため、メソッドチェーンを行うことで、この処理の結果を次の処理につなげていくことが可能です。
今回であれば、フィルタリングして照合の条件を満たした複数の RewardData 型の情報を取得することが出来ます。


参考サイト
MicroSoft
Enumerable.Where メソッド
https://docs.microsoft.com/ja-jp/dotnet/api/system...
陰干し中のゲーム開発メモ
【C#,LINQ】Where〜配列やリストを指定した条件でフィルタリングしたいとき〜
https://www.urablog.xyz/entry/2018/06/27/070000
.NET Column 様
【LINQのメソッド紹介その3】Whereで条件に合うデータを取得する
https://www.fenet.jp/dotnet/column/language/1458/


2.ToList メソッド

 IEnumerable<T> から List<T> を作成します。

 IEnumerable<T> は Linq の処理を実行した際の戻り値の情報です。例えば、フィルタリングして算出された結果を List 型にして利用したい場合に利用します。

  // 今回対象となる希少度のデータだけのリストを作成
  List<RewardData> rewardDatas = new List<RewardData>(rewardDataSO.rewardDatasList.Where(x => x.rarityType == rarityType).ToList());

 上記のケースの場合、Where メソッドによって条件に合う RewardData クラス(IEnumerable<T> の T の部分)の情報が戻り値として取得できますが、それは取得しただけで処理が終了してしまいます。
そのため、ToList メソッドを実行して実体化しておくことで、List 型として情報を取得して扱うことが可能になります。

 それを左辺に用意している変数へと代入処理しています。よって、 Where メソッドの条件式によってフィルタリングされて抽出された複数の RewardData クラスの情報が
ToList メソッドを実行することで再度 List として再編されて存在するようになります。


参考サイト
MicroSoft
Enumerable.ToList<TSource>(IEnumerable<TSource>) メソッド
https://docs.microsoft.com/ja-jp/dotnet/api/system...
Qiita @mounntainn 様
LINQについての備忘録
https://qiita.com/mounntainn/items/e8b8f94a15ec4fe...


3.Sum メソッド

 集計用のメソッドの1つです。指定したコレクションの要素の合計値を戻します。

 // 難易度による希少度の合計値を算出して、ランダムな値を抽出
  int randomRarityValue = UnityEngine.Random.Range(0, JobTypeRewardRatesDataSO.jobTypeRewardRatesDataList[(int)jobType].rewardRates.Sum());

 こちらの実装では、指定された jobType(お使いの難易度)を持つ JobTypeRewardRatesData クラスにある rewardRates 配列変数の要素を合計しています。
その値を UnityEngine.Random.Range メソッドの最大値として利用し、乱数の取得しています。

 UnityEngine.Random.Range メソッドと記述しているのは、Random.Range メソッドが using System と using UnityEngine の両方に用意されているため、
メソッドの前に using 先の指定がないと、どちらの Random.Range メソッドを利用していいのかプログラムが判断できなくなるためです。


参考サイト
MicroSoft
Enumerable.Sum メソッド
https://docs.microsoft.com/ja-jp/dotnet/api/system...
Qiita @RyotaMurohoshi 様
~https://qiita.com/RyotaMurohoshi/items/d4a6750a798...
Qitta @logikuma 様
【C#】LINQ備忘録2 〜集計編〜
https://qiita.com/logikuma/items/d4f87ff4c308a7606...


4.Select メソッド

 射影処理と呼ばれる機能です。射影とはデータベース用の専門用語で、テーブル(実データ)から特定の列のデータのみを取り出すことを言います。

 Select メソッドでは引数にした条件を元に、照合できたデータのみを取り出す操作を行います。
このメソッドの戻り値は IEnumerable<TResult> であり、その情報を取得して利用したい場合には、メソッドチェーンを利用して、ToList メソッドや ToArray メソッドを利用して扱える状態にします。
これは Where メソッドと同じ処理の手順になります。

  // 同じ希少度の合計値を算出して、ランダムな値を抽出
  int randomRewardValue = UnityEngine.Random.Range(0, rewardDatas.Select(x => x.rarityRate).ToArray().Sum());

 こちらの実装例では、Range メソッドの第2引数の部分で Select メソッドを利用しています。
rewardDatas.Select(x => x.rarityRate).ToArray().Sum() ここまでが、第2引数の処理です。

 rewardDatas 配列変数の各要素より、rarityRate 変数の情報をそれぞれ取り出します。
rewardDatas.Select(x => x.rarityRate) ここまでが Select メソッドです。


参考サイト
MicroSoft
Enumerable.Select メソッド
https://docs.microsoft.com/ja-jp/dotnet/api/system...
.NET Column 様
【LINQのSelectメソッドの書き方3選|LINQについてなどを紹介
https://www.fenet.jp/dotnet/column/language/1454/
Qiita @t_takahari 様
LINQのそのForEach、実はSelectで書き換えられるかも
https://qiita.com/t_takahari/items/6dc72f48b1ebdfe...


5.ToArray メソッド

 IEnumerable<T> から配列を作成します。

 IEnumerable<T> は Linq の処理を実行した際の戻り値の情報です。例えば、フィルタリングして算出された結果を 配列型にして利用したい場合に利用します。

  // 同じ希少度の合計値を算出して、ランダムな値を抽出
  int randomRewardValue = UnityEngine.Random.Range(0, rewardDatas.Select(x => x.rarityRate).ToArray().Sum());
 
 Select メソッドによって抽出された情報を配列にしています。そしてその後に Sum メソッドを実行することにより、
配列の要素をすべて合計した値を算出し、それを Range メソッドの最大値として利用しています。

  // 同じ希少度の合計値を算出して、ランダムな値を抽出
  int randomRewardValue = UnityEngine.Random.Range(0, [ 配列である rewardDatas クラスの持つ各 rarityRate 変数の値のみ取り出してそれを配列にし、その配列の要素の値の合計値 ]);


参考サイト
MicroSoft
Enumerable.ToArray<TSource>(IEnumerable<TSource>) メソッド
https://docs.microsoft.com/ja-jp/dotnet/api/system...
Qiita @Marimoiro 様
LINQチートシート的なもの
https://qiita.com/Marimoiro/items/0e119b47d65bf138...


4.ゲームを実行して動作を確認する


 Debug.Log メソッドを活用して、褒賞がランダムに抽選されるか、確認を行います。
お使いの難易度(JobType)を変更し、何回も試して、どのような処理が行われてるのかをしっかりと把握しておきましょう。


<実装動画 ,使いの難易度(JobType)が Common の場合>
動画ファイルへのリンク


<実装動画◆,使いの難易度(JobType)が Normal の場合>
動画ファイルへのリンク




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

 次は 手順20 ーランダムで抽出した褒賞のデータを褒賞表示ポップアップに反映する処理の実装ー です。

コメントをかく


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

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

Menu



技術/知識(実装例)

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

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

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

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

レースゲーム(抜粋)

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

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

3D脱出ゲーム(抜粋)

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

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

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

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

VideoPlayer イベント連動の実装例

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

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

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

private



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

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