こんにちは、今日はHoudiniでカードモデルのFBXを作って、UVに合わせてテクスチャを貼り、
そのカードをひっくり返したり、ランダムでマテリアルを付け替えてドローしたりします。
出来れば、手札に加えたりというところまでできたら良いなと思っています。
それではまずはカードモデルから!
HoudiniでカードのモデルをFBXでUnityに吐き出す
まずは、ボックスをTransformで変形させカード型に調節し、ポリベベルで選択した角を丸めます。
あまり説明するような複雑な事はしていないので、特に迷いなく作れるのではと思います。
UVunwrapでUVを展開し、UVlayoutで最大化します。
UVlayoutノードを右クリックしてTextureを保存します。
このようにテクスチャのアウトラインが出てくるので、これを使用して、テクスチャを作成します。
Photoshopで先ほど出力したレイヤーのガイドに合わせ、イメージ画像を配置し、裏と表のデザインを貼ります。
アルファチャンネルに、テクスチャを放り込んで、味が出るようにします。
FBXをUnityに取り込んで、マテリアルを作成し、シェーダーを適用してからテクスチャを貼ってカードが出来ました。
裏もきちんとテクスチャが綺麗に納まっていますね。
UnityとPhotonでカードのモデルマテリアルを動的に切り替える
カードを配る時に、配列を用いて、ランダムにカードを配りたいので、
カードマテリアルをランダムで動的にあてがうようなスクリプトを付けます。
まず、マテリアルを3種類(テストなので)用意しておきます。
次に、CardSwitcher.csというカードのマテリアルをスイッチするスクリプトを書いておき、カードにくっつけます。
using System.Collections; using System.Collections.Generic; using UnityEngine; public class CardSwitcher : MonoBehaviour { [SerializeField] Material[] CardMat; public void SwitchMaterial(int x ) { gameObject.GetComponent<MeshRenderer>().material = CardMat[x]; } }
この時、引数に配列のインデックスが渡ることを想定しています。
一方で、カードを引く時にランダムで配列の番号を渡してあげたいので、
カードPrefabのインスタンス化時にEvent.csを書き換え、Random.Range(int,int)を足してあげます。
using Photon.Pun; using System.Collections; using System.Collections.Generic; using UnityEngine; using UnityEngine.EventSystems; public class Event : MonoBehaviour { GameObject ClickObject; [SerializeField] Transform spawnPoint; CardSwitcher cardSwitcher; public void click() { GameObject cardCopy = (GameObject)PhotonNetwork.Instantiate("NewCard", spawnPoint.position, spawnPoint.rotation, 0); cardSwitcher = cardCopy.GetComponent<CardSwitcher>(); cardSwitcher.SwitchMaterial(Random.Range(0, 3)); } }
今は3種類しかないので0,3としてありますが、最終的には配列の長さを渡してあげるのがスマートですね。
後々実装したいと思います。
これで、マテリアルの動的な切り替えが実装されました。
参考にしたサイトはここです。
Unity C#Photonでカードを手札にする
手札の表示をどうしようか迷っているのですが、とりあえず行き当たりばったりで作ります。
詰まったらやり直そうと思っています。
手札もライブラリ(山札)も配列で管理しようと考えていまして、カードのインデックス番号をカードの枚数分の配列に格納していく方式です。
配列を常に更新して、それをリアルタイムで描画するというのを原則として作ろうと思います。
まずは、自分の陣地の縁にカードを引っ張ってきた場合HandHolderとの衝突判定でカードを引いたことにします。
そして、引いたカードは消去してしまい、HandHolder1(1)に新たなカードを表示させることを考えます。
二枚目に引いたカードはHandHolder2(1)に、というように7枚までカードを引ける仕様にします。
7枚のカードを保持するポジションが、カメラの前に並んでいるという状態です。
カードを引いたら、カードの情報を読み取って現在の手札の配列に加え、カードを破壊して、手札を描画するという具合です。
手札は手札が更新されるたびに全部刷新したいので、”Hands”タグをつけてまとめて破壊できるようにしてあります。
具体的なスクリプトは下のように書きました。
using Photon.Pun; using System.Collections; using System.Collections.Generic; using UnityEngine; public class HandHolder : MonoBehaviour { //手札を表示する場所の配列 [SerializeField] Transform[] holders; //現在の手札の配列 public int[] hands; //手札のマテリアルの種別 public int handIndex; private void OnCollisionEnter(Collision collision) { //カードtagが付いているオブジェクトがHandHolderに衝突した場合 if (collision.gameObject.tag == "Card") { // GameObject型の配列に、"Hands"タグのついたオブジェクトをすべて格納 GameObject[] allHands = GameObject.FindGameObjectsWithTag("Hands"); //一旦現在のハンドを全部消去 foreach (GameObject hand in allHands) { Destroy(hand); } //衝突したオブジェクトのCardSwitcherを取得して、カードのインデックスを取得 CardSwitcher cardSwitcher = collision.gameObject.GetComponent<CardSwitcher>(); handIndex = cardSwitcher.cardIndex; //手札の配列に取得したインデックスを加える。 List<int> list = new List<int>(hands); list.Add(handIndex); hands = list.ToArray(); //ぶつかったカードを消去 Destroy(collision.gameObject); //現在の配列に基づいて手札を表示 for (int i = 0; i < hands.Length;i++) { //手札のインスタンス化 GameObject cardCopy = (GameObject)PhotonNetwork.Instantiate("NewCard", holders[i].position, holders[i].rotation, 0); //タグを"Hands"に変える cardCopy.tag = "Hands"; //リジッドボディを切る Rigidbody rigidbody = cardCopy.GetComponent<Rigidbody>(); Destroy(rigidbody); //手札のマテリアル表示をインデックス値通りにする cardSwitcher = cardCopy.GetComponent<CardSwitcher>(); cardSwitcher.SwitchMaterial(hands[i]); } } } }
これで一応手札の表示まではできました。
この状態では7枚以上カードを引くことができてしまう事、手札を使用する事はまだ対応できてない等、色々と不具合がありますが、
少なくとも7枚まで引いたカードがきちんと描画されるというところまでは漕ぎつけました。
蛇足ですが、Holdersには手札を表示するところのキューブのTransform(120度傾けている)が格納されています。
おわりに
今回は取り急ぎ手札を表示するという事が出来ました。
今度は手札を使用した時に、現在の手札配列から特定のインデックスカードを消去していかないといけませんね。
これは少し厄介な気がしますが、知恵を絞って考えようと思います。
それでは、また!