対戦カードゲームをunityとc#とphotonで作りたい:クラスの使い方を応用してみる(13)

Githubソースコード公開&まとめ

引き続き対戦カードゲームを作っていきたいと思います。役判定、勝敗判定ができたので、3/5/5のうちの真ん中(middle)の役だけでなく、下(bottom)の役も判定できるようにします。理想的には役判定クラスを作って、player毎にインスタンス化するのが良いのではないかと考えました。最近読んでいる確かな力が身に付くC#「超」入門風に描くと、下記のように考えると効率よくスクリプトが書けるのではと予想します。

これで、役判定スクリプトを2つ用意する必要は無い事になります。クラスの中身は大まかに考えると、下記のようになれば理想的なのかなと考えます。

そして、 プレイヤーごとにインスタンス化するために下記のような流れでクラスを呼び出せば大枠はOKという事になりそうな予感がします。

public int number;
public string screen;

Rank.player1 = new Rank();
player1.player = PhotonNetwork.Player.ID;
player1.top = new int[3] {#,#,#};
player1.middle = new int[5] {#,#,#,#,#};
player1.bottom = new int[5] {#,#,#,#,#};

screen = player1.RankJudge();
number = player1.RankCalc();

しかし、一度書いたあの判定スクリプトを汎用性を高めるために再度書き直す事を考えると寒気がするので、判定スクリプトは複製してbottomに適応する事にします。クラスを使った、より良い書き方は、3/5/5の一番上(top)のハンドの判定で使用してみたいと思います。

まず、TopGameControler.csを作成し、空のオブジェクトにアタッチします。大枠は下記のようになるのではないかと完成予想図をザックリと書いてみました。

public class TopGameControler : MonoBehaviour {

    //変数
    private int player;
    private int[] handRank;

    int[] handNumber;

    string hand;
    int rankPoint;

   
    public TopGameControler(int player, int[] handRank) //コンストラクタを使用
    {
        this.player = player;
        this.handRank = handRank;
    }
   
    public string RankJudge()
    {
        //役判定メソッド本体がここに入る
        return hand;
    }
    
    public int RankCalc()
    {
        //得点計算メソッド本体がここに入る
        return rankPoint;
    }
}

一方、プレイヤー毎にTopGameControlerクラスをインスタンス化して、実際の得点をRoomCustomPropetyへ送るクラスも必要になります。そのクラスをTopRankSenderとします。空のオブジェクトにTopRankSender.csをアタッチし、以下のように大枠を考えてみました。

public class TopRankSender : MonoBehaviour
{
    string topRank;
    int topWinner;

    int[] TopHandRank = new int[] { (int)PhotonNetwork.room.customProperties[PhotonNetwork.player.ID+"Topcard0"],
        (int)PhotonNetwork.room.customProperties[PhotonNetwork.player.ID + "TopCard1"],
        (int)PhotonNetwork.room.customProperties[PhotonNetwork.player.ID +"TopCard2"] };

    TopGameControler myplayer = new TopGameControler( PhotonNetwork.player.ID, TopHandRank);

    topRank = myplayer.RankJudge();
    topWinner = myplayer.RankCalc();

}

この考え方で上手くいくのではないかと思ったのですが、エラーが沢山出てしまいました。”コンストラクタ、C#、Unity”で検索してみると、Unityではコンストラクタを推奨していないとの記事をいくつか発見し、この書き方は一度忘れて、いままで通りのやり方でTopの役判定プログラムを作っていく事にしました。自分でもチキンだと思いますが、まずはプログラムを一度完成させる事を優先して先を急ぎます。

Topの手役は3カードとワンペアのみしか判定しませんので、少ない行数で済みました。ストレートやフラッシュは3枚の場合役の強さと出現率が前後する可能性があるのでカウントしません。桁数も少なくて良さそうでしたので、結局16進法で進めました。判別の仕方は下記のようになります。

"pig"   0ABC
"1pair" 1AB0
"3card" 2A00

役判別と点数計算のクラス、TopGameControler.csを空のオブジェクトにアタッチして、挙動を確認します。Middle,Bottomと同様の書き方で判別ができるように書いてあります。

public class TopGameControler : MonoBehaviour {

    //変数
    private int player;
    private int[] handRank;

    int[] handNumber;

    public string hand;
    int rankPoint;

    GameObject[] tagObjects;
    int buttonX;

    private void Awake()
    {
        handRank = new int[3] { 0, 0, 0};
    }

    private void Update()
    {
        tagObjects = GameObject.FindGameObjectsWithTag("bar");
    }

    void OnJoinedRoom()
    {

        if (PhotonNetwork.player.ID == 1)
        {
            buttonX = 890;
        }
        else
        {
            buttonX = 20;
        }
    }

    void OnGUI()
    {
        if (tagObjects.Length != 0)
        {
            if (GUI.Button(new Rect(buttonX, 70, 100, 28), "check hand!!"))
            {

                int rank = (int)PhotonNetwork.room.customProperties[PhotonNetwork.player.ID + "topRankhand0"];
                int rankB = (int)PhotonNetwork.room.customProperties[PhotonNetwork.player.ID + "topRankhand1"];
                int rankC = (int)PhotonNetwork.room.customProperties[PhotonNetwork.player.ID + "topRankhand2"];

                handRank = new int[3] { rank, rankB, rankC}; //リストの作成
                RankJudge();
            }
        }
    }


    public void RankJudge()
    {
        //役判定メソッド本体がここに入る
        if (handRankCalc() > 2 * 16 * 16 * 16)
        {
            Debug.Log("You got 3 of a kind! " + handRankCalc());
            hand = "You got 3 of a kind!" + handRankCalc();
            sendhandrank(handRankCalc());
        }
        else if (handRankCalc() > 16* 16 * 16)
        {
            Debug.Log("You got one pair" + handRankCalc());
            hand = "You got one pair" + handRankCalc();
            sendhandrank(handRankCalc());
        }
        else if (handRankCalc() > 13)
        {
            string i;
            Debug.Log("you are pig." + handRankCalc());
            i = "you are pig." + handRankCalc().ToString();
            hand = i;
            sendhandrank(handRankCalc());
        }
        else
        {
            Debug.Log("You are mistery, report this bug");
            hand = "You are mistery, report this bug";
        }
    }
    
    public int handRankCalc()
    {
        //得点計算メソッド本体がここに入る
    
        int k;

        handNumber = new int[3] {0, 0, 0};

        for (k = 0; k < 3; k++)
        {
            if (handRank[k] % 13 != 0)
            {
                handNumber[k] = handRank[k] % 13 + 1;
            }
            else
            {
                handNumber[k] = 14;
            }
        }

        var list = new List<int>();
        list.AddRange(handNumber);
        list.Sort();
        list.Reverse();

        int i;
        int j;
        int doubling = 0;
        for (i = 0; i < list.Count; i++)
        {
            for (j = i + 1; j < list.Count; j++)
            {
                if (list[i] == list[j])
                {
                    doubling++;
                }
            }
        }
        if (doubling == 1)
        {
            ///ワンペアの場合
            int rankPoint;
            
            int z;
            int pairIndex = 0;
            int pairNum;
            for (z = 0; z < 4; z++)
            {

                if (list[z] == list[z + 1]) // 連番で一致する場所を確認する
                {

                    break;
                }
                pairIndex++; // ペアが存在するインデックスの開始位置
            }
            pairNum = list[pairIndex]; //ペアのナンバー
            list.RemoveAll(p => p == list[pairIndex]);//ナンバーと一致している数を取り除く

            ///rankpoint = 16進法で一桁目がペア、それから大きい順に残りの3つの数字が並ぶ
            rankPoint = 16*16*16 + pairNum * 16 *16 + list[0] *16;
            list = new List<int>() { pairNum, pairNum, list[0]};

            return rankPoint;
        }

        else if (doubling == 3)
        {
            ///スリーカードの場合
            int rankPoint;

            rankPoint = 2 * 16 * 16 * 16 + list[0] * 16 * 16;

            return rankPoint;

        }

        else
        {
            ///豚の場合
            int rankPoint;
            ///rankpoint = 16進法で5桁 0xfffff >  0x11111
            rankPoint = list[0] * 16 * 16 + list[1] * 16 + list[2]  ;

            return rankPoint;
        }
    }

    void sendhandrank(int i)
    {
        i = handRankCalc();
        var properties = new ExitGames.Client.Photon.Hashtable();
        properties.Add(PhotonNetwork.player.ID + "top", i);
        PhotonNetwork.room.SetCustomProperties(properties);
    }
}

今回は役の点数が小さいのでdoubleではなくintで扱う事にしました。この役計算スクリプトを利用してその他のスクリプトも調整した結果、3/5/5の全てにおいて、正しく勝敗判定がされたことが確認できます。

おすすめの記事