突然ですが、Unityでオセロ作ってます。
本記事では、その制作過程をご紹介します。

無題_

・Prefabの作成
下図のようなPrefabを作成します。
無題

・クラス設計
クラス設計は以下のようにしました。
BoardScriptがボード全体を、GridScriptがボードの中の各グリッドを、StoneScriptがグリッドに置かれる各石を表しています。
GameScriptがゲームを統括するクラスで、グリッドのタップを検知し、GridScriptに対して石を置いたり、ひっくり返したりといった処理をさせます。
GridScriptクラスが自分の周辺のグリッドの情報をBoardScriptクラスから得られるように双方向関連を持たせています。
無題_

・StoneScript
StoneScriptクラスは、自分が黒石か白石かという情報だけを扱います。
using UnityEngine;
using System.Collections;

public class StoneScript : MonoBehaviour {

bool isBlack_;

public bool IsBlack()
{
return isBlack_;
}

public void IsBlack(bool isBlack)
{
isBlack_ = isBlack;
}

// Use this for initialization
void Start () {
}

// Update is called once per frame
void Update () {

}
}
・BoardScript
BoardScriptクラスは、最初にグリッド群(オセロ盤)を生成し、ゲーム中は指定された場所にあるグリッドの情報を(GameScriptクラスに)提供します。
using UnityEngine;
using System.Collections;

public class BoardScript : MonoBehaviour {

public GameObject gridPrefab_, blackStonePrefab_, whiteStonePrefab_;
int colNum_ = 8, rowNum_ = 8; // 縦横のグリッド数
int planeSize_ = 10; // 1グリッドの大きさ
GameObject[] grids_ = new GameObject[64];

public int GetColNum()
{
return colNum_;
}

public int GetRowNum()
{
return rowNum_;
}

public GameObject GetGrid(int colNo, int rowNo)
{
return grids_[rowNo * colNum_ + colNo];
}

// グリッド群(オセロ盤)の生成
void MakeGrids()
{
// 盤中心から端グリッド中心までの距離[グリッド分]
float offsetX = colNum_ / 2 - 0.5f;
float offsetZ = rowNum_ / 2 - 0.5f;

for (int r = 0; r < rowNum_; ++r)
{
float posZ = (offsetZ - r) * planeSize_; // グリッド中心のz座標
for (int c = 0; c < colNum_; ++c)
{
// グリッドの生成
float posX = (c - offsetX) * planeSize_; // グリッド中心のx座標
Vector3 pos = new Vector3(posX, 0, posZ); // グリッド中心の三次元座標
GameObject grid = (GameObject)Instantiate(
gridPrefab_, pos, Quaternion.identity); // グリッドの生成

// グリッドの登録
GridScript gridScript = grid.GetComponent<GridScript>();
gridScript.SetColNo(c);
gridScript.SetRowNo(r);
gridScript.SetBlackStonePrefab(blackStonePrefab_);
gridScript.SetWhiteStonePrefab(whiteStonePrefab_);
gridScript.SetBoardScript(this);
grids_[r * colNum_ + c] = grid;
}
}

// 初期配置の生成
int right = colNum_ / 2;
int left = right - 1;
int bottom = rowNum_ / 2;
int top = rowNum_ / 2 - 1;
grids_[top * colNum_ + left].GetComponent<GridScript>().PutStone(false);
grids_[bottom * colNum_ + right].GetComponent<GridScript>().PutStone(false);
grids_[top * colNum_ + right].GetComponent<GridScript>().PutStone(true);
grids_[bottom * colNum_ + left].GetComponent<GridScript>().PutStone(true);

// Use this for initialization
void Start () {
MakeGrids();
}

// Update is called once per frame
void Update()
{
}
}
・GridScript
GridScriptはグリッドの上に石を置けるか判断する、石を置く、石をひっくり返すといった処理を行います。
石を置けるかの判断や石をひっくり返す処理は再帰処理で実現しています(もっとスマートにできる気が)。
using UnityEngine;
using System.Collections;

public class GridScript : MonoBehaviour {

GameObject stone_;
GameObject blackStonePrefab_, whiteStonePrefab_;
BoardScript boardScript_;
int colNo_, rowNo_;
int colNum_, rowNum_;
int dirNum_ = 8; // 8方向
int[] dirCol_ = new int[8] { -1, 0, 1, -1, 1, -1, 0, 1 }; // 各方向の移動量
int[] dirRow_ = new int[8] { -1, -1, -1, 0, 0, 1, 1, 1 }; // 各方向の移動量

public void SetColNo(int colNo)
{
colNo_ = colNo;
}

public void SetRowNo(int rowNo)
{
rowNo_ = rowNo;
}

public void SetBlackStonePrefab(GameObject blackStonePrefab)
{
blackStonePrefab_ = blackStonePrefab;
}

public void SetWhiteStonePrefab(GameObject whiteStonePrefab)
{
whiteStonePrefab_ = whiteStonePrefab;
}

public GameObject GetStone()
{
return stone_;
}

public void SetBoardScript(BoardScript boardScript)
{
boardScript_ = boardScript;
}

bool SearchSameColorStone(bool isBlackTurn, int dirNum, int colNo, int rowNo)
{
if (colNo >= 0 && colNo < boardScript_.GetColNum() && rowNo >= 0 && rowNo < boardScript_.GetRowNum())
{
GameObject grid = boardScript_.GetGrid(colNo, rowNo);
GameObject stone = grid.GetComponent<GridScript>().GetStone();
if (stone && stone.GetComponent<StoneScript>().IsBlack() == isBlackTurn)
{
return true;
}
else
{
return SearchSameColorStone(isBlackTurn, dirNum, colNo + dirCol_[dirNum], rowNo + dirRow_[dirNum]);
}
}
return false;
}

bool JudgeStonePutableDir(bool isBlackTurn, int dir)
{
// 1個目が自分と異なる色か確認
int colNo = colNo_ + dirCol_[dir];
int rowNo = rowNo_ + dirRow_[dir];
if (colNo >= 0 && colNo < boardScript_.GetColNum() && rowNo >= 0 && rowNo < boardScript_.GetRowNum())
{
GameObject grid = boardScript_.GetGrid(colNo, rowNo);
GameObject stone = grid.GetComponent<GridScript>().GetStone();
if (stone && stone.GetComponent<StoneScript>().IsBlack() != isBlackTurn)
{
// 自分と同じ色の石を探索していく
return SearchSameColorStone(isBlackTurn, dir, colNo + dirCol_[dir], rowNo + dirRow_[dir]);
}

}
return false;
}

public bool JudgeStonePutable(bool isBlackTurn)
{
for (int d = 0; d < dirNum_; ++d)
{
if (JudgeStonePutableDir(isBlackTurn, d))
{
return true;
}
}
return false;
}

void TurnStoneDir(bool isBlackTurn, int dir, int colNo, int rowNo)
{
if (colNo >= 0 && colNo < boardScript_.GetColNum() && rowNo >= 0 && rowNo < boardScript_.GetRowNum())
{
GameObject grid = boardScript_.GetGrid(colNo, rowNo);
GameObject stone = grid.GetComponent<GridScript>().GetStone();
if (stone && stone.GetComponent<StoneScript>().IsBlack() != isBlackTurn)
{
Destroy(stone);
grid.GetComponent<GridScript>().PutStone(isBlackTurn);
TurnStoneDir(isBlackTurn, dir, colNo + dirCol_[dir], rowNo + dirRow_[dir]);
}
else
{
return;
}
}
}

public void TurnStone(bool isBlackTurn)
{
for (int d = 0; d < dirNum_; ++d)
{
if (JudgeStonePutableDir(isBlackTurn, d))
{
TurnStoneDir(isBlackTurn, d, colNo_ + dirCol_[d], rowNo_ + dirRow_[d]);
}
}
}

public void PutStone(bool isBlack)
{
// 黒か白のPrefabを設定
GameObject stonePrefab;
if (isBlack) stonePrefab = blackStonePrefab_;
else stonePrefab = whiteStonePrefab_;

// 石を置く
stone_ = (GameObject)Instantiate(stonePrefab, transform.position, Quaternion.identity);

// 石の色を設定
stone_.GetComponent<StoneScript>().IsBlack(isBlack);
}

// Use this for initialization
void Start()
{
}

// Update is called once per frame
void Update()
{
}
}
・GameScript
GameScriptクラスは、タップを検知し、グリッドがタップされていたら、GridScriptに各処理を実行させます。
using UnityEngine;
using System.Collections;

public class GameScript : MonoBehaviour {

bool isBlackTurn;

// タップを検知し、GridScriptを取得する
bool DetectTap(out GridScript gridScript)
{
gridScript = null;
if (Input.GetMouseButtonDown(0)) // タップ検知
{
Ray ray = Camera.main.ScreenPointToRay(Input.mousePosition);
RaycastHit hit = new RaycastHit();
if (Physics.Raycast(ray, out hit))
{
GameObject obj = hit.collider.gameObject; // タップしたGameObjectを取得
gridScript = obj.GetComponent<GridScript>(); // GridScriptを取得
return true;
}
}
return false;
}

// Use this for initialization
void Start () {
isBlackTurn = true;
}

// Update is called once per frame
void Update () {
// タップ検知
GridScript gridScript;
if (DetectTap(out gridScript))
{
// グリッドをタップしており、かつ、そこに石が無いなら
if (gridScript && !gridScript.GetStone())
{
// そこに石を置けるなら
if (gridScript.JudgeStonePutable(isBlackTurn))
{
// 石を置く
gridScript.PutStone(isBlackTurn);

// ひっくり返す
gridScript.TurnStone(isBlackTurn);

// 相手のターンに変更
isBlackTurn = !isBlackTurn;
}
}
}
}
}
あとは、GameScriptとBoardScriptを持つGameObjectを生成したり、各ScriptにPrefabを登録すれば動くはずです。
次回は対戦相手のAIか3D化を実装したいと思います。

続き
http://akasuku.blog.jp/archives/66804617.html