前回までの記事で、ドローやターンエンドボタンなど
ターンフェーズについての実装が完了しましたね!
前回の記事を見てない人はそちらを参考↓
今回の記事では、カードゲームなら外せない、
カード同士を戦わせるバトルの機能を実装していきます!!
完成形としてはこんな感じ↓
攻撃が出来ると、よりカードゲームっぽくなるね!
徐々にコードが増えて難しくなってきたけど、少しながら理解しながらやっていこう!!
Contents
全体の流れの説明
ではまず今回やる全体の作業の流れについて説明します!
ざっくりこんな感じに進めてくよ↓
- バトル関数の作成
カードを重ねた時にバトルする処理の追加 - 攻撃に制限を付ける
攻撃回数に制限を掛ける処理の追加 - 攻撃可能なカードに枠を付ける
攻撃可能なのかわかりずらいので見える化する - 枠を作る
攻撃可能なカードに付ける枠を作る - アタッチする
コードとオブジェクトをアタッチする
今回はかなりコードのボリュームと難しさがあると思うけど、頑張っていこう!!
バトル関数の作成
ではここの章では、
カードをドラッグして、
他のカードの上でドロップした時に、
パワーが低い方を破壊する
という処理を作って、追加していくよ!
実際にやることはこんな感じ↓
- 「AttackedCard」クラスを作る
- attackedCardクラスに処理を書く
- GameManagerにカードバトルメソッドを作る
- CardControllerにDestroy処理を追記する
- GameManagerをどこでも使える化する
- Cardプレハブにアタッチ
では上から順番にやっていくよ!
①「AttackedCard」クラスを作る
まずは新しいクラス「AttackedCard」を作ろう。
こんな感じに作れたらOK↓
②AttackedCardクラスに処理を書く
ではまず、さっき作ったAttackedCardクラスに処理を書いていくよ!!
丸々コピペで大丈夫だよ↓
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; using UnityEngine.EventSystems; // 攻撃される側のコード public class AttackedCard : MonoBehaviour, IDropHandler { public void OnDrop(PointerEventData eventData) { /// 攻撃 // attackerを選択 マウスポインターに重なったカードをアタッカーにする CardController attackCard = eventData.pointerDrag.GetComponent<CardController>(); // defenderを選択 CardController defenceCard = GetComponent<CardController>(); // バトルする GameManager.CardBattle(attackCard, defenceCard); } } |
エラーが出てると思うけど、いったん気にしないで大丈夫。
コードの説明
先に進む前に、ざっくりコードの内容の説明をするよ!
ここで重要になるのは「OnDrop」メソッド。
1 2 3 4 5 6 7 8 9 10 11 12 |
public void OnDrop(PointerEventData eventData) { /// 攻撃 // attackerを選択 マウスポインターに重なったカードをアタッカーにする CardController attackCard = eventData.pointerDrag.GetComponent<CardController>(); // defenderを選択 CardController defenceCard = GetComponent<CardController>(); // バトルする GameManager.CardBattle(attackCard, defenceCard); } |
って人は素晴らしい!
第4回目に解説した「DropPlace」クラスでも使ったメソッドだね。
「DropPlace」クラスは、
カードを“フィールドにドロップした時”に
処理が動くようにしたけど、
今回の「AttackedCard」クラスは、
カードを“カードの上にドロップした時“に
処理を動かすようにしていくよ!
では実際のコードの説明をしていくと、、
1 2 |
// attackerを選択 マウスポインターに重なったカードをアタッカーにする CardController attackCard = eventData.pointerDrag.GetComponent<CardController>(); |
↑これでマウスの下にあるカードを攻撃側(attackCard)に設定。
1 2 |
// defenderを選択 CardController defenceCard = GetComponent<CardController>(); |
↑これでドロップされたカードを守備側(defendCard)に設定。
1 2 |
// バトルする GameManager.CardBattle(attackCard, defenceCard); |
↑これで(まだ作ってないけど)、GameManagerのCardBattleメソッドを使って攻撃側と守備側をバトルさせる。
という処理をしているよ!!
③CardBattleメソッドを作る
では次は今回の主役。
CardBattleメソッドを作っていこう!
GameManagerに追記する(EnemyTurnメソッドの下とかでいいよ)↓
1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19 20 21 |
public void CardBattle(CardController attackCard, CardController defenceCard) { // 攻撃側のパワーが高かった場合、攻撃されたカードを破壊する if (attackCard.model.power > defenceCard.model.power) { defenceCard.DestroyCard(defenceCard); } // 攻撃された側のパワーが高かった場合、攻撃側のカードを破壊する if (attackCard.model.power < defenceCard.model.power) { attackCard.DestroyCard(attackCard); } // パワーが同じだった場合、両方のカードを破壊する if (attackCard.model.power == defenceCard.model.power) { attackCard.DestroyCard(attackCard); defenceCard.DestroyCard(defenceCard); } } |
またエラーが出てると思うけど、気にしなくて大丈夫!
コードの説明
わりと見たまんまだけど、一応説明!
さっき、AttackedCardクラスのOnDropメソッドで、攻撃側(attackCard)と守備側(defndCard)が決まったよね?
1 |
if (attackCard.model.power > defenceCard.model.power){} |
↑それらのパワー(~.model.power)を比較して、攻撃側のパワーが高いなら、
1 |
defenceCard.DestroyCard(defenceCard); |
↑守備側(defenceCard)のカードを破壊(destory)する
って処理を行ってるよ!!
他の2つ処理も、
- パワーが同じなら両方のカードを破壊する。
- 守備側のパワーが高いなら攻撃側のカードを破壊する。
ということなので、ほぼ一緒!!
④CardControllerにdestory処理を書く
今さっき出てきた、“カードを破壊する”って処理がまだ書かれてないので、CardControllerに追記していくよ。
CardControllerに追記しよう↓
1 2 3 4 |
public void DestroyCard(CardController card) { Destroy(card.gameObject); } |
追記してもまだエラーが出るけど、まだ無視して!
コードの説明
これはめっちゃ単純で、
1 |
Destroy(card.gameObject) |
↑このDestroy関数(オブジェクトを削除してくれる関数)で、指定したCardオブジェクトを破壊してるだけ!!
⑤GameManagerをどこからでも使えるようにする
では最後にエラーを解消しよう!
現状だとこんなエラーがずっと出てるよね↓
って気持ちはよくわかる。
でも大丈夫、僕もずっと思ってた。
てか最早、今でも「何言ってんの?」って思ってる。笑
ただ実は言ってることは単純で、
この場合は「このままじゃAttackedCardクラスから、GameManagerのメソッドは使えないよ!!」ってこと。
要は今回の場合で言うと、
他のクラスのメソッドは使えないよ!!
ってことだね。
※なんで他のメソッドを使えないのかって言うと、色々深い意味があるんだけど、今はまだ「基本そのままだと他のクラスのメソッドは使えない」って認識で」OK
でも「使えません、残念でした(‘ω’)」って話じゃないからご安心を。
使うためにはひと手間が必要ってことね。
今回はそのうちの一つの方法を使っていくよ!
GameManagerに追記しよう(Startメソッドの上でいいよ)↓
1 2 3 4 5 6 7 8 |
public static GameManager instance; public void Awake() { if (instance == null) { instance = this; } } |
こっちはAttackedCardクラスのOnDropメソッドの一部を編集しよう↓
1 2 3 4 5 6 |
public void OnDrop(PointerEventData eventData) { (省略) // バトルする GameManager.instance.CardBattle(attackCard, defenceCard); } |
追記したらエラーは消えたかな??
詳しい説明は省くけど、
1 2 3 4 5 6 7 8 |
public static GameManager instance; public void Awake() { if (instance == null) { instance = this; } } |
「他のクラスでも、このクラスのメソッドを使いたい!!」って時は、これを書いておけばすべてのクラスから使えるようになる!!って認識でひとまずOK。
んで、そのメソッドを使いたい時は
1 |
GameManager.instance.CardBattle(attackCard, defenceCard) |
こんな風に、
《クラス名》.instance.《メソッド名》
と書けば他のクラスからも制限なく使えるよ!!
※ただし注意点として、参照元のメソッドの名前の前に”public”って書いてないメソッドは他のクラスからは使えないから注意ね!!
では最後に「AttackedCard」のコードを、Cardプレハブにアタッチしたら完成!!
では実際にやってみよう!
攻撃が出来るようになった!!!
でも
- すぐ攻撃できちゃうし、
- 何度でも攻撃できちゃう。
という問題があるので、次はここら辺を修正していこう!!
攻撃に制限を付ける
まずは修正したいことを洗い出そう↓
- 出したターンは攻撃できないようにする
- 1ターンに1度だけ攻撃出来るようにする
こんな感じかな!
これを実現するには、カード一枚一枚に
「いま攻撃を出来る状態なのか」という情報
を持たせる必要がある。
じゃあどうやるかというと、
“canAttack“というbool型の変数を使って実装するよ!
※bool型の変数って言うのは、”True”か”False”しか入れられない変数のことね。
int型の変数は、数字の整数しか入れられないじゃん?
それの「〇」か「×」しか入れられない版。って認識でOK
具体的に言うと、
canAttack=True → 攻撃出来る
canAttack=False → 攻撃出来ない
っていう風に攻撃の制御をしていくよ!!
実装の為にやることはこんな感じ↓
- CardModelクラスに、変数”canAttack”を作る
- CardBattleメソッドに、攻撃可能か判断する処理を追記する
- PlyerTurnメソッドに、
ターンの始めにフィールドのカードを攻撃可能にする処理を追記する
では上からやっていこう!
CardModelに追記↓
1 |
public bool canAttack = false; |
GameManagerにもいくつか追記しよう。
CardBattleメソッドにオレンジ部分を追記しよう↓
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 |
public void CardBattle(CardController attackCard, CardController defenceCard) { // 攻撃カードがアタック可能でなければ攻撃しないで処理終了する if (attackCard.model.canAttack == false) { return; } // 攻撃側のパワーが高かった場合、攻撃されたカードを破壊する if (attackCard.model.power > defenceCard.model.power) { defenceCard.DestroyCard(defenceCard); } // 攻撃された側のパワーが高かった場合、攻撃側のカードを破壊する if (attackCard.model.power < defenceCard.model.power) { attackCard.DestroyCard(attackCard); } // パワーが同じだった場合、両方のカードを破壊する if (attackCard.model.power == defenceCard.model.power) { attackCard.DestroyCard(attackCard); defenceCard.DestroyCard(defenceCard); } attackCard.model.canAttack = false; } void SetAttackableFieldCard(CardController[] cardList, bool canAttack) { foreach (CardController card in cardList) { card.model.canAttack = canAttack; } } |
最後に”PlayerTurn”メソッドに追記しよう↓
1 2 3 4 5 6 7 8 9 |
void PlayerTurn() { Debug.Log("Playerのターン"); CardController[] playerFieldCardList = playerField.GetComponentsInChildren<CardController>(); SetAttackableFieldCard(playerFieldCardList, true); DrawCard(playerHand); // 手札を一枚加える } |
では実際に動かしてみよう!!
出したターンに攻撃出来ないし、
連続で攻撃も出来なくなったかな??
そしたら無事バグの解消が出来たので、
コードの解説に入っていくよ!!
コードの説明
ではコードの説明をざっくりやってくよ!!
まず最初にCardModelクラスに下記のコードを追記したよね↓
1 |
public bool canAttack = false; |
これでカードは基本的に攻撃できないってことになる。
次にGameManagerに追記したコードについて。
CardBattleメソッドに、4~7行目と11行目の追記をしたよね↓
1 2 3 4 5 6 7 8 9 10 11 12 |
public void CardBattle(CardController attackCard, CardController defenceCard) { // 攻撃カードがアタック可能でなければ攻撃しないで処理終了する if (attackCard.model.canAttack == false) { return; } (省略)バトル処理 attackCard.model.canAttack = false; } |
これらに解説を付けるとこんな感じ↓
【解説】攻撃できないカード(canAttackがFalseのカード)は、
if (attackCard.model.canAttack == false)
{
【解説】バトル処理まで行かずに終了する。
return;
}
(省略)~バトル処理~
【解説】攻撃を終えたカードを攻撃不可にする
attackCard.model.canAttack = false;
要はバトル処理の前に、攻撃してきたカードが攻撃できる状態なのかを判断して、
バトル処理が終わったら、もう攻撃できなくする。
ってことだね。
その後に追記したメソッドはこんな感じ↓
【解説】指定したリストのカードを全て攻撃可能か攻撃不能にするメソッド
void SetAttackableFieldCard(CardController[] cardList, bool canAttack)
{
【解説】リストの中のカードに対して全て同じ処理を行う
foreach (CardController card in cardList)
{
【解説】”canAttack”を引数に指定した方に変える
card.model.canAttack = canAttack;
}
}
このメソッドを使うことで、指定したフィールドのカードを全て攻撃可能にしたり、攻撃できなくしたり出来るよ!
最後に”PlayerTurn”メソッドに追記したのは、今説明したメソッドだね。
1 2 3 4 5 6 7 8 9 |
void PlayerTurn() { Debug.Log("Playerのターン"); CardController[] playerFieldCardList = playerField.GetComponentsInChildren<CardController>(); SetAttackableFieldCard(playerFieldCardList, true); DrawCard(playerHand); // 手札を一枚加える } |
Playerフィールドのカードリストを取得(5行目)して、
それらを全て攻撃出来るようにする(6行目)って処理だね。
つまり、「ターンの始めにPlayerフィールドのカードを全部攻撃可能にしてる」ってことだね。
なかなか複雑になってきたので「よく分かんない!!」って人はコメントくださいな。
理解しながら進めてるよーって人もコメント頂けるとありがたいです!
【演習】バグの解決
ではでは攻撃処理も完成に近づいてきたので、演習やっていきましょう!
今回の演習はバグの解決です!!
さっきは、下のふたつのバグを解決したよね?
- 場に出したターンに攻撃出来ること
- 何度も攻撃出来ること
気づいてる人も居るかもしれないけど、実はまだバグが2つあります。
※気づいてない人は探してみてね。バグを見つけるのも大事な力です。
一般的なカードゲームのルールを元にすると、
- 味方同士でバトル出来ること
- 手札に攻撃出来ること
この2つが出来るのはおかしいよね??
(まあ攻撃の選択肢が広がって、これはこれで面白そうだけど。(笑))
今回の演習ではこの2つのバグを直してもらいます!!
そして今回は新しい試みとして、まだ答えを教えません!!!
悩んで下さい!!(笑)
そして実装出来たらコメントで教えてね!
出来た人が出てきたら、答え合わせとして答えを載せようかと思ってます!
※出来なかったら「難しい!!」ってコメントください。
それはそれで答えのヒントや、解説を載せるので。
最後に
いつかの前の記事で「7月中にカードゲームの基本の作り方記事は完成させるよ!!」って言ったのに、完成できなくてごめんなさい!
思った以上に、1記事作るのに時間が掛かってしまってしまいました。。
8月中には完成する(はず)なので、のんびり演習やるか、
今までの知識を使って自分の作りたいカードゲームを作ってみて下さい。
恐らく今までの記事の知識を使えば、
あなたが作ってみたかったカードゲームを少し形に出来ると思います。
このカードゲーム作成講座の記事をやる前だったら、
「どこから手を付けて良いのかも分かんないよ!!」って状態だったかも知れません。
でも今なら、
カードはどうやって作るのか、
どうしたらカードを持って動かせるのか、
どうやってフィールドを作るのか、
全部わかるよね??
(「そんなのやったっけ??(^.^)」ってひとは復習なさい。(笑))
だから一旦、自分の作りたいゲームに手を付けてみる。ってのもアリかと思います。
ただぶっちゃけ、ここまで来れた方々は超ツワモノだと思います。
「カードゲームを作りたい!!」って思って、解説記事①を読んだ人の中でも、この記事まで来れた人は見た感じ全体の5%くらいです。
95%のひとは「難しそうだな~」とか「やり方はなんとなく分かった(作ってないけど)。」とか言って、カードゲームが作りたい気持ちはあっても行動に移さないで、ゲームやって遊んでますね。たぶん。
だからここまでゲームを作ってこれた人達は自信持っていいと思います。
「初心者でも出来る!!」ってタイトルのくせに、最近の解説難しいしね。(笑)
出来るだけ分かりやすく噛み砕いて教えるので、また見てくださいな!
※分かりやすく書いてるつもりが、逆に説明し過ぎて分かりずらいみたいなこともあるので、コメントはほんとにありがたいです。
そんな訳で今回は終わりっ!!
次はリーダーへの攻撃を実装してくよ!!
(そういえばカードの枠付けるの忘れてたので、次回解説します。。笑)
では演習頑張って!!!
次の記事↓
前の記事↓
参考にさせて頂いた動画
[Unityゲーム開発講座] シャドバ風!?カードゲームの作り方 #1 UIの実装
http://yuus01.info/huntoki/datu-dt-huntoki1/
こんにちは。
解説が分かりやすく、ここまで一気にやることができました。
演習は、コードの書き方がいまいちわからないですけど親を取得してif文を使うとかですかね?
それと、自分の場には何体でもモンスターを出せる(これはすぐ解決できた)と相手のモンスターを自分の場に出せる(直し方は演習のとおなじかな?)というバグを発見しました。できればこちらも教えてほしいです。
次回の記事も楽しみにしています。
>ナエニアさん
ありがとうございます!!
そう言っていただけると、頑張って解説書いてよかったです、、(泣)
演習はナエニアさんの言ったように親を取得でも出来ないことはないと思いますが、
解答例として出そうとしてたのは、カードに変数isPlayer(プレイヤーのカードなのかどうか)を持たせて、ifで味方同士ならバトルしない。という分岐にする予定でした。これなら手札にも攻撃できなくなりますからね。
あとで解答を追記しますが、このヒントを使ってやってみてください!
出来なかったとしても、めっちゃ力付くと思いますので!
バグについても自己解決出来ていて素晴らしいですね。
理解しながら進めているのが分かって、すごく嬉しいです!
他のバグのところも今後解説していきますね。
コメントほんとにありがとうございました!
次回の記事は少々お待ちください。(笑)
毎回楽しみにしています!!
今回の演習からぐっと難易度が上がりましたね
半日くらい悩み続けて、やっとできました(汗
いや~これは難しかったです
コメント欄のみじんこさんとナエニアさんのヒントを参考にして
ギリギリできたって感じです
以下、追記した箇所です
public class CardModel
{
(省略)
public bool isPlayer = false; // true=Player, false=Enemy
(省略)
}
public class GameManager : MonoBehaviour
void PlayerTurn()
{
UnityEngine.Debug.Log(“Playerのターン”);
CardController[] playerHandCardList = playerHand.GetComponentsInChildren();
CardController[] playerFieldCardList = playerField.GetComponentsInChildren();
// ターン開始時はPlayerフィールドのカードをすべて攻撃可能にする
SetAttackableFieldCard(playerFieldCardList, true);
// ターン開始時はPlayerHandのカードをすべてプレイヤー属性にする
SetPlayerableCard(playerHandCardList, true);
// ターン開始時はPlayerFieldのカードをすべてプレイヤー属性にする
SetPlayerableCard(playerFieldCardList, true);
DrowCard(playerHand,0); // 手札を一枚加える
}
public void CardBattle(CardController attackCard, CardController defenceCard)
{
(省略)
if (attackCard.model.isPlayer != defenceCard.model.isPlayer)
{
(省略 アタック動作の処理)
//攻撃を終えたカードは追加で攻撃不可にする
attackCard.model.canAttack = false;
}
//プレイヤーフィールドのカードをすべて isPlayer=ture or false にする
void SetPlayerableCard(CardController[] cardList, bool isPlayer)
{
// リストの中のカードに対してすべて同じ処理を行う
foreach (CardController card in cardList)
{
card.model.isPlayer = isPlayer;
}
}
}
>もっけさん
これは素晴らしすぎますね、、!!
というかこんなにしっかり書けるってことは、もっけさん初心者ではないですね。。笑
失礼しました。素晴らしいです!
ではちょっとだけコードの添削しますね!
CardModelのコードについては文句無しです。
GamaManagerのコードについても、
① Playerのカードに対してPlayer属性を付与
② 同じPlayer同士なら攻撃しないようにする
の2点がしっかり実装されていていて素晴らしいです!!
(if (attackCard.model.isPlayer != defenceCard.model.isPlayer){} の条件分岐の中にreturnが書かれてないのは、抜けですかね??)
ただ1点気になったのが、DrowCardのメソッドをちょっと変更しました??
(例えば、2つ目の引数が0なら、Playerのカードにするとか?)
そうじゃないと、ドロー前に手札のカードを全てPlayerの属性を付与しても、ドローしたカードにPlayer属性が付かなくなっちゃうので!
このままのコードでもほぼ大丈夫ですが、あとで(次の記事がもう少しなので、それを上げたら、、、)僕のコード例を出すのでちょっと参考にしてみてくださいね!
「ちょっと難しすぎたかなぁ。。」と反省してたので答えていただけて助かりました。
もっけさんには簡単になっちゃうかも知れないですけど、次からちょっとだけ簡単にしてみます!
コメントと回答、ありがとうございましたー!!
添削ありがとうございます!
おっしゃる通り条件分岐内でreturnを書いた方がいいですね
そのほうが予期せぬ動作を防げそうです
DrowCardメソッドでは前回の課題でデッキを2つ作っていて
答えどおりに戻し忘れたまま進めていました(汗
そのため、2つ目の引数が0だとPlayerのデッキからカードを引き
1だとEnemyのデッキからカードを引くようになっていました
忘れずに課題⑥の答えに戻して進めてみたところ
たしかにドローにPlayer属性がついていませんね(汗
プレイヤー属性を付与した後に手札を加えるというのが原因でした
逆にすると良いと思い
PlayerTrunメソッド内のDrowCard呼び出しを、
playerHandCardListの定義前に持っていくことで解消できました!
8回目ももうすぐということなので楽しみです!!
>もっけさん
DrowCardメソッドはそういう事だったんですね!
「なるほど。そんなやり方もあるな!」って思ってました。笑
8回目も投稿したのでやってみてくださいねー!(‘ω’)
すいません、バグが出たので相談したいです。
戦闘のコードを試していたのですが、攻撃している側のカードが勝負に勝った際に負けカードと一緒に消えてしまうという現象が起きています。
攻撃側が負けの場合は問題なく動いており、いろいろ試してみたところ「攻撃時にドラッグしたカードが攻撃対象カードの子図番に移動してしまう」という現象がおきているみたいです。。。
おそらくCardMovementのどこかでなにかミスをしたんだと思うのですが自分で見ても問題があわかりません。。。
何か「ここが間違っているんじゃないか」って思い当たることがあれば教えていただきたいです。
すいません、自己解決しました。
Cardプレハブに何故かDropPlaceを貼り付けていたみたいです。DropPlaceを削除したら無事に動きました。
お手数おかけしました
>トキムネさん
返信出来ず、すみません、、!
なるほど、そんな動きするんですね。笑
解決出来たみたいで良かったです!
えっと、まだ途中しか見てないんですが、カードを破壊するんじゃなくて、墓地の子にさせたいのですが、どうすればよいのでしょうか?
>ラいさん
返信遅れてすみません!
バトルで破壊されたカードをDestroyするんじゃなくて、墓地にカードを移す方法ですかね?
んー、色々方法はあると思うますが、ラいさん的にはどうやったら実装できると思いますか??
今までの解説で出てきた方法や、ほかに知ってる方法を使ったらどうやって実装出来るか。を考えてみると案外できるかと思います!
ちょっとだけヒントを出すと、Cardを表示させている「Instantiate」をうまく使ってみてください!
追記:墓地はImageにして写真のっけてます
あの…?
わかりました!頑張ってみます!
AttackedCardのとは要らないんじゃないんですかね?
>ラいさん
AttackedCardの”ed”のことですか?
攻撃される側のコードなので、要りますよー。受け身の”ed”です。
コンパイルエラーが出ます…原因もわからないです。
GameManager
using System.Collections;
using System.Collections.Generic;
using UnityEngine;
public class GameManager : MonoBehaviour
{
[SerializeField] CardController cardPrefab;
[SerializeField] Transform playerHand, playerField, enemyField;
bool isPlayerTurn = true; //
List deck = new List() { 1, 2, 3, 1, 1, 2, 2, 3, 3, 1, 2, 3, 1, 2, 3, 1, 2, 3 }; //
public static GameManager instance;
public void Awake()
{
if (instance == null)
{
instance = this;
}
}
void Start()
{
StartGame();
}
void StartGame() // 初期値の設定
{
// 初期手札を配る
SetStartHand();
// ターンの決定
TurnCalc();
}
void CreateCard(int cardID, Transform place)
{
CardController card = Instantiate(cardPrefab, place);
card.Init(cardID);
}
void DrowCard(Transform hand) // カードを引く
{
// デッキがないなら引かない
if (deck.Count == 0)
{
return;
}
CardController[] playerHandCardList = playerHand.GetComponentsInChildren();
if (playerHandCardList.Length < 9)
{
// デッキの一番上のカードを抜き取り、手札に加える
int cardID = deck[0];
deck.RemoveAt(0);
CreateCard(cardID, hand);
}
}
void SetStartHand() // 手札を3枚配る
{
for (int i = 0; i < 3; i++)
{
DrowCard(playerHand);
}
}
void TurnCalc() // ターンを管理する
{
if (isPlayerTurn)
{
PlayerTurn();
}
else
{
EnemyTurn();
}
}
public void ChangeTurn() // ターンエンドボタンにつける処理
{
isPlayerTurn = !isPlayerTurn; // ターンを逆にする
TurnCalc(); // ターンを相手に回す
}
void PlayerTurn()
{
Debug.Log("Playerのターン");
DrowCard(playerHand); // 手札を一枚加える
}
void EnemyTurn()
{
Debug.Log("Enemyのターン");
CardController[] playerHandCardList = playerHand.GetComponentsInChildren();
if (playerHandCardList.Length defenceCard.model.power)
{
defenceCard.DestroyCard(defenceCard);
}
// 攻撃された側のパワーが高かった場合、攻撃側のカードを破壊する
if (attackCard.model.power < defenceCard.model.power)
{
attackCard.DestroyCard(attackCard);
}
// パワーが同じだった場合、両方のカードを破壊する
if (attackCard.model.power == defenceCard.model.power)
{
attackCard.DestroyCard(attackCard);
defenceCard.DestroyCard(defenceCard);
}
}
}
AttakedCard
using System.Collections;
using System.Collections.Generic;
using UnityEngine;
using UnityEngine.EventSystems;
// 攻撃される側のコード
public class AttackedCard : MonoBehaviour, IDropHandler
{
public void OnDrop(PointerEventData eventData)
{
/// 攻撃
// attackerを選択 マウスポインターに重なったカードをアタッカーにする
CardController attackCard = eventData.pointerDrag.GetComponent();
// defenderを選択
CardController defenceCard = GetComponent();
// バトルする
GameManager.instance.CardBattle(attackCard, defenceCard);
}
}
CardController
using System.Collections;
using System.Collections.Generic;
using UnityEngine;
public class CardController : MonoBehaviour
{
public CardView view; // カードの見た目の処理
public CardModel model; // カードのデータを処理
private void Awake()
{
view = GetComponent();
}
public void Init(int cardID) // カードを生成した時に呼ばれる関数
{
model = new CardModel(cardID); // カードデータを生成
view.Show(model); // 表示
}
public void DestroyCard(CardController card)
{
Destroy(card.gameObject);
}
}
おかしいところが見つかれば指摘していただけると嬉しいです
>みたらしさん
んー、詳しく中身を見れてはないですけど、
ファイル名とclass宣言部の名称が合っているか確認して貰えますか?(特に大文字と小文字)そこを間違えて出る場合が多いので!
あとエラーメッセージを載せてもらえるとより分かりやすいかと!
すみません。風邪をひいていたのでパソコンを確認できていませんでした
Assets/Scripts/GameManager.cs(105,32):error CS0103:The name ‘hand’ does not exist in the current context
と出ています
>みたらしさん
返信のスピードはそんなに気にしてないので、気づいた時で大丈夫ですよ!笑
んー、エラーをダブルクリックして、移動した部分がどこか教えてもらえますか?
(DrowCardメソッドの部分な気がしますが、コードを見た感じ引数のスペルミスでもなさそうなので、謎ですね。。)
ちょっとこっちで分からないことも多いので、
参考になりそうな記事を見つけたので、みたらしさん自身でも確認してみて下さい。
自己解決しました!手伝ってくださりありがとうございました。
おー、良かったです!
とりあえずエラーで困ったら、エラーメッセージをそのまま打ち込んで調べれば、かなり自力で解決出来るかと思います!
攻撃側と守備側を指定するときに、場所で指定したいのですが、どうしたらいいのでしょうか?
>じゃがすけさん
んー、色々やり方はあると思いますがパッと思いつくのは、
自分と相手のフィールドを順番に1~5とか番号を付けて、
指定した番号の攻撃力とHPを取得してバトルさせるとかですかね~
(むしろなんか他に良さげな方法があれば是非教えてください。笑)
なるほど。。。
今、この記事を見てオリジナルのカードゲームを作ろうとしていて、そのゲームは戦うところが1つしかない(ポケモンカードのような感じ)なのですが、そういう場合はどうですかね?
んーポケモンカードのルールがちょっと曖昧ですけど、バトルゾーンとベンチがあるやつですよね??
バトルゾーンとベンチを作って、バトルゾーンにはカードを1枚しか置けないようにすれば良いんじゃないですかね、、?
すみません、いまいち質問の意図が読み取れなくて、、
解答が的外れだったら申し訳ないです。(´・ω・`)
質問の際はもう少し具体的に「~を実装したい。自分ではこんな風にやってみた。でも実装部分の…する処理が分からないのでどう実装すればいいか教えて欲しい。」と言った感じで質問頂けるともう少しお力になれるかと!!
記事とても勉強になってます
演習やってみました
AttackedCardに追記
// defenderを選択
CardController defenceCard = GetComponent();
Debug.Log(transform.parent.gameObject.name);
if(transform.parent.gameObject.name == “EnemyField”)
{
// バトルする
GameManager.instance.CardBattle(attackCard, defenceCard);
}
一応味方に攻撃できないようになりました。
このやり方手抜きっぽい感じするんですけど、いいんですかね?
カードゲーム楽しく作らせてもらっています!ありがとうございます!演習など応用が苦手でコピペになってしまっていますが頑張りたいです……
一つ気になったのですが、
⑤GameManagerをどこからでも使えるようにする
(省略)
こっちはAttackedCardクラスのOnDropメソッドの一部を編集しよう↓
public void OnDrop(PointerEventData eventData)
{
(省略)
// バトルする
GameManager.instance.CardBattle(attackCard, defenceCard);
}
の部分でとを入れるとエラーが出ました。この2つを消すとエラーは出ずうまくいきました。unityのver.の違いとかでしょうか……?
> キクラゲさん
コメント頂きありがとうございます!
これはただのこちらのミスですね。。ご指摘ありがとうございます!当記事の該当箇所は修正しました。
ご指摘いただいた通り、ストロングの部分は削除して貰って大丈夫です。
楽しんでゲーム作りをするのが一番の上達方だと思うので、演習は出来たらでいいと思いますよ!
ではでは、また不明点あればお気軽に聞いてくださいー!
ありがとうございます!
楽しくゲーム作りしていきたいです!
ごめんなさい。太字になっている部分を
<ストロング></ストロング>で囲っています。
<ストロング>Ondrop</ストロング>
<ストロング>と</ストロング>です。
unityでもこれは文字を太字にするというコードなのでしょうか?
こんばんは、プログラム単語を一つも知らない人間です。がここまで来れました。
ただ、思考錯誤したものの私の頭では解決できなかった問題があったので質問です。
途中の攻撃に制限をつける。
までは無事進めたのですが、その後のコードを書くと、攻撃事態ができない(敵にドラックしても元のフィールドに戻る)状態になってしまいます。
私としては、遊戯王の様にフィールドを1マス1マスに敵味方両方したのが、リストに悪さしてるのかなーなんて思ったりしてるのですが、いかんせん何がどうだめなのか一切わかりません……!
どうか助言のほどをよろしくお願いいたします!
これは解決できました……!
ただ、1マスのみに置いて、その後ほかのマスに手札からおけない様に、かつ、マスを自由に移動できないようにしたいのですが、いいやり方ありましたら、教えてくださるとありがたいです!!!
マナ利用でいけるかもしれませんので試してみます!
ただ、それでもフィールドを縦横無尽に移動できるのは変えられなさそうです……
>クルルさん
返信遅れてすみません!!
そうですね、手札からフィールドへの移動はマナの実装で制御できると思います。
それでお悩みのフィールドから他のフィールドへの移動制御の方法ですが、
マナの制御のところまでいくと、Cardに「FieldCard」っていうパラメータを持たせることになるんですが、それを使うとうまく制御出来るかと思います!
ヒントを軽く言うと、もしCard.model.FieldCardがFalse(フィールドのカードでない)なら、フィールドにドロップした時に、cardParent(カードの親要素)を変更する処理を実行させない。
とかにすれば、フィールドのカードを他のフィールドに移動し放題にはならないかと思います!
また分からなければまたコメントくださいー!
なるほどー?
マナまで行ってから実践してみます!w
また質問するかと思いますが、その時はまたお世話になります
いつも楽しく作らせてもらっています!
// バトルする
GameManager.instance.CardBattle(attackCard, defenceCard);
「CardBattle」に対して
objectにCardBattleの定義が含まれておらず、アクセス可能な拡張メソッドが見つかりません。
と言われてしまいます。
どのように対処すればよいでしょう?
GameManagerクラスに正しくCardBattleメソッドは書けてますか??
記事の記載通りにコピペして、
保存すればそのエラーは出ないと思うので確認してみてください!