扫雷 unity版

以前看没想过扫雷的实现,昨天看到一个帖子发的扫雷,写的很恶心,所以自己就尝试了一下,直接新建一个cs脚本复制以下代码就可以了。

先看看效果

代码:

 

using System.Collections.Generic;
using UnityEngine;

public class MineSweeper : MonoBehaviour
{
    public static MineSweeper instance;
    private GameObject prefab;
    private List<MineCube> objects; 

    public int Row = 5;
    public int Col = 5;
    public int Mine = 10;
    private int totalCount;

    void Start()
    {
        instance = this;
        CreatePrefab();
        objects = new List<MineCube>();
    }

    void Create()
    {
        //mine总数小于格子数
        if(Mine > Row*Col) {Debug.LogError("Mine's count canot more than grid's count!");return;}
        totalCount = Row*Col;
        //清除所有旧物体
        int count = objects.Count;
        for (int i = count-1; i >=0 ; i--)
        {
            objects[i].DoDestroy();
        }
        objects.Clear();
        //创建物体
        for (int i = 0; i < Row; i++)
        {
            for (int j = 0; j < Col; j++)
            {
                CreateObject(i, j);
            }
        }
        //创建mine
        CreateMines();
        //更新数据
        UpdateMines();
    }

    void OnGUI()
    {
        GUI.Label(new Rect(Screen.width * 0.5f - 100, 0, 200, 30),  "TotalBlock: " + Row * Col + " Mine: " + Mine);
        GUI.Label(new Rect(0,0,50,30),"Row" );
        string row = GUI.TextField(new Rect(50, 0, 50, 30), Row.ToString());
        if (!int.TryParse(row, out Row))
            Row = 3;
        GUI.Label(new Rect(0, 35, 50, 30), "Col");
        string col = GUI.TextField(new Rect(50, 35, 50, 30), Col.ToString());
        if (!int.TryParse(col, out Col))
            Col = 3;
        GUI.Label(new Rect(0, 70, 50, 30), "Mine");
        string mine = GUI.TextField(new Rect(50, 70, 50, 30), Mine.ToString());
        if (!int.TryParse(mine, out Mine))
            Mine = 3;
        if(GUI.Button(new Rect(10, 110, 50, 30), "Create"))
            Create();

    }

    /// <summary>
    /// 创建预制体,附加TextMesh
    /// </summary>
    void CreatePrefab()
    {
        prefab = GameObject.CreatePrimitive(PrimitiveType.Cube);
        GameObject text = new GameObject("Text");
        text.AddComponent<MeshRenderer>();
        TextMesh txtMesh = text.AddComponent<TextMesh>();
        text.transform.parent = prefab.transform;
        text.transform.localPosition = Vector3.zero;

        txtMesh.color = Color.black;
        txtMesh.anchor = TextAnchor.MiddleCenter;
        txtMesh.alignment = TextAlignment.Center;
        txtMesh.fontSize = 10;

        prefab.SetActive(false);
        prefab.AddComponent<MineCube>();
        prefab.transform.localScale = Vector3.one * 0.9f;
    }

    void CreateObject(int x, int y)
    {
        GameObject obj = Instantiate(prefab);
        obj.SetActive(true);
        MineCube mineCube = obj.GetComponent<MineCube>();
        mineCube.Set(x, y, objects.Count);
        objects.Add(mineCube);
    }

    void CreateMines()
    {
        //Mine个不重复随机数
        List<int> randoms = new List<int>();
        for (int i = 0; i < Mine; i++)
        {
            int r = Random.Range(0, objects.Count-1);
            while (randoms.Contains(r))
            {
                r = (r + 1)%objects.Count;
            }
            randoms.Add(r);
        }
        //设置mine
        for (int i = 0; i < Mine; i++)
        {
            objects[randoms[i]].SetState(1);
        }
    }

    /// <summary>
    /// (该部分可优化)
    /// 如果是mine,跳过
    /// 否则,判断周围是否有mine
    ///         是:直接统计九宫格内mine 个数
    ///         否:把周围空格标记
    /// </summary>
    void UpdateMines()
    {
        for (int i = 0; i < Row; i++)
        {
            for (int j = 0; j < Col; j++)
            {
                MineCube mine = objects[i*Col + j];
                if(mine.isMine()) continue;
                for (int k = i-1; k <= i+1; k++)
                {
                    for (int l = j-1; l <= j+1; l++)
                    {
                        if(k < 0 || k >= Row || l < 0 || l >= Col) continue;//划定九宫格界限
                        if(k == i && l == j) continue;//排除自身
                        if (objects[k*Col + l].isMine())
                            mine.AddAroundMine();
                        else
                            mine.AddAroundBlock(objects[k*Col + l]);
                    }
                }
            }
        }
    }

    internal void GameOver()
    {
        Debug.Log("GameOver!");
    }

    /// <summary>
    /// 点击判断,根据剩下的格子数判断输赢
    /// </summary>
    /// <param name="ismine"></param>
    internal void SendCount(bool ismine)
    {
        if (!ismine)
        {
            totalCount--;
            if (totalCount == Mine)
            {
                Debug.Log("Congratulations! You Win");
            }
        }
    }
}


public class MineCube : MonoBehaviour
{
    private TextMesh textMesh;
    private int x;
    private int y;
    private int num;
    private int state;//0空白, 1mine
    private Material mat;

    public int aroundMine;
    private List<MineCube> aroundBlock;

    public bool selected;//是否选中

    void Awake()
    {
        textMesh = GetComponentInChildren<TextMesh>();
        mat = GetComponent<Renderer>().material;
        state = 0;
        aroundMine = 0;
        aroundBlock = new List<MineCube>();
        selected = false;
    }

    public void OnMouseDown()
    {
        if(selected) return;
        selected = true;//标记选中
        MineSweeper.instance.SendCount(isMine());
        Show();
        if (isMine())//该块是mine则游戏结束
        {
            MineSweeper.instance.GameOver();
            return;
        }
    }

    /// <summary>
    /// 是mine标记X, 不是则判断周围有显示数字,没有则把相邻的所有没有的都显示出来
    /// </summary>
    private void Show()
    {
        if (isMine())
        {
            textMesh.text = "X";
            mat.SetColor("_Color", Color.red);
        }
        else
        {
            if (aroundMine != 0)
                textMesh.text = aroundMine.ToString();
            else
            {
                ShowAroundBlock();
            }
            mat.SetColor("_Color", Color.gray);
        }

    }

    /// <summary>
    /// 显示周围空白格
    /// </summary>
    public void ShowAroundBlock()
    {
        if (!selected)
        {
            this.selected = true;
            MineSweeper.instance.SendCount(false);
        }
        mat.SetColor("_Color", Color.gray);
        foreach (var _block in aroundBlock)//遍历周围的空白方格
        {
            if (!_block.selected && !_block.isMine() && _block.aroundMine == 0)//该方格未被选中且同样和当前方格一样是一个空白的,周围没有mine的
            {//点击到空白的时要一起显示空白
                _block.ShowAroundBlock();
            }
        }
    }


    /// <summary>
    /// 鼠标进入时设置颜色、因为创建的预制体有碰撞器,故OnMouse***函数有效
    /// </summary>
    public void OnMouseEnter()
    {
        mat.SetColor("_Color", Color.green);
    }

    /// <summary>
    /// 鼠标退出时恢复原状
    /// </summary>
    public void OnMouseExit()
    {
        if (selected)
        {
            if(!isMine())
                mat.SetColor("_Color", Color.gray);
            else
                mat.SetColor("_Color", Color.red);
        }
        else
            mat.SetColor("_Color", Color.white);
    }
    


    internal void Set(int x, int y, int num)
    {
        this.x = x;
        this.y = y;
        this.num = num;
        transform.position = new Vector3(x, y, 0);
    }

    internal void DoDestroy()
    {
        Destroy(gameObject);
    }

    /// <summary>
    /// state 的 0:空白没有mine
    ///          1:是mine
    /// </summary>
    /// <param name="p"></param>
    internal void SetState(int p)
    {
        state = p;
    }

    /// <summary>
    /// 判断是否是mine
    /// </summary>
    /// <returns></returns>
    internal bool isMine()
    {
        return state == 1;
    }

    /// <summary>
    /// 在UpdateMines中用来更新该block周围的Mine数量
    /// </summary>
    internal void AddAroundMine()
    {
        aroundMine++;
    }

    /// <summary>
    /// 当前格为空block时标记周围八个格中没有mine的格
    /// 用来显示连续显示
    /// </summary>
    /// <param name="block"></param>
    internal void AddAroundBlock(MineCube block)
    {
        aroundBlock.Add(block);
    }
}

 

转载于:https://www.cnblogs.com/garsonlab/p/9992147.html

评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值