ビンゴが成立した情報を表示に反映する:最終回

ここまで来れたらウイニングラン。sub infomationを更新する処理を実装して締めたいと思います。

目次

sub infomationを更新する処理を追加

文字を変更する処理は、イベントを介して行います。送る側と受け取る側、両方の処理が必要ですね。

文字の更新を促す処理を追加

BingoManagerから文字を変更して欲しい時にお願いをする処理を追加します。イベント着火用の変数と、メッセージを送信する処理を追加します。追加箇所は以下

  • NewGameメソッド内で文字をリセットする
  • Nextメソッド内でビンゴが成立した時にメッセージを送る処理
public class BingoManager : MonoBehaviour
{
    // staticなイベントを作成
    public static System.Action<string> OnChangeSubInfoText;

    public void NewGame()
    {
        GenerateBingoCard(25);
        for (int i = 0; i < SQUARE_COUNT; i++)
        {
            cardAreaView.SetCardNumber(i, bingoSquareList[i].number);
            cardAreaView.SetCardClose(i);
        }
        OnChangeSubInfoText?.Invoke("");
    }

    public void Next()
    {
        // まだ空いていないSquareを探す
        int number = GetRandomNumber();
        if (number == -1)
        {
            return;
        }

        // イベント発信
        OnBingoNumber?.Invoke(number);

        // 数字から何番目のSquareのIndexかを探す
        int squareIndex = bingoSquareList.FindIndex(x => x.number == number);

        // 要素内に存在しない場合はエラー
        if (squareIndex == -1)
        {
            Debug.Log($"number:{number} squareIndex:{squareIndex}");
            return;
        }
        // 表示更新(ここもイベント化しても良さそう)
        cardAreaView.SetCardOpen(squareIndex);
        // 変数の更新
        bingoSquareList[squareIndex].isOpen = true;

        if (IsBingo(squareIndex))
        {
            // ここでSubInfo向けに変更したい文字を入力Bingo!!にしたりして見てください
            // ちなみにTextMeshProの関係で、日本語は使えないぞ!
            OnChangeSubInfoText?.Invoke("Bingo!");
            Debug.Log("Bingo!(Nextメソッドのログを修正)");
        }
    }
}

BingoManagerのプログラムはこれで終わりなので、全文は以下。

using System.Collections;
using System.Collections.Generic;
using UnityEngine;

public class BingoSquare
{
    public int number;
    public bool isOpen;
}

public class BingoManager : MonoBehaviour
{
    public const int SQUARE_COUNT = 25;
    private List<BingoSquare> bingoSquareList = new List<BingoSquare>();
    [SerializeField] private CardAreaView cardAreaView;

    private List<int> bingoNumberBuffer = new List<int>();
    public static System.Action<int> OnBingoNumber;
    public static System.Action<string> OnChangeSubInfoText;

    private void GenerateBingoCard(int maxNumber)
    {
        bingoSquareList.Clear();
        bingoNumberBuffer.Clear();
        maxNumber = Mathf.Min(Mathf.Max(maxNumber, SQUARE_COUNT), 99);
        List<BingoSquare> tempList = new List<BingoSquare>();
        for (int i = 1; i <= maxNumber; i++)
        {
            BingoSquare bingoSquare = new BingoSquare();
            bingoSquare.number = i;
            bingoSquare.isOpen = false;
            tempList.Add(bingoSquare);
            bingoNumberBuffer.Add(i);
        }
        for (int i = 0; i < SQUARE_COUNT; i++)
        {
            int randomIndex = Random.Range(0, tempList.Count);
            bingoSquareList.Add(tempList[randomIndex]);
            tempList.RemoveAt(randomIndex);
        }
    }

    private void Start()
    {
        NewGame();
    }

    public void NewGame()
    {
        GenerateBingoCard(25);
        for (int i = 0; i < SQUARE_COUNT; i++)
        {
            cardAreaView.SetCardNumber(i, bingoSquareList[i].number);
            cardAreaView.SetCardClose(i);
        }
        OnChangeSubInfoText?.Invoke("");
    }

    public void Next()
    {
        // まだ空いていないSquareを探す
        int number = GetRandomNumber();
        if (number == -1)
        {
            return;
        }

        // イベント発信
        OnBingoNumber?.Invoke(number);

        // 数字から何番目のSquareのIndexかを探す
        int squareIndex = bingoSquareList.FindIndex(x => x.number == number);

        // 要素内に存在しない場合はエラー
        if (squareIndex == -1)
        {
            Debug.Log($"number:{number} squareIndex:{squareIndex}");
            return;
        }
        // 表示更新(ここもイベント化しても良さそう)
        cardAreaView.SetCardOpen(squareIndex);
        // 変数の更新
        bingoSquareList[squareIndex].isOpen = true;

        if (IsBingo(squareIndex))
        {
            OnChangeSubInfoText?.Invoke("Bingo!");
            Debug.Log("Bingo!(Nextメソッドのログを修正)");
        }
    }

    private int GetRandomNumber()
    {
        if (bingoNumberBuffer.Count == 0)
        {
            return -1;
        }
        int randomIndex = Random.Range(0, bingoNumberBuffer.Count);
        int bingoNumber = bingoNumberBuffer[randomIndex];
        bingoNumberBuffer.RemoveAt(randomIndex);
        return bingoNumber;
    }

    private void DebugShowRowLine(int index)
    {
        int row = index / 5;
        for (int i = 0; i < 5; i++)
        {
            Debug.Log($"row:{row} col:{i} {bingoSquareList[row * 5 + i].number}");
        }
    }
    private void DebugShowColLine(int index)
    {
        int col = index % 5;
        for (int i = 0; i < 5; i++)
        {
            Debug.Log($"row:{i * 5} col:{col} {bingoSquareList[i * 5 + col].number}");
        }
    }
    // 特定のsquareでBingoになっているかを判定する
    public bool IsBingo(int squareIndex)
    {
        // まずはsquareIndexが有効かを確認する
        if (squareIndex < 0 || SQUARE_COUNT <= squareIndex)
        {
            return false;
        }
        // そのsquareが開いているかを確認する
        if (!bingoSquareList[squareIndex].isOpen)
        {
            return false;
        }
        // そのsquareがBingoになっているかを確認する
        int row = squareIndex / 5;
        int col = squareIndex % 5;
        // 横の判定
        bool isBingo = true;
        for (int i = 0; i < 5; i++)
        {
            if (!bingoSquareList[row * 5 + i].isOpen)
            {
                isBingo = false;
                break;
            }
        }
        if (isBingo)
        {
            return true;
        }

        // 縦の判定
        isBingo = true;
        for (int i = 0; i < 5; i++)
        {
            if (!bingoSquareList[col + i * 5].isOpen)
            {
                isBingo = false;
                break;
            }
        }
        if (isBingo)
        {
            return true;
        }

        // 右下がり:左上から右下の斜め判定
        isBingo = true;
        for (int i = 0; i < 5; i++)
        {
            if (!bingoSquareList[i * 6].isOpen)
            {
                isBingo = false;
                break;
            }
        }
        if (isBingo)
        {
            Debug.Log("右下がり:左上から右下の斜め判定");
            return true;
        }

        // 右上がり:右上から左下の斜め判定
        isBingo = true;
        for (int i = 0; i < 5; i++)
        {
            if (!bingoSquareList[(i + 1) * 4].isOpen)
            {
                isBingo = false;
                break;
            }
        }
        if (isBingo)
        {
            Debug.Log("右上がり:右上から左下の斜め判定");
            return true;
        }
        return false;
    }
}

受け取る側の処理

AreaInfoViewを更新します。基本的には選択された番号の更新と同じです。ただし、最初にsubInfomationが表示されていると不自然なので、起動時になんの文字も表示されていないようにしましょう。

using UnityEngine;
using TMPro;

public class AreaInfoView : MonoBehaviour
{
    [SerializeField] private TextMeshProUGUI currentNumberText;
    [SerializeField] private TextMeshProUGUI subInfoText;

    public TextMeshProUGUI CurrentNumberText => currentNumberText;
    public TextMeshProUGUI SubInfoText => subInfoText;

    private void Awake()
    {
        BingoManager.OnBingoNumber += (number) =>
        {
            currentNumberText.text = number.ToString();
        };
        subInfoText.text = "";
        BingoManager.OnChangeSubInfoText += (text) =>
        {
            subInfoText.text = text;
        };
    }
}

実際に動かしてみる

動作確認

あとは実際に動かしてみて確認してみましょう。確認するポイントとしては以下。

  • 起動時にsub Infomationの文字が消える
  • ビンゴ成立時にBingo!の文字が表示される
  • New Game時に文字が消える

チャレンジ

基本になる部分は作ることが出来ました。あとは各々で独自にカスタマイズや変更を行ってみてください。難易度高いものもありますが、以下のような変更が出来るといいですね。

  • ビンゴしたらNextボタンを押せないようにする
  • ビンゴが成立したラインの色だけ変更する
  • リーチになったらsub Infomatonにリーチ状態を表示させる
よかったらシェアしてね!
  • URLをコピーしました!
  • URLをコピーしました!

この記事を書いた人

コメント

コメントする

目次