マインスイーパーの作り方

#マインスイーパーの作り方
詳しい作り方は動画で解説しているので、素材とコードだけを乗っけておきますw
https://youtu.be/LGvzNmZGq-Y
![0401サムネ.png](https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/1442441/6152af43-90a5-31c5-e4c6-941dac7498fe.png)



##素材はこちら
![bg.png](https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/1442441/6e755e4a-7f16-22c5-ed9c-43e7662340f5.png)![boom.png](https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/1442441/8b17320e-5477-aa25-e186-d77198d2a7ee.png)![cover.png](https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/1442441/afd77113-3462-5aad-b3ea-e4661ead3d1d.png)![flag.png](https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/1442441/43716b55-764b-ed04-2b14-6fea121a2234.png)![hatena.png](https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/1442441/2e78acd1-74c5-6fe5-5d18-39d388f9a183.png)
※動画で語ってないが、ゲームオーバーの時、ボムの後ろの赤い背景はテクスチャーを使ってないImageで作っていました。付け間違ったフラグに付けるバツはテキストの✕で作っていました。なのでこの二つに関しては素材がないです。

##カウントの文字に使う色のコードはこちら
1 → 0000F7　<font color=0000F7>■</font>　2 → 007C00　<font color=007C00>■</font>
3 → EC1F1F　<font color=EC1F1F>■</font>　4 → 00007C　<font color=00007C>■</font>
5 → 7C0000　<font color=7C0000>■</font>　6 → 007C7C　<font color=007C7C>■</font>
7 → 000000　<font color=000000>■</font>　8 → 7C7C7C　<font color=7C7C7C>■</font>
※大体ですw

##コードはこちら
###①右クリック対応ボタン

```C#
using UnityEngine;
using UnityEngine.EventSystems;
using UnityEngine.Serialization;
using UnityEngine.Events;
using System;

public class CCButton : MonoBehaviour, IPointerClickHandler
{
    [Serializable]
    public class LeftButtonClickedEvent : UnityEvent { }

    [FormerlySerializedAs("onLeftClick"), SerializeField]
    private LeftButtonClickedEvent m_OnLeftClick = new LeftButtonClickedEvent();

    [Serializable]
    public class RightButtonClickedEvent : UnityEvent { }

    [FormerlySerializedAs("onRightClick"), SerializeField]
    private RightButtonClickedEvent m_OnRightClick = new RightButtonClickedEvent();

    public void OnPointerClick(PointerEventData eventData) 
    {
        switch (eventData.button)
        {
            case PointerEventData.InputButton.Left:
                m_OnLeftClick.Invoke();
                break;
            case PointerEventData.InputButton.Right:
                m_OnRightClick.Invoke();
                break;
            case PointerEventData.InputButton.Middle:
                //中クリックの時の処理、はないです
                break;
            default:
                break;
        }
    }
}
```

###②タイル

```C#
using UnityEngine;
using UnityEngine.UI;

public enum TileType { EMPTY, BOOM, COUNT }
public class Tile : MonoBehaviour
{
    enum MarkState { NO_MARK, FLAG, QUESTION }
    public TileType TileType { get { return mTileType; } }
    public int Index { get { return mIndex; } }

    Manager mManager;
    TileType mTileType = TileType.EMPTY;
    MarkState mMarkState = MarkState.NO_MARK;
    int mIndex;
    bool mIsDigged = false;

    [SerializeField] GameObject mCover;
    [SerializeField] GameObject mFlag;
    [SerializeField] GameObject mQuestion;
    [SerializeField] GameObject mRedBG;
    [SerializeField] GameObject mRedCross;
    [SerializeField] Text mCount;
    [SerializeField] GameObject mBoom;
    [SerializeField] Color[] mCountCols = new Color[8];

    public void Initialize(Manager manager, int index)
    {
        mManager = manager; 
        mIndex = index;
    }

    //タイルを掘る
    public void OnDigged() 
    {
        if (mIsDigged || mMarkState == MarkState.FLAG)
            return;

        if (mMarkState == MarkState.QUESTION)
            mQuestion.SetActive(false);

        mIsDigged = true;

        mCover.SetActive(false); 
         
        switch (mTileType) 
        { 
            case TileType.EMPTY: 
                //マネージャーに隣接タイルを掘ってもらう 
                mManager.DigAround(mIndex);
                mManager.CountDiggedTile();
                break; 
            case TileType.BOOM:
                //マネージャーにゲームオーバー処理をしてもらう
                mRedBG.SetActive(true);
                mManager.GameOver(); 
                break; 
            case TileType.COUNT:
                mManager.CountDiggedTile();
                break; 
        } 
    }  

    //周りの地雷数を設定/表示
    public void SetCount(int count)
    {
        mTileType = TileType.COUNT;

        //カウントを設定して表示
        mCount.gameObject.SetActive(true);
        mCount.text = count.ToString();

        //数字によって、文字の色を変える
        mCount.color = mCountCols[count - 1];
    }

    public void SetBoom()
    {
        mTileType = TileType.BOOM;
        mBoom.SetActive(true);
    }

    //マークを付ける
    public void SetMark()
    {
        if (mIsDigged)
            return;

        switch (mMarkState)
        {
            case MarkState.NO_MARK:
                mFlag.SetActive(true);
                break;
            case MarkState.FLAG:
                mFlag.SetActive(false);
                mQuestion.SetActive(true);
                break;
            case MarkState.QUESTION:
                mQuestion.SetActive(false);
                break;
            default:
                break;
        }

        mMarkState++;
        int markStateLength = System.Enum.GetNames(typeof(MarkState)).Length;
        if ((int)mMarkState == markStateLength)
            mMarkState -= markStateLength;
    }

    public void GameOverCheck()
    {
        if (mMarkState == MarkState.FLAG && mTileType != TileType.BOOM)
            mRedCross.SetActive(true);
        else if (mMarkState != MarkState.FLAG && mTileType == TileType.BOOM)
            mCover.SetActive(false);
    }
}
```

###③タイル管理

```C#
using System.Collections.Generic;
using UnityEngine;

public class Manager : MonoBehaviour
{  
    [SerializeField] Tile mTilePrefab;  
    [SerializeField] Vector2Int mFieldSize = new Vector2Int(10, 10); 
    [SerializeField] int mTotalBoomCount = 20; 
    [SerializeField] GameObject mTilesRoot; 
    [SerializeField] GameObject mGameOverImage; 
    [SerializeField] GameObject mGameClearImage; 
     
    Tile[] mTiles; 
    Tile[] mBoomTiles; 
    int mDiggedTileCount;

    private void Start()
    {
        GenerateTiles(); 
        SetBooms(); 
        SetCounts(); 
    }

    //タイルを設置
    void GenerateTiles()
    {
        Vector2 canvasCenter = new Vector2(Screen.width / 2f, Screen.height / 2f);

        float x = (mFieldSize.x - 1f) / 2f;
        float y = (mFieldSize.y - 1f) / 2f;
        Vector2 leftUnderTilePos = canvasCenter - new Vector2(x, y) * 100f;

        mTiles = new Tile[mFieldSize.x * mFieldSize.y];

        for (int i = 0; i < mTiles.Length; i++)
        { 
            Vector2 thisTilePos = leftUnderTilePos + new Vector2(i % mFieldSize.x, i / mFieldSize.x) * 100f; 
             
            Tile tile = Instantiate(mTilePrefab, mTilesRoot.transform); 
            tile.GetComponent<RectTransform>().position = thisTilePos; 
             
            tile.Initialize(this, i); 
            mTiles[i] = tile; 
        }
    }

    //地雷を設置
    void SetBooms()
    {
        List<Tile> safeTiles = new List<Tile>(mTiles.Length);
        safeTiles.AddRange(mTiles);

        mBoomTiles = new Tile[mTotalBoomCount];

        for (int i = 0; i < mTotalBoomCount; i++)
        {
            int index = Random.Range(0, safeTiles.Count);
            Tile boomTile = safeTiles[index];

            mBoomTiles[i] = boomTile;
            safeTiles.RemoveAt(index);

            boomTile.SetBoom();
        }
    }

    void SetCounts()
    {
        int[] boomCountEach = new int[mTiles.Length];

        foreach (var tile in mBoomTiles)
        {
            int[] aroundTileIndices = GetAroundIndices(tile.Index);
            foreach (var aroundIndex in aroundTileIndices)
                boomCountEach[aroundIndex] = boomCountEach[aroundIndex] + 1;
        }

        for (int i = 0; i < boomCountEach.Length; i++)
        {
            int boomCount = boomCountEach[i];
            if (boomCount != 0 && mTiles[i].TileType != TileType.BOOM)
                mTiles[i].SetCount(boomCount);
        }
    }

    //隣のタイルを開く
    public void DigAround(int index)
    {
        foreach (var aroundTileIndex in GetAroundIndices(index))
            mTiles[aroundTileIndex].OnDigged();
    }

    int[] GetAroundIndices(int index)
    {
        List<int> result = new List<int>(8);

        int index0 = index - mFieldSize.x - 1;
        if (index0 >= 0 && index0 % mFieldSize.x != mFieldSize.x - 1)
            result.Add(index0);

        int index1 = index - mFieldSize.x;
        if (index1 >= 0)
            result.Add(index1);

        int index2 = index - mFieldSize.x + 1;
        if (index2 >= 0 && index2 % mFieldSize.x != 0)
            result.Add(index2);

        int index3 = index - 1;
        if (index3 >= 0 && index3 % mFieldSize.x != mFieldSize.x - 1)
            result.Add(index3);

        int index4 = index + 1;
        if (index4 % mFieldSize.x != 0)
            result.Add(index4);

        int index5 = index + mFieldSize.x - 1;
        if (index5 < mTiles.Length && index5 % mFieldSize.x != mFieldSize.x - 1)
            result.Add(index5);

        int index6 = index + mFieldSize.x;
        if (index6 < mTiles.Length)
            result.Add(index6);

        int index7 = index + mFieldSize.x + 1;
        if (index7 < mTiles.Length && index7 % mFieldSize.x != 0)
            result.Add(index7);

        return result.ToArray();
    }

    //ゲームオーバー
    public void GameOver()
    {
        mGameOverImage.SetActive(true);

        foreach (var tile in mTiles)
        {
            tile.GameOverCheck();
        }
    } 
     
    public void CountDiggedTile() 
    { 
        mDiggedTileCount++;
        if (mDiggedTileCount == mFieldSize.x * mFieldSize.y - mTotalBoomCount)
            GameClear();
    } 

    //ゲームクリア
    void GameClear()
    {
        mGameClearImage.SetActive(true);
    }
}