【Untiy】扫雷游戏

工程项目:https://github.com/yangjiqiu/MineGame

1、选择难度 2、根据难度调整分辨率 3、游戏规则算法

效果图 

代码块

using System.Collections;
using System.Collections.Generic;
using UnityEngine;
using UnityEngine.UI;
using Epitome.Utility;
using UnityEngine.EventSystems;

public class WorldInit : MonoBehaviour
{
    public GameObject mMineField; //雷区:所有雷块父物体

    int[,] mMinefieldsData; //雷区数据 -2:墙 -1:地雷 0:周边无雷 1-8:周边雷数量
    int[,] mMinefieldsStart; //雷区状态  -1:排除 0:无操作 1:标记

    //状态图标
    public Sprite[] mMineCount; // 0:周边无雷 1-8:周边雷数量
    public Sprite mSign; // 标记
    public Sprite mMine; // 雷
    public Sprite mChunk; // 原块

    int mMapMatrixX, mMapMatrixY; //地图矩阵长度
    int mMapMineCount; //地图地雷数量
    int mSurplusMineCount; // 剩余地雷数

    bool IfSignMine; // 是否标记地雷

    private void Awake()
    {
        IfSignMine = true;

        //初始化
        mMapMatrixX = 30;
        mMapMatrixY = 16;
        mMapMineCount = mSurplusMineCount = 99;

        MineFieldInit(Screen.width,Screen.height);
    }

    /// <summary>
    /// 雷区初始化 varInterval:块之间的间隔
    /// </summary>
    void MineFieldInit(float varWidth, float varHeight,int varInterval = 5)
    {
        int tempYPixel = (int)(varHeight / mMapMatrixY); //计算X轴所需最大块像素
        int tempXPixel = (int)(varWidth / mMapMatrixX); //计算Y轴所需最大块像素

        int tempPixel = tempXPixel < tempYPixel ? tempXPixel : tempYPixel; //取最小像素块

        Transform tempMineLump = mMineField.transform.Find("MineChunk"); //获取块模板
        tempMineLump.GetComponent<RectTransform>().sizeDelta = new Vector2(tempPixel - varInterval, tempPixel - varInterval); //设置块大小像素

        TypeSetting(mMapMatrixX, mMapMatrixY, tempPixel, tempMineLump);
    }

    /// <summary>
    /// 排版
    /// </summary>
    void TypeSetting(int varX, int varY, int varPixel, Transform varMineLump)
    {
        for (int i = 0; i < varX; i++)
        {
            for (int j = 0; j < varY; j++)
            {
                // 克隆
                GameObject tempGame = Instantiate(varMineLump, mMineField.transform).gameObject;
                tempGame.name = i + "_" + j;
                // 给雷块添加点击事件 + 回调
                UIEventListener tempUIEventListener = tempGame.gameObject.AddComponent<UIEventListener>();
                tempUIEventListener.OnMouseClick += Ret;
                // 设置位置像素大小等
                RectTransform tempRect = tempGame.transform.GetComponent<RectTransform>();
                tempRect.anchoredPosition3D = new Vector3(i * varPixel, (j + 1) * varPixel, 0); //设置块像素
                tempRect.localScale = Vector3.one;

                tempGame = null;
            }
        }

        BuriedMine(mMapMatrixX, mMapMatrixY, mMapMineCount);
    }

    /// <summary>
    /// 填充数据
    /// </summary>
    void BuriedMine(int varX, int varY, int varMineCount)
    {
        mMinefieldsData = new int[varX, varY];
        mMinefieldsStart = new int[varX, varY];

        int tempMineCount = 0;
        int tempX_Index;
        int tempY_Index;
        // 填充地雷
        do
        {
            // 随机某区域
            tempX_Index = Random.Range(0, varX);
            tempY_Index = Random.Range(0, varY);

            if (mMinefieldsData[tempX_Index, tempY_Index] != -1) //当区块没有地雷时可填充地雷
            {
                mMinefieldsData[tempX_Index, tempY_Index] = -1;

                if (IfSignMine)
                {
                    // 标记地雷 测试使用
                    Image tempImage = GetChunkImage(tempX_Index, tempY_Index);
                    if (tempImage != null) tempImage.color = Color.red;
                    tempImage = null;
                }

                for (int i = (tempX_Index == 0 ? tempX_Index : tempX_Index - 1); i <= (tempX_Index == mMapMatrixX ? tempX_Index : tempX_Index + 1); i++)
                {
                    for (int j = (tempY_Index == 0 ? tempY_Index : tempY_Index - 1); j <= (tempY_Index == mMapMatrixY ? tempY_Index : tempY_Index + 1); j++)
                    {
                        if (i == mMapMatrixX || j == mMapMatrixY) continue;
                        if (mMinefieldsData[i, j] != -1)
                        {
                            mMinefieldsData[i, j] += 1;
                        }
                    }
                }
                tempMineCount += 1;
            }
        } while (tempMineCount < varMineCount);

        tempMineCount = tempX_Index = tempY_Index = 0;
    }

    void Ret(GameObject varGO, PointerEventData varData)
    {
        if (!varGO.tag.Contains("GameBlock")) //不是雷块时
            return;

        string[] tempStr = varGO.name.Split('_');

        int tempX = int.Parse(tempStr[0]);
        int tempY = int.Parse(tempStr[1]);

        if (varData.pointerId == -1) // 鼠标左键
        {
            if (mMinefieldsStart[tempX, tempY] != 1 && mMinefieldsData[tempX, tempY] == -1)
            {
                Debug.Log("游戏结束");
                //显示所有
                for (int i = 0; i < mMinefieldsData.GetLength(0); i++)
                {
                    for (int j = 0; j < mMinefieldsData.GetLength(1); j++)
                        SweepShow(i, j, true);
                }
            }
            else 
            {
                SweepShow(tempX, tempY, true);
            }
        }
        else if (varData.pointerId == -2)// 鼠标左键
        {
            MarkIcon(tempX, tempY);

            if (mSurplusMineCount == 0)  //剩余雷 == 0 时
            {
                if (DetectionMine())
                    Debug.Log("游戏成功");
            }
        }
    }

    /// <summary>
    /// 检测地雷是否全部完成
    /// </summary>
    bool DetectionMine()
    {
        for (int i = 0; i < mMinefieldsStart.GetLength(0); i++)
        {
            for (int j = 0; j < mMinefieldsStart.GetLength(1); j++)
            {
                // 当(i, j)没有排除时 显示
                if (mMinefieldsStart[i, j] == 1)
                {
                    if (mMinefieldsData[i, j] != -1) //标记地方不是雷
                        return false;
                }
            }
        }
        return true;
    }

    /// <summary>
    /// 扫雷显示
    /// </summary>
    void SweepShow(int varX,int varY,bool varBool = false)
    {
        int tempSafetyZone = mMinefieldsStart[varX, varY]; //雷块状态
        int tempMinefieldsMatrix = mMinefieldsData[varX, varY]; //雷块数据

        // 没有排除
        if (tempSafetyZone != -1 && (tempSafetyZone != 1 || !varBool))
        {
            Image tempImage = GetChunkImage(varX, varY);
            if (tempImage == null) return;

            if (tempMinefieldsMatrix == -1)
            {
                tempImage.sprite = mMine;
                mMinefieldsStart[varX, varY] = -1;
            }
            else if (tempMinefieldsMatrix >= 0 && tempMinefieldsMatrix < 9)
            {
                tempImage.sprite = mMineCount[tempMinefieldsMatrix];
                mMinefieldsStart[varX, varY] = -1;

                Demining(varX, varY);

                tempImage.raycastTarget = false; //显示后 不可触发检测
            }
        }
    }

    /// <summary>
    /// 排雷:只有在周边没雷时继续向外围进行排雷
    /// </summary>
    void Demining(int varX, int varY)
    {
        if (mMinefieldsData[varX, varY] != 0) return; 

        // 获取(varX,varY)周边八个点 && 限制数组超出范围
        for (int i = (varX == 0 ? varX : varX - 1); i <= (varX == mMapMatrixX ? varX : varX + 1); i++)
        {
            for (int j = (varY == 0 ? varY : varY - 1); j <= (varY == mMapMatrixY ? varY : varY + 1); j++)
            {
                if (i == mMapMatrixX || j == mMapMatrixY) continue;
                // 当(i, j)没有排除时 显示
                if (mMinefieldsStart[i, j] != -1)
                    SweepShow(i, j);
            }
        }
    }

    /// <summary>
    /// 标记图标
    /// </summary>
    void MarkIcon(int varX, int varY)
    {
        // 当(varX, varY)没有排除显示时
        if (mMinefieldsStart[varX, varY] != -1)
        {
            Image tempImage = GetChunkImage(varX, varY);
            if (tempImage == null) return;

            // 当(varX, varY)无操作 && 剩余雷数>零
            if (mMinefieldsStart[varX, varY] == 0 && mSurplusMineCount > 0)
            {
                tempImage.sprite = mSign;//替换标记图标
                mMinefieldsStart[varX, varY] = 1;//添加标记
                mSurplusMineCount -= 1;
            }
            // 当(varX, varY)有标记 && 剩余雷数<mMapMineCount(初始雷数)
            else if (mMinefieldsStart[varX, varY] == 1 && mSurplusMineCount < mMapMineCount)
            {
                tempImage.sprite = mChunk;//替换块原图
                mMinefieldsStart[varX, varY] = 0;//设置无操作
                mSurplusMineCount += 1;
            }
        }
    }

    /// <summary>
    /// 获取块图标
    /// </summary>
    /// <returns></returns>
    Image GetChunkImage(int varX, int varY)
    {
        Transform tempTrans = mMineField.transform.Find(string.Format("{0}{1}{2}", varX, "_", varY));
        if (tempTrans != null)
        {
            Image tempImage = tempTrans.GetComponent<Image>();
            return tempImage;
        }
        return null;
    }
}

 

  • 0
    点赞
  • 3
    收藏
    觉得还不错? 一键收藏
  • 打赏
    打赏
  • 0
    评论

“相关推荐”对你有帮助么?

  • 非常没帮助
  • 没帮助
  • 一般
  • 有帮助
  • 非常有帮助
提交
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包

打赏作者

JIQIU.YANG

你的鼓励将是我创作的最大动力

¥1 ¥2 ¥4 ¥6 ¥10 ¥20
扫码支付:¥1
获取中
扫码支付

您的余额不足,请更换扫码支付或充值

打赏作者

实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

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

余额充值