こんにちは、みじんこと申します。
本記事では前記事から引き続き、Unityでのオンライン対戦機能の実装方法を説明します。
そちらをまだ見ていない方は、実施後にこの記事に進んで頂けると良きかと思います!
本記事では下記の流れにて、カードゲームにおけるオンライン対戦機能の実装方法を解説していきます。
※本記事では②のオンライン対戦機能における「UIの作成、カードの生成実装」のみ解説していきます。
- 前準備とカードの作成
- UIの作成、カードの生成実装
- カードの種類の実装
- カードの移動処理の実装
- カードバトル処理の実装
- リーダーへの攻撃処理の実装
- オンライン機能の導入と実装
本記事の完成形としてはこんな感じですね。
オンライン対戦のカードバトルにおいて必要な要素を作成して、前回作ったカードプレハブを画面に出現させています。
ただ今回は前回と違ってコードを書いていきます。
でもプログラム恐怖症の方、安心してください。
コピペでOKです。もはや1文字も打たなくても出来ます。
それでは今回も頑張っていきましょう!!
Contents
【実装概要】本記事で実装する内容について
それではまずは
今回実装する内容と、その実装の流れについて
整理してから始めましょう。
いきなりガリガリと作り始めることも出来ますが、
最初にやることを明確にしてから作り始めるのといきなり始めるのでは、
進捗も理解度も段違いに違います。
しっかりとやることを踏まえてから先に進みましょう!
今回実装する内容について
では今回実装していく内容は下記の2つです。
- 対戦画面のUIの作成
- カードを生成する処理の実装
① 対戦画面のUIの作成
ここでは、オンライン対戦時に必要になる対戦画面の要素をUnity上で作っていきます!
前回カードを作ったやり方と同じ感じなので、難しくないはず!
② カードを生成する処理の実装
ここでは、前回作ったカードプレハブをコードにてゲーム上に生成していきます。
コードとは言っても、全然難しいものではないので安心して進んでくださいな!
作っていく流れとしては、こんな感じ↓
- 新規のスクリプトを作る
- コードを書く
- ゲームを実行する
覚える必要はないので、なんとなく「こんなふうに進めるのねー」って理解でOK!
最後には理解度を確かめる演習を入れているので、理解しながら進めてね!
それでは今回やっていく内容をなんとなく頭に入れたら、実装に入っていきましょう!
(/*´∀`)o レッツゴー
手順①:対戦画面のUI作成
手順①の完成形はこれです。
下記の5つの要素を、自分と敵の分作っていきます!!
- フィールドの場所
- 手札の場所
- リーダーの画像
- HPテキスト
- ターンエンドボタン
覚える必要はないので、なんとなく「これに向かって作ってるんだなー」と思ってもらえていればOKです。
※あくまでここで作っていくUIは見え方の問題なので、全部の値が記事通りになっている必要はないです。
適宜、変えてもらっても問題ありません!!(ただし、初心者の方はそのまま作るの推奨)
1-1.カード生成場所の設定
それでは早速、UIの作成をやっていきましょう。
まずは自分のフィールドを作っていきます!
画像の通りに作っていきましょう。
- 「Canvas」を右クリック(Canvasがなかったら、左上の「+」をクリックでOK)
- 「UI」をクリック
- 「Panel」をクリックして、Panelを作成しよう
今作ったPanelを元にして作っていくよ。
- 「Panel」の名前を「PlayerField」に変更する
- 「PlayerField」のパラメータを変更する
次は敵のフィールドを作りましょう。
- 「PlayerField」をコピぺして、その名前を「EnemyField」に変更
- パラメータを画像通りにする
お次は自分の手札の場所を作りましょう!
- 「PlayerField」をコピぺして、その名前を「PlayerHand」に変更
- パラメータを画像通りにする
次は敵の手札の場所を作りましょう!
- 「PlayerHand」をコピぺして、その名前を「EnemyHand」に変更
- パラメータを画像通りにする
次はターンエンドのボタンを作りましょう!
- 「Canvas」を右クリック、「UI」をクリック、「Button」を選択
- 名前を「TurnEndButton」に変更
- パラメータを画像通りにする
続けてターンエンドボタンの文字を修正していきましょう。
- 「Text」を選択
- パラメータを画像通りにする
次はリーダーパネルを作っていきましょう!
- 新しくPanelを作成して、その名前を「PlayerLeader」に変更
- パラメータを画像通りにする
- 「AddComponent」を押して、「Mask」を追加
- こんな感じのが張り付いたらOK!!
Maskってなんだよ!!
って人は、後で説明するので一旦気にしないでくださいな!
そしたら、今作ったパネルに画像を付けていきましょう!
まあ画像はなんでもいいけど、今回は以下の画像を使っていくよ。
こいつをダウンロードしたら、Unityの設定に戻ろう。
- 「PlayerLeader」の中にImageを追加
- さっきの画像を使って、パラメータを画像通りにする
さて、さっき説明を飛ばした「Mask」についてですが、
「Mask」とは要は、
アタッチした物の中にある物を、アタッチした物の形に切り取るよ。
って認識でOKです。
もっと具体的に説明すると、もし「PlayerLeader」に
Maskが付いてないと、左のようにリーダー画像が全身表示されちゃうけど、
Maskが付いてる(アタッチされてる)と、右のように「PlayerLeader」の形に切り取られる。
ってことですな!!!
では敵さんにもリーダーパネルを作成してあげましょう。
- 「PlayerLeader」をコピぺして、その名前を「EnemyLeader」に変更
- パラメータを画像通りにする
では最後の要素であるプレイヤーのHPを作りましょう。
- テキストを新規作成して、名前を「PlayerHPText」に変更
- パラメータを画像通りにする
そしたら敵のリーダーのHPも作りましょう!
- 「PlayerHPText」をコピペして、「EnemyHPText」を作成
- パラメータを画像通りにする
これで要素の作成完了です!!
ただ背景の色がちょいと気に入らないので、黒に変えておきましょう。
- 「MainCamera」を選択
- カラーを黒にする
これで一旦、UIの作成は完了です!!
ここまでお疲れ様でした!!!
慣れないUI作成でちょいとお疲れかと思いますので、
ひと休憩してから次に進みましょう!!
手順②:新規スクリプトの作成
次はコードを書いてカードを生成していきます!!
でもその前に、何をするコードを書いているのかイメージして欲しいので、
一旦、Unity画面上でカードを生成するとはどんな感じなのかをやってもらいます!
画像の通りに進めてください。
- CardプレハブをPlayerHandにドラッグ&ドロップして、PlayerHandの中にCardを作る
- PlayerHandの場所にカードが表示されたらOK!
これからコードで実装するのは、
今、手でやったように「CardプレハブをPlayerHandの場所に作る。って処理なんだな!」
って認識を持ってもらえればOKです!!
※いま画面上に作ったカード自体はいらないので、削除しておいてください!
2-1.新規スクリプトの作成
それでは、まずはコードを書くスクリプト用のフォルダを作りましょう。
Assetsフォルダ配下に「Scripts」って名前で作成。(すでにある場合はそれでOK)
下記の画像通りに進めて新規スクリプトを作成しましょう。
- Scriptsフォルダの配下で右クリックをして、「Create」をクリック
- 「C#Script」をクリック
- 「GameManager」って名前にしましょう。
スクリプトを新規作成するときに名前を変更する前にエンターを押してしまうと、デフォルトだと「NewBehaviourScript」って名前でスクリプトが作られてしまいます。
後から変更も出来なくはないですが、可能な限りエラーの起きないように進めたいので、もしデフォルトのままの名前で一瞬確定してしまったな。って場合は、一度それを消して、新しくスクリプトを作り直した方がいいです。
こんな感じのものが出来たら完成!!
これにコードを書いていくよ!
2-2.コードの記入
それでは早速コードを書いていきましょう!
さっき作った「GameManager」スクリプトをダブルクリックしましょう。
そしたらこんな感じの画面が出てくるので、プログラミング恐怖症の方は恐れ慄いて、三度の飯よりプログラミング大好き変態人間はワクワクしてください。(しなくていいです笑)
そしたらそこに書いてある文字列は全部消していいので、
下記のコードを全部コピーして、そのスクリプトに貼り付けちゃってください!
1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 |
using System.Collections; using System.Collections.Generic; using UnityEngine; public class GameManager : MonoBehaviour { [SerializeField] GameObject cardPrefab; // カードプレハブ // カードの生成場所 [SerializeField] Transform playerHand; private void Start() { // cardPrefabをPlayerHandに生成する Instantiate(cardPrefab, playerHand); } } |
無事に貼り付けられましたかね??
貼れたら保存して、次に進みましょう!
コード解説コーナー
ここからは今回記入したコードについて、ざっくりと説明をしていきます!
今回記入したコードは下記のコードで、
ハイライトされた箇所が今回の大事な箇所になるので注目してみましょう。
1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 |
using System.Collections; using System.Collections.Generic; using UnityEngine; public class GameManager : MonoBehaviour { [SerializeField] GameObject cardPrefab; // カードプレハブ // カードの生成場所 [SerializeField] Transform playerHand; private void Start() { // cardPrefabをPlayerHandに生成する Instantiate(cardPrefab, playerHand); } } |
■[SerializeField]〜の箇所について
まずは下記の2行の説明から。
[SerializeField] Transform playerHand; // カードの生成場所
すごくざっくりと書きますが、一旦この2行はこの理解で大丈夫です。
Unity上で設定出来るようにしますよ GameObject型の cardPrefabって変数を
[SerializeField] GameObject cardPrefab;
Unity上で設定出来るようにしますよ Transform型の playerHandって変数を
[SerializeField] Transform playerHand;
この説明で何となくでも分かった方は次に進んでOKです。
何を言ってんでい??
って方だけ聞いてください。
【補足】変数と型、SerializeFieldについて
一旦、「GameObject cardPrefab」の説明をします。
「GameObject型のcardPrefabって変数」って書いてる部分ですね。
雑に言うと、「『GameObject型』のものだけを入れられる『cardPrefab』って名前の箱を作る。」ってことです。
もっと雑に言います。「食べ物 美味しいものA」って書いてあったら、
「『食べ物型』のものだけを入れられる『美味しいものA』って名前の箱を作る。」ってことです。
試しにこの『美味しいものA』の中に、クロワッサンを入れてみましょう。
『美味しいものA』をおくれ
って人には、『美味しいものA』の箱の中に入っているクロワッサンを渡してあげる。ってことです。
勝手にお寿司とか、焼肉を渡してはダメですよ。
中に入っているクロワッサンをあげてください。
逆に言えば、箱の中にだし巻き卵が入っていたら、だし巻き卵をあげてください。
このように変数っていうのは、同じ「美味しいものA」でも、箱の中に入ってるものが変われば内容が変わります。だから『変わる数』で『変数』なんですね。
ちなみに『美味しいものA』の箱の中に「車」とか「エッフェル塔」を入れることは出来ません。
もちろん大きさの問題ではありません。
『美味しいものA』の箱は『食べ物型』だからです。食べ物しか入りません。
どうしても「車」とか「エッフェル塔」を変数に入れたかったら、
「乗り物型 乗り物A」とか
「建物型 好きな塔」って変数を別に定義してください。
このように、変数という箱に入る内容を決めるのが『型』って認識でOKです。
そして最後に「この箱に何を入れるかをコード上ではなくてUnity上で設定しますよ!」っていう宣言が「SerializeField」の意味ですな。
変数:何かしらが中に入る箱のこと
型 :変数(箱)にどんなものを入れられるか決めるもの
SerializeField:Unity上で設定出来るようにしますよーって宣言
■Startメソッドの箇所について
最後にStartメソッドについて!!
private void Start()
{
// cardPrefabをplayerHandに生成する
Instantiate(cardPrefab, playerHand);
}
これは割と書いてあるまんまだけど、
カードをplayerHandって場所に生成しちゃうよ。
って処理が、
Startメソッド(ゲームを実行すると勝手に最初に実行される処理)に書いてあるよ。
ってだけ!
要はゲームを開始したら、カードをplayerHandに生成するよ。って書いてるだけ。
【補足】メソッドって何だい??
メソッドって言われたら「詠唱破棄ね」と思えばOK(BLEACH知らない人ごめん)
もう少しちゃんというと「コードがまとまった処理のことね」でOK。
例えばあなたは今、
あんぱんとメロンパンと明太フランスパンが欲しいとします。
この場合、
あんぱんと
メロンパンと
明太フランスパンを買ってきて
って言うしか無いです。
でもこんなコードがあったら、
void パン買ってきて
{
あんぱんを買う;
メロンパンを買う;
明太フランスパンを買う;
}
パン買ってきて
って言うだけで、
あんぱんとメロンパンと明太フランスパンを買ってきて貰えます。
なんて便利!!
これが「パン買ってきて」メソッド(関数)と言います。
2-3.Unity側の設定
それではコードを書いたはいいですが、
コードを書いただけではUnity上では動かないのでUnity側の設定をしていきましょう。
まずはHierarchyビューにて右クリックして、「Create Empty」をクリックしましょう。
そしたら「GameObject」ってものが出来ます。
今作った「GameObject」を使って、作業を進めます。
- 「GameObject」を「GameManager」に名前を変更
- 「Add Component」をクリックして、「GameManager」を選択してアタッチする
- 「GameManager」のCardPrefabのところに、以前作ったCardプレハブをドラッグ&ドロップする
- 「GameManager」のPlayerHandのところに、「PlayerHand」をドラッグ&ドロップする
若干ややこしいけど、出来ましたかね??
出来たらゲームの実行に進みましょう!!
2-4.ゲームの実行
ではではゲームを実行しちゃいましょう!(真ん中の「▶︎」ボタンをクリック!)
カードが出てきた!!
ってなればOKです!
今の流れをまとめるとこんな感じ!!
- コードにて、下記の処理を記載
- カードを生成する場所の記載([SerializeField] Transform 場所の名前)
- カードを生成するコードの記載(Instantiate(cardPrefab, カードを生成する場所))
- Unity上で、コードに対して場所をアタッチ(ドラッグ&ドロップ)する
2-4.カードの重なりの修正
じゃあカード生成も出来たし、次に進むぞい!!
と言いたいところだけど、
今のままだとちょっと問題があるのでそこの修正をしていきましょう。
その問題が何かというと、説明するより実際見た方がわかりやすいので実際に見てみましょう。
さっき書いたコードに下記のハイライト行を追記してみてください!
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; public class GameManager : MonoBehaviour { [SerializeField] GameObject cardPrefab; // カードプレハブ // カードの生成場所 [SerializeField] Transform playerHand; private void Start() { // cardPrefabをPlayerHandに生成する Instantiate(cardPrefab, playerHand); Instantiate(cardPrefab, playerHand); } } |
やってることは「プレイヤーの手札にもう一枚カードを生成しますよ!」ってだけですね。
これで手札にカードが2枚できるはず!!
ということで、ゲームを実行しましょう!
カードが1枚しか生成されないんだが???!!
ってなるかと思いますが、これは
カード自体はちゃんと2枚生成されてるけど「カードが重なって表示されている」のが原因です!
というわけで、うまい感じにカードをずらして表示してくれる機能を使っていきましょう。
- 「EnemyHand」〜「PlayerHanad」を選択(自分の手札以外もずらして表示させたいため)
- AddComponentをクリックして、「Horizontal Layout Group」を追加
- パラメータを画像通りに変更
ちなみに「Horizontal Layout Group」っていうのは、
子要素を均等に横並びにしてくれる便利なコンポーネントのこと!!
今、設定した値に沿って子要素の並び方が変わるよ。
さてこれでもう一度ゲームを実行してみましょう!!
こんな感じにカードが2枚表示されるようになったよね??
こうなればOKです!!
【演習】カードの生成
それでは続けて他の場所にもカードの生成をやっていくんですが、
ほぼ今やったやり方を流用すれば出来るので、演習としてやっていきましょう!
今回の演習はゲームを開始したら、下記のこの画面になるようにやってみてください!
自分の手札にカードが2枚、フィールドに4枚、敵の手札とフィールドに3枚のカードが生成されてる状態ですね。
初めてコードに触れた方はちょっと難しいかもしれないけど、今回の内容が分かっていれば出来るはず!!
出来るか不安でもまずはトライしてみましょ (/・ω・)/ レッツトライ‼︎
【答え合わせ】カードの生成
ではでは皆さま出来ましたかね?!
これが出来てれば、今回の内容はバッチリ理解出来てます!
もし出来なくてもこの記事を読む前より、出来るようになったことはあるはず!
一歩づつ前進です!!
それでは早速答え合わせしていきましょ。
この流れでやっていきます。
- コードにて、下記の処理を記載
- カードを生成する場所の記載([SerializeField] Transform 場所の名前)
- カードを生成するコードの記載(Instantiate(cardPrefab, カードを生成する場所))
- Unity上で、コードに対して場所をアタッチ(ドラッグ&ドロップ)する
①コードの記入
記載するコードは下記になります!
ハイライト部分が今回の演習の肝です。
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 |
using System.Collections; using System.Collections.Generic; using UnityEngine; public class GameManager : MonoBehaviour { [SerializeField] GameObject cardPrefab; // カードプレハブ // カードの生成場所 [SerializeField] Transform playerHand; [SerializeField] Transform playerField; [SerializeField] Transform enemyHand; [SerializeField] Transform enemyField; private void Start() { Instantiate(cardPrefab, playerHand); Instantiate(cardPrefab, playerHand); Instantiate(cardPrefab, playerField); Instantiate(cardPrefab, playerField); Instantiate(cardPrefab, playerField); Instantiate(cardPrefab, playerField); Instantiate(cardPrefab, enemyHand); Instantiate(cardPrefab, enemyHand); Instantiate(cardPrefab, enemyHand); Instantiate(cardPrefab, enemyField); Instantiate(cardPrefab, enemyField); Instantiate(cardPrefab, enemyField); } } |
やったことは、
「[SerializeField] Transform 〜」で各場所の設定を入れて、
「Instantiate(cardPrefab, 〜)」で各場所にカードを生成。って書くだけですね!
②Unity側の設定
最後にコードを追記した箇所の設定をしましょう。
- GameManagerを選択
- 各オブジェクトを各場所にアタッチ
これで完了!!
③ゲームの実行
ではではゲームを実行してみましょう!!!
こんな感じに自分と敵の手札とフィールドにカードが表示されていればOK!!
今回の実装は完了となります!お疲れ様でした!!
ちょっと長丁場でしたが、お疲れ様でした!!!!
【コラム】コードがあんまり分かってないけど大丈夫?って方へ
コードについてちゃんと分かってないのに、
ゲーム作りを進めていいのかな??
全然大丈夫!
ぶっちゃけ自分もよくわかってない笑
まあ分かってないと言うとだいぶ語弊があると思いますが、「私は全てのコードについてに知っていて、完璧に説明も出来ます」ってひとの方が少ないと思います。
大体の人は「何となくこうだろ」とか「調べた内容をコピペしたらできたze☆」みたいな感じでやってると思います。(ガチで仕事でやってるひと以外)
だから最初から全部を理解することは諦めてください。
むしろいきなり全部を理解しながら進める方が非効率です。
何か一つ分かれば儲けもの。
中身は分からんが動けば正義。それでOKです。
作りたいゲームがあるなら、勉強してないで作れ。
※一応言っておくと、勉強は大事です。笑
でも作りたいゲームがあるけど、まずは勉強の為に作りたくもないブロック崩しとか、別のゲームを作るのは違くない??作りたいゲームを作りながら勉強すれば良くない??実際作ってみたら分かんないところがいっぱい出てくるだろうから、それから勉強するので良くない??
って言う意見です。勉強を否定してる訳ではないので悪しからず。
【終わりに】UI作成とカードの生成
今回も最後までお疲れ様でした!!
色々コードが出てきましたが、演習含めて実施出来たでしょうか。
何となくでも、1mmでも理解出来れてばOKです!
ただ「全然わからん!!」って状態だと解説してる意味ないので、
改善のために演習を自力で出来たかなどをコメントに書いていただけると助かります!
それでは今回はこれで終わり!!
次回も楽しんでゲーム作りしていきましょー!
【次の記事】