こんにちは、みじんこと申します。
本記事では前記事から引き続き、Unityでのガチャ(パック)機能の実装方法を説明します。
そちらをまだ見ていない方は、実施後にこの記事に進んで頂けると良きかと思います!
本記事では④のガチャ機能における「カードのランダム生成機能の実装」を解説していきます。
- 前準備とカードの作成
- カードとパックの生成実装
- カードの種類の実装
- カードのランダム生成機能の実装
- カードの移動アニメーションの実装
- カード詳細パネルの実装
- ショップの実装
本記事の完成形としてはこんな感じですね。
パックが出てきて、、
クリックしたら、ランダムな種類のカードが8枚生成される!
こんな感じで、今回の記事にてガチャ機能の基本は完成となります!!
ここまでお疲れ様でした!今回も頑張っていきましょう!!
Contents
【実装概要】本記事で実装する内容について
今回はカードのランダム生成を実装していきますが、この流れにて実装していきます。
- カードをランダムに生成させる処理の実装
- パックをクリック時にカードを生成させる処理を実装
前回までの記事で、指定したカードを生成出来るようにはなったので、
その処理を使って、今回はランダムにカードを生成するようにしていく感じですね。
それでは早速やっていきましょう!
手順①:カードをランダムに生成させる処理の実装
この手順では、ゲームを実行したときに、
ランダムな種類のカードが8枚生成される処理を実装していきます。
完成形はこれですね。
新規スクリプトの作成
では早速やっていきましょう!
今回書いていく処理はパック開封時特有の処理になるので、まず新しいスクリプトを作っていきます。(今まで色々書いていたGameManagerスクリプトはゲーム全体に関わる処理だけを書きたい)
「OpenPackManager」って名前でスクリプトを新規作成しましょう。
コードの記載
それではコードを書いていきますが、
今回は「抽選確率が一定の場合」のコードを書いていきます。
要は全てのカードの排出率が同じ場合ってことですね。
※カードによって出てくる確率が変わる場合のシステムは別の記事にて解説予定です。
ちょっとだけコード解説!!
今回はコードを記載する前にちょっとだけ内容の解説をしていきます。
今回はGameManagerスクリプトとOpenPackManagerスクリプトを記載、変更していくんですが、その内容を下記にまとめました。
今回記載、変更するコードの内容について
■GameManagerスクリプトの変更点
- 下記コードの削除(OpenPackManagerスクリプトに移動する)
- パックプレハブやパック生成場所などの変数定義
- Startメソッド
- OpenPackメソッド
- シングルトン化(詳細は後述)
- 他のスクリプトから参照出来るようにしてる
- CreateCardメソッドのPublic化(詳細は後述)
- 他のスクリプトから参照出来るようにしてる
■OpenPackManagerスクリプトの記載内容
- 下記コードの記載(GameManagerスクリプトから移動してくる)
- パックプレハブやパック生成場所などの変数定義
- Startメソッド
- OpenPackメソッド
- 排出されるカードのIDリストの記載
- 「このパックからはこのカードが出てきますよー」っていうカードのリスト
- 生成するカードのIDをランダムに決定するメソッドの記載
- カードのIDリストを参照して、ランダムにカードのIDを教えてくれるメソッド
シングルトン化、Public化ってなに??
※ちょっと長いから気になる人だけ読んで!!
ざっくりとだけ書きますが、下記のイメージでOKです。
- シングルトン化:「このインスタンスはこれ1つだけだよ!!」ってすること。
- ここでは他のスクリプトから参照出来るようにこの方法を使用。
- Public化:「他のスクリプトでも参照していいよ!」ってやること。
多分これだけだと、
なんでそんなことをする必要があるの??
って思うと思いますが、
基本的にC#は他のスクリプト(クラス)の内容を知れない。からです。
例えば、
スクリプトAに「変数 i=1」って書いてあっても、
スクリプトBはスクリプトAの変数iの値が分からないんです。
これを解決するために、
スクリプトAをシングルトン化(スクリプトの内容を他のスクリプトからも参照出来るようにしてあげる)して、変数iもPublic化してあげることで、
やっとこスクリプトBで変数iの値が「1だ!」って知れるイメージです。
今回で言うと「GameManager」に書いてあるCreateCardメソッドが
「OpenPackManager」から使えないので、
シングルトン化とPublic化してあげた。ってイメージを持って貰えれば完璧です。
※「そもそもなんで他のスクリプトの内容を参照出来ないの??」っていう疑問を持った方もいるかも知れないのでもうちょっとだけ答えると、C#がオブジェクト指向の言語だからです。
オブジェクト指向の考え方的に「何でもかんでも他のクラスから参照出来ちゃったら、ダメじゃない??」って言うのがあるので、こんな仕様になってます。
(これ以上のオブジェクト指向についての言及は避ける。。もっと知りたい人は自分で勉強なさい。笑)
まあひとまず今回の解説記事の中では、
シングルトン化とか、Public化とかって出てきたら
他のスクリプトから参照出来るようにしたのね
って理解してもらえればOK!!
まあとりあえず、
- GameManagerスクリプトからOpenPackManagerにいくつかのコードを移動したよ。
- OpenPackManagerにカードリストからランダムにカードを生成する処理を書いたよ。
って理解でOK。
コードを記載する
それでは今ちょろっと解説した内容を念頭に置いたら、
GameManagerスクリプトは下記の内容に書き換えましょう。(丸ごとコピペする)
※どこがどう変わったのかをしっかり理解してからコピペしてね。
1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19 20 21 22 23 24 25 26 27 28 29 30 31 32 |
using System.Collections; using System.Collections.Generic; using UnityEngine; public class GameManager : MonoBehaviour { [SerializeField] CardController cardPrefab; // カードプレハブ // シングルトン化 public static GameManager instance; private void Awake() { if (instance == null) { instance = this; DontDestroyOnLoad(this.gameObject); } else { Destroy(this.gameObject); } } // カードを生成するメソッド(Public化した) public void CreateCard(int cardId, Transform trans) { // cardPrefabをopenedCardTransに生成する CardController card = Instantiate(cardPrefab, trans); card.Init(cardId); } } |
次は「OpenPackManager」スクリプトに下記のコードを丸ごとコピー。
※こっちもどの記載がどの処理をしてるのかを理解してからコピペしてね。
1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19 20 21 22 23 24 25 26 27 28 29 30 31 32 33 34 35 |
using System.Collections; using System.Collections.Generic; using UnityEngine; public class OpenPackManager : MonoBehaviour { [SerializeField] GameObject cardPackPrefab; // カードパックプレハブ [SerializeField] Transform openedCardTrans; // 開封したカードの生成場所 [SerializeField] Transform cardPackTrans; // カードパックの生成場所 public List<int> packCardList = new List<int>() { 0, 1, 2, 3 }; // パックのカードリスト private void Start() { OpenPack(); } // パックを開封するメソッド public void OpenPack() { // 8枚カードを生成する for (int i = 0; i < 8; i++) { int cardId = decisionCardId(); GameManager.instance.CreateCard(cardId, openedCardTrans); } } // カードのIDをランダムに決めるメソッド int decisionCardId() { int randomCardId = packCardList[Random.Range(0, packCardList.Count)]; return randomCardId; } } |
コピーして保存出来たらOKです。次に進みましょう。
Unity側にアタッチする
続いてはUnity側の設定をしていきましょう。
- Hierarchyウィンドウ(Main Cameraとかあるところ)にて右クリックして、「Create Empty」をクリックして、それを「OpenPackManager」に名称変更!!
- 「Add Component」で、OpenPackManagerをアタッチする
今Hierarchyウィンドウに作った「OpenPackManager」に設定をしていこう。
- 「OpenPackManager」をクリックして、「OpenedCardTrans」「CardPackTrans」「CardPack」をアタッチしよう(以前、「GameManager」にアタッチしたのと同じ要領で)
これでUnity側の設定は出来たので、次へ進みましょう!
ゲームを実行してみる
それではゲームを実行しましょう!
ランダムにカードが8枚されてる!!
となってればOKです。
ざっくりとコードの解説
今回の実装で鍵となるコードは、ざっくり下記の3つですね。
- パックカードのリスト
- カードのランダム抽選をするメソッド
- OpenPackメソッド
こちらをサクッとだけ説明していきますね。
①パックカードのリスト
public List packCardList = new List() { 0, 1, 2, 3 };
「このパックではカードIDが0〜3のカードが登場しますよー」っていう、
パックに入っているカードIDのリストですね。
パックによって出現させるカードを変えたい!って場合はこのリストを変更させればOKです。
②カードのランダム抽選をするメソッド
コードで言うとこれですね。今回の肝です!
1 2 3 4 5 6 |
// カードのIDをランダムで決めるメソッド int decisionCardId() { int randomCardId = packCardList[Random.Range(0, packCardList.Count)]; return randomCardId; } |
ただやってることはシンプルで、雑に和訳するとこんな感じ!
「randomCardId」って変数に、packCardListのランダム番目の数字を入れます!
int randomCardId = packCardList[Random.Range(0, packCardList.Count)];
そんで、randomCardIdの値を返します!
return randomCardId;
なのでこのメソッドを実行すると、
packCardListに書かれているカードのIDをランダムに教えてくれる!
と言う感じですね。
③OpenPackメソッド
これも雑に訳すとこんな感じですね。
public void OpenPack()
{
// 8枚カードを生成する
for (int i = 0; i < 8; i++)
{
【意訳】変数cardIdにdecisionCardIdメソッドの値を代入
int cardId = decisionCardId();
【意訳】CreateCardメソッドで変数cardIdのIDのカードを生成
GameManager.instance.CreateCard(cardId, openedCardTrans);
}
}
今までOpenPackメソッドはFor文の中に
CreateCard(1,openedCardTrans)みたいな記載で、指定した固定の値が入っていたけど、
それが「decisionCardId」ってランダムな値を返すメソッドを使うことで、
ランダムな値のカードを生成することが出来るようになった!と言う感じです!
手順②:パックをクリック時にカードを生成させる
それでは最後に「パックをクリックしたらカードを生成する処理」の実装にいきましょう!
この手順でやることは、この辺り!!
- ゲームを開始したらパックを作成させて、
- パックをクリックしたらOpenPackメソッドを動かしてカードを生成する。
- そのあとパックは削除させる。
完成形はこんな感じ。
パックがまず生成されて、、
クリックしたら、ランダムな種類のカードが8枚生成された!パックも消えてる!!
では完成形が分かったところで実装していこう!!
スクリプトの作成
次に書いていく処理はパック特有の処理になるので、
また新しいスクリプトを作っていきます。
「PackController」って名前でスクリプトを新規作成。
スクリプトの記載
コードを書く前に、記載する内容について説明していきます!
今回実装したい処理はプログラム的に言うと下記ですね。
- ゲームを実行したらPackプレハブを生成
- Packプレハブをクリックしたら、下記の処理を実行させる
- クリックを検知する
- OpenPackメソッドを実行する
- Packプレハブを破壊する
①については、
OpenPackManagerスクリプトのStartメソッドに
パックを生成してくれるコードを書けば良さそうですね。
②については、
Packプレハブがクリックされたことを検知してもらう必要がありそうです。
それを実現するために作ったスクリプトが「PackController」です。
このスクリプトに「こいつがクリックされたらこんな処理(カード生成とパックの破壊)をしてー」っていうコードを書いていきます。
これをPackプレハブにアタッチすることで、
「クリック検知!処理を実行します!!」ってやらせるイメージです。
コードの記載、変更
それでは説明した内容を念頭に置きながら、
「OpenPackManager」スクリプトのハイライト箇所を変更しましょう。
1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 |
(省略) public class OpenPackManager : MonoBehaviour { (省略) private void Start() { CreatePack(); } // パックを作成するメソッド void CreatePack() { // PackPrefabを作成する Instantiate(cardPackPrefab, cardPackTrans); } (省略) } |
「PackController」スクリプトは下記を丸ごとコピペしましょう。
1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19 20 21 22 23 24 25 26 27 28 29 30 31 32 |
using System.Collections; using System.Collections.Generic; using UnityEngine; using UnityEngine.EventSystems; public class PackController : MonoBehaviour, IPointerClickHandler { // クリックしたときに実行される処理 public void OnPointerClick(PointerEventData eventData) { OpenThisPack(); } // カードを生成して、パックを破壊する void OpenThisPack() { // OpenPackManagerを取得 OpenPackManager openPackManager = GameObject.Find("OpenPackManager").GetComponent<OpenPackManager>(); // Cardを生成する openPackManager.OpenPack(); // Packオブジェクトを破壊する DestroyPack(); } // Packオブジェクトを破壊する void DestroyPack() { Destroy(this.gameObject); } } |
Unity側の設定
下記の手順でCardPackプレハブにスクリプトをアタッチしましょう。
- CardPackプレハブを選択して、OpenPrefab。
- AddComponntをクリックして、PackControllerをアタッチする。
ゲームの実行
ではゲームを実行してみましょう!!
パックがまず生成されて、、
クリックしたら、ランダムな種類のカードが8枚生成された!!
と言う感じです!
コード解説
最後に追加したコードの解説をしていきます。
鍵になるのはPackプレハブにアタッチした「PackController」スクリプトの処理ですね。
コード内容の説明の時に、
「パックがクリックを検知するようにしましょー」って書きましたけど、
その処理をしてるコードが下記の「OnPointerClick」メソッドです。
1 2 3 4 5 |
// クリックしたときに実行される処理 public void OnPointerClick(PointerEventData eventData) { OpenThisPack(); } |
基本的には「OnPointerClick」メソッドを書いて、それをオブジェクトにアタッチしとけばクリック時に処理を起こさせることが出来るようになるよ!!って認識でOK。
※ちなみに「OnPointerClick」メソッドを使う時には「IPointerClickHandler」を継承する必要あり。
そんでクリックされたらOpenThisPackメソッドが実行されて、
OpenPackメソッドを実行してカード生成して、
パックオブジェクトを破壊する!って処理ををしてるよ。
1 2 3 4 5 6 7 8 9 10 11 12 |
// カードを生成して、パックを破壊する void OpenThisPack() { // OpenPackManagerを取得 OpenPackManager openPackManager = GameObject.Find("OpenPackManager").GetComponent<OpenPackManager>(); // Cardを生成する openPackManager.OpenPack(); // Packオブジェクトを破壊する DestroyPack(); } |
※途中でやってる「OpenPackManagerを取得」の処理は、これをやらないと「PackController」スクリプトが「OpenPackManager」って何よ!!ってなるので、取得して教えてあげてる処理。
ではでは今回の実装は以上になります。
お疲れ様でした!( ´∀`)
【終わりに】カードのランダム生成
本記事も最後まで読んでいただきありがとうございました!!
機能的にはガチャの実装はほぼ完成したので、
一旦、解説記事的には終わろうかな??
と思ったのですが、開封時のカードの動きも付けたほうがそれっぽいな!
って思ったので、次回は開封時にカードが動く処理の実装解説をしていきます。
もし何かしら質問、要望があればコメントくださいな!
それではまた次回!!
【次の記事】
サイト更新お疲れ様です!いつも参考にさせてもらってますー
お疲れ様です!
白紙さんもいつもコメントありがとうございます!( ´∀`)
お疲れ様です。
ランダム生成まではうまくいったのですが
Packの生成がうまくいかず再生しても何もない状態になります。
インスペクターで指定しているものが変更入って不一致と表示されていたことが原因でした。
お騒がせいたしました。