イベントをランダムに発生させる練習として、ポーカーを作ってみようと思います。
ただし、作るポーカーは、完全に乱数というわけではなく、手持ちのカードによって特定の役がちょっと揃いやすくなる、ちょっと不思議なポーカーです。
題して「ちょっとだけそろいやすいポーカー」!!
第1回、2回は一般的なポーカーゲームの作り方です。乱数調整は第3回以降に実装していきます。
画面設計
カジノでおなじみのトランプカードゲームであるポーカーは、手札5枚を交換して役を作っていくゲームです。
ゲームオブジェクトの配置
まず、カードとトグルスイッチ5個、ボタン1個を配置して、おおまかな座標を決めます。
以下のようにグループ分けしています。
(1) 一対のカードとトグルをひとまとめにします。これは交換可能な最小セット(SelectiveCard)を表します。このセットはVerticalLayoutGroupで体裁を整えます。この最小セットはプレハブにして最終的に削除します。
(2) カードとトグルのセット5枚分をさらにひとまとめにして、スート(CardSuit)というグループにします。スートにはHorizontalLayoutGroupを設定します。
(3) さらに、スートと交換決定ボタン(ButtonChange)を整列させるためにグループにして、VerticalLayoutGroupで囲みます。これは言わばカジノのテーブル(CasinoTable)です。
出来上がった階層構造は以下のようになっています。
(4) カードとチェックボックスはプレハブにして複製し、体裁を整えた後で消去します。
処理の流れ
まずはゲームとしてのポーカーの流れを確認しておきます。
(1) ゲーム開始時:5枚ドローします。
(2) 役を確認します(次回)。
(3) 交換するカードにチェックをつけて、Change! を押します。
(4) チェックが付いているカードを捨てて、捨てた枚数だけドローします。
以降、(2)役の確認、(3)チェック、(4)ドロー、を繰り返します※
※本来のポーカーは1回の交換で終わることが多いですが、交換回数の制限は後から設定できるのと、偏りのある乱数振り出しのシミュレートを兼ねているので、今回はカードが残っている限り、無限に交換できるようにします。
なお、チェックを付けないでChange!を押したら上がりとします(上がり処理は次回以降に)。
ここからは、「(4) チェックが付いているカードを捨てて、捨てた枚数だけドローする」を、さらに細分化します。
(a) チェックが付いているカードを捨てる(交換するカードの確認)
(b) ドローしたカードの決定(乱数の振り出し)
(c) ドローしたカードに基づいて表示を切り替え(イメージ切り替え)
それぞれの処理を、簡単に見ていきます。
チェックが付いているカードを捨てる
Change!が押された時に、チェックが付いていた場合は手持ちのカードを捨て、新しいカードを取得します。トグルのチェックは、Toggle::isOn で確認します。
void カード切り替え() { for( int i = 0; i < 5; i++ ){ if( トグル.isOn ){ カード変更(); } } }
ドローしたカードの決定
カードのドローは、乱数を使用します。Unityでは、System.Random と UnityEngine.Random が使えます。System と UnityEngine の両方を使っている場合、UnityEngine側の乱数を使用する時はUnityEngine.Random で呼び出します。
今回使用したトランプのカードは、たとえばスペードのエースの場合は "card_spade_01" のように、"card_"(定型句)+マーク名+"_"+序数(01~13)という名前になっています。この文字列を乱数から生成します。
今の段階では、とりあえず以下のようにします。
●マーク:カード÷13
●序数:カード÷13 のあまり
string カードのドロー() { int カード = UnityEngine.Random.Range(0f, 51f); // ジョーカーは後から return "card_" + マーク[カード/13] + "_" + (カード%13+1).ToString().PadLeft(2, '0'); }
ドローしたカードに基づいて表示を切り替え
カードを取得できたら、カードのイメージを変更します。
void カード変更() { string カード名 = カードのドロー(); Texture2D texture = Resources.Load(カード名) as Texture2D; image.sprite = Sprite.Create(texture, new Rect(0, 0, texture.width, texture.height), Vector2.zero); }
コード
スート管理(CardSuit.cs)とイベントトリガ(ButtonChange.cs)を作成します。
ButtonChange はイベントを CardSuit に伝えるだけです。カードの切り替えは CardSuit 内で行います。
スート管理(CardSuit.cs)
using System.Collections; using System.Collections.Generic; using UnityEngine; using UnityEngine.UI; public class CardSuit : MonoBehaviour { [SerializeField] GameObject SelectableCardPrefab = default; Toggle dummyToggle = default; Image dummyImage = default; string[] mark = {"spade", "heart", "diamond", "club"}; Toggle GetToggle(int no) { if( 0 <= no && no < 5 ){ return gameObject.transform.GetChild(no).GetChild(0).GetComponent<Toggle>(); } else { return dummyToggle; } } Image GetImage(int no) { if( 0 <= no && no < 5 ){ return gameObject.transform.GetChild(no).GetChild(1).GetComponent<Image>(); } else { return dummyImage; } } // カードのドロー string DrawCard() { int card = (int)UnityEngine.Random.Range(0f, 51f); // 52枚(ジョーカー含まず) return "card_" + mark[(card/13)] + "_" + ((card%13)+1).ToString().PadLeft(2, '0'); } // カード変更 void ChangeCard(int i) { Image image = GetImage( i ); if( !ReferenceEquals(image, null) ){ string card = DrawCard(); Texture2D texture = Resources.Load(card) as Texture2D; image.sprite = Sprite.Create(texture, new Rect(0, 0, texture.width, texture.height), Vector2.zero); } } // カード切り替え public void ChangeCards() { for( int i = 0; i < 5; i++ ){ if( GetToggle( i ).isOn ){ ChangeCard( i ); } } } void Start() { UnityEngine.Random.InitState(100); for( int i = 0; i < 5; i++ ){ GameObject obj = Object.Instantiate( SelectableCardPrefab ); obj.transform.SetParent( gameObject.transform, true ); ChangeCard( i ); } } }
カード交換イベントトリガ(ButtonChange.cs)
using System.Collections; using System.Collections.Generic; using UnityEngine; using UnityEngine.UI; public class ButtonChange : MonoBehaviour { [SerializeField] CardSuit suit = default; void ButtonClicked(int buttonNo) { suit.ChangeCards(); } void Start() { Button button = gameObject.GetComponent<Button>(); // クリックイベントの登録 button.onClick.AddListener( () => ButtonClicked(0) ); } }
作成したコードは、それぞれ CardSuitオブジェクト と ButtonChangeオブジェクト にそれぞれ取り付けます。
動作テスト
公開準備中です。