[Unity Blocks 11]ブロックスのルールに則ってピースを置く。反転・回転を実装する
次はブロックスのルールである、「ピースの辺同士が接触してはいけない」「頂点のどこかが自分のピースと接していなければならない」部分を実装します。
ボードのスクリプトに追加する
BoardのSetPieceでの確認事項を増やす形にしています。
using System.Collections;
using System.Collections.Generic;
using UnityEngine;
public class Board : MonoBehaviour
{
public int[,] BoardInfo{get; set;} //ボードのピースの位置を管理する2重配列
List<int> SetPlayer = new List<int>(); //ピースを置いたことのあるプレイヤーリスト
void Start()
{
BoardInfo = new int[ConstList.BoardSize,ConstList.BoardSize];
}
void Update()
{
}
public bool SetPiece(List<int[]> PieceDesign, int[] Pivot, int PlayerNum)
{
List<int[]> NewPieceDesign = new List<int[]>();
foreach (int[] Point in PieceDesign)
{
int[] TmpPoint = new int[]{0, 0};
TmpPoint[0] = Point[0] + Pivot[0];
TmpPoint[1] = Point[1] + Pivot[1];
NewPieceDesign.Add(TmpPoint);
}
return SetPiece(NewPieceDesign, PlayerNum);
}
//ピースを置く。置けない場合はfalseを返し、置けた場合はBoardInfoに書き込んで、trueを返す。
//初めて置く場合は頂点が接している条件を満たせないので、別関数での確認
public bool SetPiece(List<int[]> PieceDesign, int PlayerNum)
{
foreach (int[] Point in PieceDesign)
{
if (!CheckBaseRule(Point, PlayerNum))
return false;
}
bool IsPossible = false;
foreach (int[] Point in PieceDesign)
{
if (!SetPlayer.Contains(PlayerNum + 1))
{
IsPossible = CheckStartRule(Point, PlayerNum);
}
else
{
IsPossible = CheckApplicationRule(Point, PlayerNum);
}
if (IsPossible)
break;
}
if (!IsPossible)
return false;
foreach (int[] Point in PieceDesign)
{
BoardInfo[Point[0], Point[1]] = PlayerNum + 1;
}
if (!SetPlayer.Contains(PlayerNum + 1))
SetPlayer.Add(PlayerNum + 1);
return true;
}
//スタート時はプレイヤーごとのスタート地点が違うので、CheckStartPointsで定義
//そこに入っているかを確認
bool CheckStartRule(int[] Point, int PlayerNum)
{
int[][] CheckStartPoints = new int[][]{new int[]{0, 0}, new int[]{13, 13}};
if (Point[0] == CheckStartPoints[PlayerNum][0] && Point[1] == CheckStartPoints[PlayerNum][1])
return true;
return false;
}
//頂点同士が接しているか
bool CheckApplicationRule(int[] Point, int PlayerNum)
{
int[][] CheckDiagonalPoints = new int[][]{new int[]{1, 1}, new int[]{-1, 1}, new int[]{1, -1}, new int[]{-1, -1}};
bool IsPossible = false;
foreach(int[] CheckPoint in CheckDiagonalPoints)
{
CheckPoint[1] += Point[1];
CheckPoint[0] += Point[0];
if (!Utils.IsPieceInBoard(CheckPoint))
continue;
if (BoardInfo[CheckPoint[0], CheckPoint[1]] == PlayerNum + 1)
IsPossible = true;
}
return IsPossible;
}
//基本的なルールに則しているか確認
//重なっていない、ボードからはみ出ていない、自分のピースの辺が接していない
public bool CheckBaseRule(int[] Point, int PlayerNum)
{
if (!Utils.IsPieceInBoard(Point))
return false;
if (BoardInfo[Point[0], Point[1]] != 0)
return false;
if (!CheckAdjacentRule(Point, PlayerNum))
return false;
return true;
}
public bool CheckAdjacentRule(int[] Point, int PlayerNum)
{
int[][] CheckAdjacentPoints = new int[][]{new int[]{1, 0}, new int[]{-1, 0}, new int[]{0, 1}, new int[]{0, -1}};
foreach(int[] CheckPoint in CheckAdjacentPoints)
{
CheckPoint[1] += Point[1];
CheckPoint[0] += Point[0];
if (!Utils.IsPieceInBoard(CheckPoint))
continue;
if (BoardInfo[CheckPoint[0], CheckPoint[1]] == PlayerNum + 1)
return false;
}
return true;
}
//デバッグ用
void PrintBoardInfo(int[,] Board)
{
int y = 0;
string PrintList = "\n";
for (; y < ConstList.BoardSize ;y++)
{
int x = 0;
for (; x < ConstList.BoardSize ;x++)
{
PrintList += (Board[y, x]) + " ";
}
PrintList += "\n";
}
Debug.Log(PrintList);
}
}
こんな感じです。
ピースの回転・反転を実装する
ピースのスクリプトを改良しました。
using System.Collections;
using System.Collections.Generic;
using UnityEngine;
public class Piece : MonoBehaviour
{
public List<int[]> Design{get; set;}
public Vector3 WaitPoint{get; set;} //ピースの待機場所
List<int[]> StartDesign;
int RotateAngle;
int ReverseAngle;
public bool IsSet; //置かれた後のピースか判断 あまり必要ないかも
void Start()
{
Design = PieceDesign.ReturnDesign(this.gameObject);
StartDesign = Design;
}
void Update()
{
}
//ボードで設定されているピース待機場所に戻る
public void ReturnWaitPoint()
{
this.transform.position = WaitPoint;
}
//ピースの回転。反転中は回転方向を逆にしています。回転方向は引数の±で判断
public void Rotate(int Dir)
{
foreach (int[] Piece in Design)
{
int[] Tmp = new int[]{Piece[0], Piece[1]};
Piece[1] = -1 * Dir *Tmp[0];
Piece[0] = 1 * Dir *Tmp[1];
}
if (ReverseAngle != 0)
Dir *= -1;
RotateAngle += 90 * Dir;
Quaternion TmpQ;
TmpQ = Quaternion.AngleAxis(RotateAngle, new Vector3(0, 1, 0));
transform.rotation = Quaternion.AngleAxis(ReverseAngle, new Vector3(1, 0, 0)) * TmpQ;
if (RotateAngle >= 360 || RotateAngle <= -360)
RotateAngle = 0;
}
//ピースの反転
public void Reverse()
{
foreach (int[] Piece in Design)
{
Piece[0] = -Piece[0];
}
ReverseAngle += 180;
Quaternion TmpQ;
TmpQ = Quaternion.AngleAxis(RotateAngle, new Vector3(0, 1, 0));
transform.rotation = Quaternion.AngleAxis(ReverseAngle, new Vector3(1, 0, 0)) * TmpQ;
if (ReverseAngle >= 360)
ReverseAngle = 0;
}
//デバッグ用
public void DebugLogPieceList()
{
Debug.Log("====");
foreach (int[] A in Design)
{
Debug.Log(A[0] + " " + A[1]);
}
}
}
動かしてみる
良い感じですね。
次回
この記事が気に入ったらサポートをしてみませんか?