見出し画像

[Unity Blocks 10]ボード上に重ならないようにピースを置く

視覚的に好きなピースをボードに置くことができたので、ピースが重なる場合は置けないようにしたいと思います。

ボード用のスクリプトを作成する

14×14のintの2重配列をボードに見立てていきます。全ての位置を0に初期化しておき、ピースを置いたときにその場所の値をプレイヤー番号にします。

もしピースを置こうとしている場所の値が0でなければそこにはピースが置かれており、もうピースは置けないという感じですね。

まずはボードに追加するスクリプトです。

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

public class Board : MonoBehaviour
{
   public int[,] BoardInfo{get; set;} //ボードのピースの位置を管理する2重配列

   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 (!Utils.IsPieceInBoard(Point))
               return false;
           if (BoardInfo[Point[0], Point[1]] != 0)
               return false;
       }
       foreach (int[] Point in PieceDesign)
       {
           BoardInfo[Point[0], Point[1]] = PlayerNum + 1;
       }
       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);
   }
}

SetPieceにピースの形をListの形式で引数として渡すだけですね。

C#では同じ関数名でも引数の数などが異なれば別の関数としてみてくれます。呼ぶ機会があるか分かりませんが、ピースの形と基点を渡してピースを置く関数とピースの絶対位置を渡してピースを置く関数を作っています。

PieceControllerも改良する

また、ピースの基点となる位置をPieceControllerが知っている必要があるため、少し改良しました。

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

public class PieceController : MonoBehaviour
{
   [SerializeField]
   Material[] Materials;

   Vector3 SpawnPoint;
   Vector3 DotPoint;
   int PlayerNum;
   const int MaxPlayer = 2;
   List<List<GameObject>> AllPieceList; //ピースオブジェクトのリスト
   int PieceCount = 1;
   GameObject ControlPiece; //操作中のピース
   Board BoardScript;
   int[] PiecePivot; //現在操作中のピースの原点の位置

   //スタート時に動く関数
   void Start()
   {
       BoardScript = GameObject.Find("Board").GetComponent<Board>();
       PiecePivot = new int[]{0, 0};
       AllPieceList = new List<List<GameObject>>();
       SpawnPoint = new Vector3(-0.065f, 0.05f, 0.065f);
       DotPoint = this.transform.position;
       CreatePieces(new Vector3(0.12f, 0.1f, 0.15f), 0);
       CreatePieces(new Vector3(-0.36f, 0.1f, 0.15f), 1);
       ChangeControlPiece(-1);
   }

   //プレイヤー分のピースを生成する。初期状態では重力無し
   //AllPieceListに生成したピースのオブジェクトを保管しておく
   //PieceWaitPoint:ピースの生成位置。基本的にここでピースは待機する
   void CreatePieces(Vector3 PieceWaitPoint, int MaterialNum)
   {
       List<GameObject> PlayerPieceList = new List<GameObject>();
       foreach(string PieceName in ConstList.PieceList)
       {
           GameObject NewPiece = Instantiate((GameObject)Resources.Load(PieceName));
           NewPiece.GetComponent<Rigidbody>().useGravity  = false;
           NewPiece.transform.position = PieceWaitPoint;
           NewPiece.GetComponent<Piece>().WaitPoint = PieceWaitPoint;
           PlayerPieceList.Add(NewPiece);
           PieceWaitPoint = StepPieceWaitPoint(PieceWaitPoint);
           SetMaterialToChild(NewPiece, Materials[MaterialNum]);
       }
       AllPieceList.Add(PlayerPieceList);
   }

   //ピース生成中、ピース間の距離分移動
   Vector3 StepPieceWaitPoint(Vector3 WaitPoint)
   {
       WaitPoint += new Vector3(0f, 0f, -0.06f);
       if (WaitPoint.z < -0.15f)
       {
           WaitPoint.x += 0.06f;
           WaitPoint.z = 0.15f;
       }
       return WaitPoint;
   }

   //F,Gでピース変更。スペースでピース設置
   //WASDでピース移動
   void Update()
   {
       if (Input.GetKeyDown(KeyCode.F))
           ChangeControlPiece(1);
       if (Input.GetKeyDown(KeyCode.G))
           ChangeControlPiece(-1);
       if (Input.GetKeyDown(KeyCode.Space))
       {
           SetPiece();
       }
       if (Input.GetKeyDown(KeyCode.W))
           MoveSpawnPoint(new Vector3(0f, 0f, 0.01f));
       if (Input.GetKeyDown(KeyCode.S))
           MoveSpawnPoint(new Vector3(0f, 0f, -0.01f));
       if (Input.GetKeyDown(KeyCode.D))
           MoveSpawnPoint(new Vector3(0.01f, 0f, 0f));
       if (Input.GetKeyDown(KeyCode.A))
           MoveSpawnPoint(new Vector3(-0.01f, 0f, 0f));
   }

   //ピースを置く。重力はオンにする。
   //置いたピースはAllPieceListから削除する
   //PieceCountはリセット。その後ChangeControlPieceで一番最初のピースを持たせる
   public bool SetPiece()
   {
       Piece ControlPieceScript;
       if (ControlPiece == null)
           return false;
       ControlPieceScript = ControlPiece.GetComponent<Piece>();
       bool IsSpace = BoardScript.SetPiece(ControlPieceScript.Design, PiecePivot, PlayerNum);
       if (!IsSpace)
           return false;

       ControlPiece.GetComponent<Rigidbody>().useGravity  = true;
       ControlPieceScript.IsSet = true;
       AllPieceList[PlayerNum].Remove(ControlPiece);
       IncreasePlayerNum();
       ControlPiece = null;
       PieceCount = 1;
       ChangeControlPiece(-1);
       return true;
   }

   //操作するピースを変更する。引数で次のピースか前のピースか決めている。
   //操作から離れたピースは最初の生成位置に戻る
   void ChangeControlPiece(int Dir)
   {
       int MaxPiece = (AllPieceList[PlayerNum].Count);
       if (MaxPiece == 0)
           return;
       if (ControlPiece != null)
           ControlPiece.GetComponent<Piece>().ReturnWaitPoint();
       PieceCount += Dir;
       if (PieceCount >= MaxPiece)
           PieceCount = 0;
       if (PieceCount <= -1)
           PieceCount = MaxPiece - 1;
       ControlPiece = AllPieceList[PlayerNum][PieceCount];
       ControlPiece.transform.position = this.SpawnPoint;
   }

   void IncreasePlayerNum()
   {
       PlayerNum += 1;
       if (PlayerNum == MaxPlayer)
           PlayerNum = 0;
   }

   public void MoveSpawnPoint(Vector3 diff)
   {
       if (ControlPiece == null)
           return ;

       int PointY = PiecePivot[0] - (int)(Mathf.Round(diff.z * 100));
       int PointX = PiecePivot[1] + (int)(Mathf.Round(diff.x * 100));
       if (PointX < 0 || ConstList.BoardSize <= PointX || 
       PointY < 0 || ConstList.BoardSize <= PointY)
           return;
       this.transform.position += diff;
       SpawnPoint += diff;
       diff *= 100;
       PiecePivot[0] -= (int)(Mathf.Round(diff.z));
       PiecePivot[1] += (int)(Mathf.Round(diff.x));
       ControlPiece.transform.position = this.SpawnPoint;
   }

   void SetMaterialToChild(GameObject Obj, Material Material)
   {
       foreach (Transform Child in Obj.transform)
       {
           Child.GetComponent<Renderer>().material = Material;
       }
   }
}

PiecePivotというピースの基点がボードのどこの位置にあるかを保存しています。PieceDesignで使ったようなコードですね。

これでどのプレイヤーのピースがどこに配置されているかが分るようになりました。

次回

この記事が気に入ったらサポートをしてみませんか?