こんにちは、みじんこと申します。
本記事では前記事から引き続き、Unityでのデッキ編成機能の実装方法を説明します。
そちらをまだ見ていない方は、実施後にこの記事に進んで頂けると良きかと思います!
本記事では下記の流れにて、カードゲームにおけるデッキ編成機能の実装方法を解説していきます。
※本記事では④のデッキ編成機能における「カードの移動処理の実装」のみ解説していきます。
- 前準備とカードの作成
- UIの作成、カードの生成実装
- カードの種類の実装
- カードの移動処理の実装
- デッキ編成機能の実装
- デッキ編成リスト機能の実装
本記事の完成形としてはこんな感じですね。
カードをドラッグして動かせるようにして、デッキに加わるようにしていきます!!
それでは早速やっていきましょう。
今回も張り切っていこう!!
Contents
【実装概要】本記事で実装する内容について
さて今回はカードの移動処理を実装していきますが、こんな流れにて実装していきます!
- コードの整理
- カード移動処理の実装
- ドロップ処理を実装
最初にちょっとだけ、コードを整理をして、
その後、カードを動かすためのコードを書いて、動かす処理を実装します。
最後に、デッキの場所にドロップしたらデッキにカードが生成する処理を実装。
という流れで進めていくよ!!
手順①:コードを整理する
さて、今後の作業をやっていくにあたって、
ちょっとコードを整理した方が良さそうなので、コードを整理していきましょう。
やることは「GameManager」スクリプトっていう、
ゲーム全体に関わる内容が書かれるスクリプトを作って、
そのスクリプトにCreateCardメソッドを移行してあげる。ってだけ!
新規スクリプトの作成
では、まずは新規のスクリプトを作りましょう!
名前は「GameManager」にしてね。
こんな感じの歯車マークのものが出来たら完成!!
※既に「GameManager」を作っている場合はそのままで大丈夫です。
これにコードを書いていくよ!
追記、修正するコードの説明
今回はコードを記載する前にちょっとだけ内容の解説をしていきます。
記載、変更する内容は下記になります!!
今回記載、変更するコードの内容について
■DeckEditManagerスクリプトの変更内容
- CreateCardメソッド削除
- GameManagerスクリプトへ移動するよ
■GameManagerスクリプトの記載内容
- CreateCardメソッド記載
- DeckEditManagerスクリプトから移動してくるよ
- Public化するよ(詳細は後述)
- シングルトン化(詳細は後述)
- 他のスクリプトから参照出来るようにしてる
シングルトン化、Public化ってなに??
※ちょっと長いから気になる人だけ読んで!!
ざっくりとだけ書きますが、下記のイメージでOKです。
- シングルトン化:「このインスタンスはこれ1つだけだよ!!」ってすること。
- ここでは他のスクリプトから参照出来るようにこの方法を使用。
- Public化:「他のスクリプトでも参照していいよ!」ってやること。
多分これだけだと、
なんでそんなことをする必要があるの??
って思うと思いますが、
基本的にC#は他のスクリプト(クラス)の内容を知れない。からです。
例えば、
スクリプトAに「変数 i=1」って書いてあっても、
スクリプトBはスクリプトAの変数iの値が分からないんです。
これを解決するために、
スクリプトAをシングルトン化(スクリプトの内容を他のスクリプトからも参照出来るようにしてあげる)して、変数iもPublic化してあげることで、
やっとこスクリプトBで変数iの値が「1だ!」って知れるイメージです。
今回で言うと「GameManager」に書いてあるCreateCardメソッドが
「DeckEditManager」から使えないので、
シングルトン化とPublic化してあげた。ってイメージを持って貰えれば完璧です。
※「そもそもなんで他のスクリプトの内容を参照出来ないの??」っていう疑問を持った方もいるかも知れないのでもうちょっとだけ答えると、C#がオブジェクト指向の言語だからです。
オブジェクト指向の考え方的に「何でもかんでも他のクラスから参照出来ちゃったら、ダメじゃない??」って言うのがあるので、こんな仕様になってます。
(これ以上のオブジェクト指向についての言及は避ける。。もっと知りたい人は自分で勉強なさい。笑)
まあひとまず今回の解説記事の中では、
シングルトン化とか、Public化とかって出てきたら
他のスクリプトから参照出来るようにしたのね
って理解してもらえればOK!!
まあとりあえず、
GameManagerスクリプトにCreatCardメソッドを移動したのね。
って理解でOK。
コードの記載
それでは先ほど解説した内容を念頭に置いたら、
GameManagerスクリプトを下記の内容に書き換えましょう。(丸ごとコピペする)
※既に「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 |
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) { CardController card = Instantiate(cardPrefab, trans); card.Init(cardId); } } |
コードの記載(DeckEditManager)
次は「DeckEditManager」スクリプトを丸ごと下記のコードに変更!!
※どこがどう変わったのかは、確認してからコピーしてね。
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 36 37 38 39 40 41 42 43 44 45 46 47 48 |
using System.Collections; using System.Collections.Generic; using UnityEngine; public class DeckEditManager : MonoBehaviour { // デッキカードの生成場所 [SerializeField] Transform deckCardTrans1; [SerializeField] Transform deckCardTrans2; [SerializeField] Transform deckCardTrans3; [SerializeField] Transform deckCardTrans4; [SerializeField] Transform deckCardTrans5; [SerializeField] Transform deckCardTrans6; [SerializeField] Transform deckCardTrans7; [SerializeField] Transform deckCardTrans8; [SerializeField] Transform deckCardTrans9; [SerializeField] Transform deckCardTrans10; [SerializeField] Transform deckCardTrans11; [SerializeField] Transform deckCardTrans12; [SerializeField] Transform deckCardTrans13; [SerializeField] Transform deckCardTrans14; [SerializeField] Transform deckCardTrans15; [SerializeField] Transform deckCardTrans16; // 所持カードの生成場所 [SerializeField] Transform stockCardTrans1; [SerializeField] Transform stockCardTrans2; [SerializeField] Transform stockCardTrans3; [SerializeField] Transform stockCardTrans4; [SerializeField] Transform stockCardTrans5; [SerializeField] Transform stockCardTrans6; private void Start() { // デッキ編成の画面をセットする SetDeckEditPanel(); } void SetDeckEditPanel() { GameManager.instance.CreateCard(0, stockCardTrans1); GameManager.instance.CreateCard(1, stockCardTrans2); GameManager.instance.CreateCard(2, stockCardTrans3); GameManager.instance.CreateCard(3, stockCardTrans4); GameManager.instance.CreateCard(2, stockCardTrans5); GameManager.instance.CreateCard(3, stockCardTrans6); } } |
コピーして保存出来たらOKです。次に進みましょう。
Unity側にアタッチする
続いてはUnity側の設定をしていきましょう。
- Hierarchyウィンドウ(Main Cameraとかあるところ)にて右クリックして、「Create Empty」をクリックして、それを「GameManager」に名称変更!!
- 「Add Component」で、GameManagerをアタッチする
- CardプレハブをGameManagerのところへドラッグ&ドロップ!
これでUnity側の設定は出来たので、次へ進みましょう!
ゲームを実行してみる
それではゲームを実行しましょう!
カードが6枚生成されてる!!
となってればOKです。
手順②:カードの移動処理を実装する
ではここから本番。
カードの移動処理を実装していきます!
でもやることは、
カードを動かすための処理のスクリプトを新規で作成して、
それをカードプレハブにアタッチすればOK!!ってだけ。
早速やっていきましょう!
スクリプトの作成と記載
まずはスクリプトを作っていこう!!
「CardMovement」スクリプトを新規で作成。
※これも既に「CardMovement」を作っている場合はそのままで大丈夫です。
このスクリプトにカードが移動する処理を書いていくよ。
CardMovementコードの記載と解説
次はコードの記載をしましょう。
ハイライト箇所に注目して追記、変更。(丸ごとコピペでもOK)
※既にコードが書かれている場合は、丸ごとコピペすると今までの実装が消えちゃうので、ハイライト部分を追記、変更してください!!(分かりづらかったらコメントして!)
1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19 20 21 22 23 |
using System.Collections; using System.Collections.Generic; using UnityEngine; using UnityEngine.EventSystems; public class CardMovement : MonoBehaviour, IDragHandler, IBeginDragHandler, IEndDragHandler { public void OnBeginDrag(PointerEventData eventData) // ドラッグを始めるときに行う処理 { Transform canvas = GameObject.Find("Canvas").GetComponent<Transform>(); transform.SetParent(canvas, false); } public void OnDrag(PointerEventData eventData) // ドラッグした時に起こす処理 { transform.position = eventData.position; } public void OnEndDrag(PointerEventData eventData) // カードを離したときに行う処理 { Destroy(this.gameObject); } } |
CardMovementコードの解説
今追記したハイライト部分をざっと解説していきます。
ざっくり言うと大事なのは下記の3つです。
- OnBeginDragメソッド(カードをドラッグし始めた時の処理)
- OnDragメソッド(ドラッグ中の処理)
- OnEndDragメソッド(ドラッグし終わった時の処理)
それぞれメソッドの処理を見ていきましょう。
■OnBeginDragメソッドの解説
1 2 3 4 5 |
public void OnBeginDrag(PointerEventData eventData) // ドラッグを始めるときに行う処理 { Transform canvas = GameObject.Find("Canvas").GetComponent<Transform>(); transform.SetParent(canvas, false); } |
カードをドラッグし始めた時に実行されるメソッドです。
そのまま動かすだけだと、
こんな感じ↓に動かしてるカードが別のカードの後ろに表示されたりするので、
カードの親要素をCanvasにして、一番上に表示されるようにしてます!(SetParent(canvas, false))
■OnDragメソッド
1 2 3 4 |
public void OnDrag(PointerEventData eventData) // ドラッグした時に起こす処理 { transform.position = eventData.position; } |
今回一番重要なのが、こちらの「OnDrag」メソッド。
ドラッグ中に実行されるメソッドですね。
ドラッグしてる間は、
transform.position(カードの場所)を
eventData.position(マウスポインターの場所)にする。
っていう処理をしてるから、カードが動かせる。ってことですな。
■OnEndDragメソッド
1 2 3 4 |
public void OnEndDrag(PointerEventData eventData) // カードを離したときに行う処理 { Destroy(this.gameObject); } |
最後はドラッグし終わった時のメソッドですね。
Destroy(this.gameObject)なので、
ドラッグし終わったら、このカードオブジェクトは破壊しちゃってね。って処理!
■〜Handlerについて
次はクラス名の後ろに書いてあるIDragHandlerとかについての説明。
ここね↓
1 |
public class CardMovement : MonoBehaviour, IDragHandler, IBeginDragHandler, IEndDragHandler |
さっき説明した「OnDrag」メソッド等を使う時は、この「〜Handler」書かないと使えないよ。
って認識でOK。
それぞれ以下に対応してるよ↓
【クラス名】 | 【メソッド名】 |
---|---|
IDragHandler | OnDragメソッド |
IBeginDragHandler | OnBeginDragメソッド |
IEndDragHandler | OnEndDragメソッド |
表の右のメソッドを使うには、対応したクラスを書く必要があるって理解でOK!!
unityengine.eventsystemsについて
最後にこれ↓
1 |
using UnityEngine.EventSystems; |
これは単に、〜Handlerとかを使う為に書く必要があるもの。
って認識でOK
これを書かないと使えないので書きましょう。ってだけです!
CardControllerコードの記載と解説
さて、今しがたCardMovementスクリプトを作りましたが、
CardViewと同じようにCardControllerスクリプトから管理出来たほうが便利なので、
CardControllerスクリプトも修正していきましょう。
CardControllerスクリプトにハイライト箇所を追記。
1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19 20 21 22 |
using System.Collections; using System.Collections.Generic; using UnityEngine; public class CardController : MonoBehaviour { public CardView view; // カードの見た目の処理 public CardModel model; // カードのデータを処理 public CardMovement movement; // カードの動きを処理 private void Awake() { view = GetComponent<CardView>(); movement = GetComponent<CardMovement>(); } public void Init(int cardID) // カードを生成した時に呼ばれる関数 { model = new CardModel(cardID); // カードデータを生成 view.Show(model); // 表示 } } |
これは説明するまでもなく、
CardControllerからCardMovementを扱えるようにしただけですね。
Unity側の設定
CardプレハブにもCardMovementをアタッチしましょう。
(若干画像が違うけど、問題ないのでお気になさらず!)
※これも既に「CardMovement」がアタッチ済みの場合はそのままで大丈夫です。
- Cardプレハブをクリックして、OpenPrefabして開く
- AddComponentでCardMovementをアタッチ
これで設定は完了です!!
ゲームの実行
それではゲームを実行していきましょう!
まずカードが出てきて、、
カードをドラッグしたら動いた!!
そんで離したら消えた!!
ってなればOKです!!
手順③:ドロップ処理の実装
さて、カードの移動は出来るようになったけど、
動かしたらカード消えちゃうじゃん。。
って感じなので、デッキの場所にドロップしたら
デッキの場所にカードを生成するような処理を実装しましょう!
完成系はこんな感じですね。
ゲームを実行したら、カードが出てきて、、
カードが動いて、、
デッキの場所にドロップしたら、カードがデッキに加わった!!
みたいな感じ。
ではこれを実装していきましょう!!
スクリプトの作成
まずはドロップする場所用のスクリプトを作ります。
名前を「DropDeckCardPlace」で新規に作成!
Unityの設定
お次はUnity側の設定。
画像通りに進めてね。
- Panelを新規で作成して、名前を「DeckDropPanel」にする。
- パラメータを変更
- さっき作った「DropDeckCardPlace」スクリプトをAdd Componentで追加!
Cardプレハブもちょっと設定変更しましょう。
- CardプレハブをOpenPrefabして開く
- 「Canvas Group」をAdd Componentで追加!
今カードにアタッチした「Canvas Group」は、
BlocksRaycastsの設定をいじれるようする為にアタッチしてるよ。
BlocksRaycastsについて
Blocks Raycastsってなんだ??!
レイキャストをブロックするかどうかのパラメータのこと!
もっと砕けて言うと、
ポインターから出てるビームが当たってる判定するか、
当たってない判定とするかっていうパラメータのこと!!
これはドロップ判定のために必要な機能なのですが、
いきなりドロップ判定の説明をするとややこしいので、
一旦、カードが動く処理についてちょいと説明しますね。
カードに向かってボタンを押すと、マウスポインターからカードに向かってビームが出ます。
そのビームが当たって、そのまま動き出すと、
カードが「なんか動き出した(`・ω・´)」ってなるのがドラッグの判定です。
逆に言うと、カードに
カードにビームの当たり判定(Blocks Raycasts)なんて、いらんぞい!
ってことで、ビームの当たり判定をオフ(Blocks Raycasts=off)してしまうと、
カード自体にポインターが当たっても、
「そんなの知りません(・Д・)」って顔されて、ドラッグの判定をされないって訳です。
さて本題に戻ると、
ドロップ処理もドラッグ判定と同じように、ポインターのビームでドラッグ判定を行ってます。
でも今のままだと、カードを動かせはしますが、
カードがずっとポインターのビームを「ブロックじゃ٩( ‘ω’ )و」って邪魔して、
カードより下にあるドロップした場所までビームが届きません。
なので、カードをドロップしても、
ドロップをした場所的には「ビームなんて届いてません(・Д・)」って顔される訳です。
実装したい人
じゃあどうすればいいのよ!!
となるので、
カードをドラッグし始めたらBlocks Raycastsの値をオフにして、
カードがビームを邪魔しないようにして、
ドロップした時に「DeckDropPanel」にビームを届ける!!
ってな処理をコードで実装していくよ!!
コードの記入
まずは「CardMovement」スクリプト。
やりたいことは、
カードをドラッグし始めたらBlocks Raycastsの値をオフにすることなので、
ハイライト部分を追記!!
1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19 20 21 22 23 24 |
using System.Collections; using System.Collections.Generic; using UnityEngine; using UnityEngine.EventSystems; public class CardMovement : MonoBehaviour, IDragHandler, IBeginDragHandler, IEndDragHandler { public void OnBeginDrag(PointerEventData eventData) // ドラッグを始めるときに行う処理 { Transform canvas = GameObject.Find("Canvas").GetComponent<Transform>(); transform.SetParent(canvas, false); GetComponent<CanvasGroup>().blocksRaycasts = false; // blocksRaycastsをオフにする } public void OnDrag(PointerEventData eventData) // ドラッグした時に起こす処理 { transform.position = eventData.position; } public void OnEndDrag(PointerEventData eventData) // カードを離したときに行う処理 { Destroy(this.gameObject); } } |
次に「DeckEditManager」スクリプトに、メソッドを追記!!
1 2 3 4 5 6 7 8 9 10 11 12 |
using System.Collections; using System.Collections.Generic; using UnityEngine; public class DeckEditManager : MonoBehaviour { (省略) public void SetDeckCards(int cardId) { GameManager.instance.CreateCard(cardId, deckCardTrans1); } } |
※指定されたIDのカードをdeckCardTrans1に生成する。ってだけのメソッド。
最後に「DropDeckCardPlace」スクリプトにドロップされた時の処理を書いていく!!
下記のコードを全部コピペしましょう。
1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 |
using System.Collections; using System.Collections.Generic; using UnityEngine; using UnityEngine.EventSystems; public class DropDeckCardPlace : MonoBehaviour, IDropHandler { public void OnDrop(PointerEventData eventData) // ドロップされた時に行う処理 { CardController card = eventData.pointerDrag.GetComponent<CardController>(); // ドラッグしてきた情報からCardMovementを取得 if (card.movement != null) // もしカードがあれば、 { DeckEditManager deckEditManager = GameObject.Find("DeckEditManager").GetComponent<DeckEditManager>(); deckEditManager.SetDeckCards(card.model.cardId); } } } |
もしカードがドロップされてきたら、
そのカードのIDをSetDeckCardsメソッドに渡して、デッキにカードを生成するよ!!
ってな処理ですな。
ゲームの実行
それではゲームを実行しましょう!!
カードが出てきて、、
カードが動く!
デッキの場所にドロップしたら、カードがデッキに加わった!!
ってなればOK!!
今回の実装はここまでです!
最後までお疲れ様でした( ´∀`)
【終わりに】カード移動処理とドロップ処理の実装
ひとまずデッキ編成の基礎は作れたかと思うので、一旦解説はここまでになります。
皆さま、ここまでお疲れ様でした!!!
ここから先は応用編ということで、別の記事での解説になります。
応用編の記事では、
最終的にはこんな感じのゲームが作れるように解説をガリガリ進めていくので、
ぜひぜひ一緒にやっていきましょう!!
※今まで作ってきたデッキ編成機能に加えて、
別の記事にて解説しているガチャ(パック開封)機能の応用編も含んだ内容になっています。
ここまで一緒にやっていただけた方なら、満足頂ける内容かと思いますので、
ご興味ある方は引き続きよろしくお願いします!
ではでは、改めてこの記事を最後まで読んでいただきありがとうございました!!
感想などコメント貰えると喜びます( ´∀`)
それではまた別の記事で会いましょう!!
【デッキ編成機能&ガチャ(パック開封)機能の応用編の解説記事】
続きの実装解説記事はこちらになります!!
※有料記事になりますが冒頭部分は読めるので、ちょいと覗いてくださいな!
ちなみにまだガチャ機能の実装をしてない方は、こちらの実装もしてみてくださいな!!
こんにちは!
ここまで解説の通りにしたのですがカードをドラッグしようとするとカードが消えるという現象で立ち止まっています•••
んー、記事通りに実施出来ていれば出来るとは思うので、
もう一度確認してもらえますか??
それでももしダメそうなら、
記事のどの部分のコードを書いたら、
どんなエラーだったり、どんな状態になるのかを教えていただければお力になれるかと、、!
それがエラーは一切起きてなくて正常に動くんですよね•••試しにOnDragとOnEndDragにデバッグログを追加したところ、ドラッグの処理もカードを離した時の処理も正常に動いててドラッグをしたらカードが消えてしまうんですよね
Unityのバージョンは2022,2,19f1です。
んー、OnBeginDragの処理がうまく行ってないんですかね、、
一旦、OnBeginDragの中の処理を全部コメントアウトしてみたら、
どうなるか確認してみてもらってもいいですか??
OnBeginDragの処理をコメントアウトした上で実行したところ、挙動は変わらずにドラッグしようとした瞬間にカードが消えました。
んー、記事に書いてない何かしらの設定を変更したりしました、、?
座標とか、カメラとかその辺りの設定が変わってる感がします。
もしかしたら作り直した方が早いかもですね。。
Canvasのレンダーモードをスクリーンスペース-カメラからスクリーンベース-オーバーレイに変更したところ、直りました!ここの設定が悪さをしていたようです。
おー、解決出来たみたいでよかったです!
やっぱりカメラの設定だったんですね。_φ(・_・ メモメモ
お疲れ様です!
Packとデッキ編集画面はここまで完成しました!
応用編お待ちしております!
最後までお疲れ様です!
応用編はもう少々お待ちください!
こんにちは
カードを画面に出すとこまではできたのですが画像がよみこまれません
どうすればいいでしょうか
無事解決しました!!!
自己解決出来たようで良かったです!!!
ここできくべきかわからないんですが、
ゲームを再戦するとゲームが動かず、カードが一枚も出てこなくなりました
どうすればいいかお力添えをお願いします
この記事のことでしたら、
全然ここでコメント頂いて大丈夫ですよー!
ゲームが動かなくなったのは、この記事のどの部分(手順)ですかね??
ちなみに動かない時にエラー等は出てますか?