ここまで来れたらウイニングラン。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にリーチ状態を表示させる
コメント