当前位置: 首页 > news >正文

【Unity】MiniGame编辑器小游戏(三)马赛克【Mosaic】

更新日期:2025年6月17日。
项目源码:后续章节发布

索引

  • 马赛克【Mosaic】
    • 一、游戏最终效果
    • 二、玩法简介
    • 三、正式开始
      • 1.定义游戏窗口类
      • 2.规划游戏窗口、视口区域
      • 3.地图方块阵列
        • ①.定义方块结构体
        • ②.生成方块阵列
        • ③.计算九宫格黑色方块数量
        • ④.排除任意九宫格内不存在任何一个显示文字方块的情况
        • ⑤.设置马赛克题目
      • 4.绘制方块阵列
      • 5.标记方块
      • 6.检测游戏是否通关
      • 7.绘制游戏操作说明
      • 8.游戏技巧
        • ①.数字0所在九宫格全为白色
        • ②.数字9所在九宫格全为黑色
        • ③.靠边6所在九宫格全为黑色
        • ④.精准排除法
        • ⑤.模糊排除法
      • 9.暂停游戏、退出游戏

马赛克【Mosaic】

本篇的目标是开发一个马赛克【Mosaic】小游戏。

一、游戏最终效果

Unity编辑器小游戏:马赛克

二、玩法简介

马赛克是扫雷游戏的变种,是一款推理游戏,其玩法简单却富有挑战性。

游戏界面由方块阵列组成,玩家需要推理每个方块的正确颜色,并标记为该颜色(分为黑色白色),所以游戏通关后的界面看起来像马赛克一样,因而得名。

有些方块上会显示一个数字,代表了该方块所在的9宫格中黑色方块的数量(包含该方块自身),玩家需要通过这些信息来推理逐步找出所有黑色方块。

三、正式开始

1.定义游戏窗口类

首先,定义马赛克的游戏窗口类MiniGame_Mosaic,其继承至MiniGameWindow【小游戏窗口基类】

    /// <summary>/// 马赛克/// </summary>public class MiniGame_Mosaic : MiniGameWindow{}

2.规划游戏窗口、视口区域

通过覆写虚属性实现规划游戏视口区域大小:

        /// <summary>/// 游戏名称/// </summary>public override string Name => "马赛克 [Mosaic]";/// <summary>/// 游戏窗体大小/// </summary>public override Vector2 WindowSize => new Vector2(700, 530);/// <summary>/// 游戏视口区域/// </summary>public override Rect ViewportRect => new Rect(5, 25, 500, 500);

注意:游戏窗体大小必须 > 游戏视口区域。

然后通过代码打开此游戏窗口:

        [MenuItem("MiniGame/马赛克 [Mosaic]", priority = 3)]private static void Open_MiniGame_Mosaic(){MiniGameWindow.OpenWindow<MiniGame_Mosaic>();}

便可以看到游戏的窗口、视口区域如下(左侧深色凹陷区域为视口区域):

在这里插入图片描述

3.地图方块阵列

马赛克游戏的背景也是由一系列方块组成的,所以我们先来绘制如下这样的地图方块阵列:

在这里插入图片描述

①.定义方块结构体

首先,定义方块结构体Block,其代表方块阵列中的一个方块:

        /// <summary>/// 方块/// </summary>public struct Block{/// <summary>/// 方块位置/// </summary>public Rect Position;/// <summary>/// 是否为黑色/// </summary>public bool IsBlack;/// <summary>/// 是否为白色/// </summary>public bool IsWhite;/// <summary>/// 周围九宫格内黑色方块数量/// </summary>public int BlackCount;/// <summary>/// 是否显示数量文字/// </summary>public bool IsShowCount;}
②.生成方块阵列

我们设计如下四种难度等级的关卡:

名称地图大小
初级5*5
中级10*10
高级15*15
大师级20*20
        private readonly string[] LEVELS = new string[] { "初级(5*5)", "中级(10*10)", "高级(15*15)", "大师级(20*20)" };

所以游戏视口的宽度、高度是根据大师级难度(方块尺寸25 * 方块宽高20 = 500)的大小来设置的:

        private const int BLOCKSIZE = 25;

根据选择的不同难度,来生成对应的地图方块阵列:

        private Block[,] _mosaic;/// <summary>/// 开始游戏/// </summary>private void StartGame(){if (_level == 0){WIDTH = 5;HEIGHT = 5;}else if (_level == 1){WIDTH = 10;HEIGHT = 10;}else if (_level == 2){WIDTH = 15;HEIGHT = 15;}else if (_level == 3){WIDTH = 20;HEIGHT = 20;}GenerateMosaic();}/// <summary>/// 生成马赛克矩阵/// </summary>private void GenerateMosaic(){//生成马赛克矩阵_mosaic = new Block[WIDTH, HEIGHT];for (int row = 0; row < WIDTH; row++){for (int col = 0; col < HEIGHT; col++){_mosaic[row, col].Position = new Rect(row * BLOCKSIZE, col * BLOCKSIZE, BLOCKSIZE, BLOCKSIZE);_mosaic[row, col].IsBlack = Utility.IsTriggerProbability(60);_mosaic[row, col].IsWhite = false;_mosaic[row, col].IsShowCount = Utility.IsTriggerProbability((_level == 0 || _level == 1) ? 70 : 60);}}}

在生成方块阵列的方法中,每一个方块有60%概率为黑色:

_mosaic[row, col].IsBlack = Utility.IsTriggerProbability(60);

初级中级时,每一个方块有70%概率显示九宫格内黑色方块数量,高级大师级60%,相应提升了难度:

_mosaic[row, col].IsShowCount = Utility.IsTriggerProbability((_level == 0 || _level == 1) ? 70 : 60);
③.计算九宫格黑色方块数量

在生成方块阵列完成后,下一步就需要计算每一个方块所属九宫格中的黑色方块数量:

        /// <summary>/// 生成马赛克矩阵/// </summary>private void GenerateMosaic(){//......//计算所有方块所在九宫格的黑色方块数量for (int row = 0; row < WIDTH; row++){for (int col = 0; col < HEIGHT; col++){_mosaic[row, col].BlackCount = CalculateBlackCount(row, col);}}}/// <summary>/// 计算方块所在九宫格的黑色方块数量/// </summary>private int CalculateBlackCount(int x, int y){int count = 0;for (int i = -1; i <= 1; i++){for (int j = -1; j <= 1; j++){int newX = x + i;int newY = y + j;if (newX >= 0 && newX < WIDTH && newY >= 0 && newY < HEIGHT && _mosaic[newX, newY].IsBlack){count++;}}}return count;}
④.排除任意九宫格内不存在任何一个显示文字方块的情况

我们必须确保,任意九宫格中,至少有一个方块会显示黑色方块数量,否则会显著提升解题难度,甚至不可解:

        /// <summary>/// 生成马赛克矩阵/// </summary>private void GenerateMosaic(){//......//排除单一九宫格内不存在任何一个显示文字方块的情况for (int row = 0; row < WIDTH; row++){for (int col = 0; col < HEIGHT; col++){int count = CalculateShowCount(row, col);if (count <= 0){_mosaic[row, col].IsShowCount = true;}}}}/// <summary>/// 计算方块所在九宫格的显示文字的数量/// </summary>private int CalculateShowCount(int x, int y){int count = 0;for (int i = -1; i <= 1; i++){for (int j = -1; j <= 1; j++){int newX = x + i;int newY = y + j;if (newX >= 0 && newX < WIDTH && newY >= 0 && newY < HEIGHT && _mosaic[newX, newY].IsShowCount){count++;}}}return count;}
⑤.设置马赛克题目

马赛克游戏也可以看作是一道逻辑解密题,由于之前我们随机生成了一些黑色方块,现在部分方块上已经标注了其所在九宫格中黑色方块的数量,现在只需要将所有黑色方块去掉,使玩家通过逻辑推理来寻找黑色方块即可:

        /// <summary>/// 生成马赛克矩阵/// </summary>private void GenerateMosaic(){//......//设置马赛克题目for (int row = 0; row < WIDTH; row++){for (int col = 0; col < HEIGHT; col++){_mosaic[row, col].IsBlack = false;}}}

4.绘制方块阵列

然后在OnGameViewportGUI方法中绘制方块阵列:

		//未标记的方块风格private GUIStyle _noBlockGS;//已标记的方块风格private GUIStyle _blockGS;protected override void OnGameViewportGUI(){base.OnGameViewportGUI();DrawPanel();}/// <summary>/// 绘制画布/// </summary>private void DrawPanel(){for (int h = 0; h < HEIGHT; h++){for (int w = 0; w < WIDTH; w++){DrawBlock(w, h);}}}/// <summary>/// 绘制方块/// </summary>private void DrawBlock(int x, int y){string count = _mosaic[x, y].IsShowCount ? _mosaic[x, y].BlackCount.ToString() : "";if (_mosaic[x, y].IsBlack){GUI.backgroundColor = Color.black;GUI.Box(_mosaic[x, y].Position, count, _blockGS);GUI.backgroundColor = Color.white;}else if (_mosaic[x, y].IsWhite){GUI.Box(_mosaic[x, y].Position, count, _blockGS);}else{GUI.Box(_mosaic[x, y].Position, count, _noBlockGS);}}

此时就能绘制出游戏的地图方块阵列了,比如初级(5*5)的:

在这里插入图片描述

注意:这里有一个选择关卡难度的过程省略了,该过程很简单便不浪费篇幅赘述了,后续在源码中即可一目了然。

两种状态的方块绘制出来大致是这样的:

在这里插入图片描述

5.标记方块

OnGamePlayingEvent方法中完成标记方块的逻辑:

        protected override void OnGamePlayingEvent(Event e, Vector2 mousePosition){base.OnGamePlayingEvent(e, mousePosition);if (e.type == EventType.MouseDown){if (e.button == 0){for (int h = 0; h < HEIGHT; h++){for (int w = 0; w < WIDTH; w++){if (_mosaic[w, h].Position.Contains(mousePosition)){//鼠标左键标记为黑色(再次点击则取消标记黑色)_mosaic[w, h].IsWhite = false;_mosaic[w, h].IsBlack = !_mosaic[w, h].IsBlack;Repaint();return;}}}}else if (e.button == 1){for (int h = 0; h < HEIGHT; h++){for (int w = 0; w < WIDTH; w++){if (_mosaic[w, h].Position.Contains(mousePosition)){//鼠标右键标记为白色(再次点击则取消标记白色)_mosaic[w, h].IsBlack = false;_mosaic[w, h].IsWhite = !_mosaic[w, h].IsWhite;Repaint();return;}}}}}}

6.检测游戏是否通关

检测游戏是否通关的逻辑为:每一个显示了黑色方块数量的方块,其所在九宫格内必须真实标记相应数量的黑色方块,其余标记为白色。

跟扫雷不同的是:每个方块的黑、白属性并不固定,只要最终满足每个九宫格的黑色方块数量即可。

        /// <summary>/// 检测马赛克题目是否完成(游戏是否通关)/// </summary>private bool CheckMosaicQuestion(){for (int row = 0; row < WIDTH; row++){for (int col = 0; col < HEIGHT; col++){//如果此方块显示了黑色方块数量,则检测其所在九宫格中是否存在相应数量的方块if (_mosaic[row, col].IsShowCount){int count = CalculateBlackCount(row, col);//任意九宫格中黑色方块数量不对,则游戏未通关if (count != _mosaic[row, col].BlackCount){return false;}}}}return true;}

7.绘制游戏操作说明

最后,操作说明等其他UI统一绘制在OnOtherGUI方法中:

        protected override void OnOtherGUI(){base.OnOtherGUI();Rect rect = new Rect(ViewportRect.x + ViewportRect.width + 5, ViewportRect.y + ViewportRect.height - 25, 80, 20);GUI.backgroundColor = Color.green;//玩家可主动点击Done按钮,检测游戏是否通关if (GUI.Button(rect, "Done")){if (CheckMosaicQuestion()){IsGameSuccessed = true;}else{ShowNotification(new GUIContent("You are failed, please try again."));}}rect.x += 85;GUI.backgroundColor = Color.yellow;//也可重新开始(如果当前题目无解,随机生成会有无解的情况)if (GUI.Button(rect, "Restart")){OnRestart();}GUI.backgroundColor = Color.white;rect.Set(ViewportRect.x + ViewportRect.width + 5, ViewportRect.y + ViewportRect.height - 75, 80, 20);GUI.Button(rect, "Mouse Left");rect.x += 85;rect.width = 100;GUI.Label(rect, "Marked as black");rect.Set(ViewportRect.x + ViewportRect.width + 5, ViewportRect.y + ViewportRect.height - 50, 80, 20);GUI.Button(rect, "Mouse Right");rect.x += 85;rect.width = 100;GUI.Label(rect, "Marked as white");}

这里绘制出来的效果如下:

在这里插入图片描述

8.游戏技巧

介绍一些游戏技巧(并不是全部)。

①.数字0所在九宫格全为白色

数字0代表所在九宫格中一个黑色方块也没有:

在这里插入图片描述

②.数字9所在九宫格全为黑色

同理,数字9代表所在九宫格中全为黑色方块:

在这里插入图片描述

③.靠边6所在九宫格全为黑色

靠边数字6代表所在九宫格中有6个黑色方块,但其九宫格只有6个方块,所以全为黑色:

在这里插入图片描述

④.精准排除法

如下图方块数字4,已知其下方2个方块为白色,排除后其九宫格只剩4个方块,所以4个全为黑色:

在这里插入图片描述

⑤.模糊排除法

如下图方块数字5,已知其下方2个方块为黑色,则上方4个方块中只能有3个黑色方块。

转向数字8,表明其所在九宫格中只有1个白色方块,则其上方左侧方块均为黑色(那1个白色方块在与数字5的交界区域中)。

在这里插入图片描述

至此,一个简单的马赛克小游戏就完成了,简单但却耐玩,试玩效果如下:马赛克【Mosaic】。

9.暂停游戏、退出游戏

同俄罗斯方块。

相关文章:

  • EPOLL相关接口和原理
  • CppCon 2016 学习:BUILDING A MODERN C++ FORGE FOR COMPUTE AND GRAPHICS
  • 如何将数据从安卓设备传输到 iPhone | 综合指南
  • 【QT】QT项目修改QT设计师界面类类名和文件名的方法
  • 408第二季 - 组成原理 - 数据类型转换
  • 在linux上用nginx配置ssl应该怎么操作?下面是示例
  • Python实现企业微信Token自动获取到SQLite存储
  • 微服务拆分 SpringCloud
  • 渲染学进阶——机械动力的渲染(3)
  • 对微服务的了解
  • 准确识别检索头,提高大模型长上下文能力
  • MyBatis与JPA有哪些不同?
  • 【MATLAB去噪算法】基于VMD联合小波阈值去噪算法(第六期)
  • CNN卷积神经网络实战(1)
  • 执行 PGPT_PROFILES=ollama make run下面报错,
  • 记录:安装VMware、Ubuntu、ROS2
  • Android实例项目【智能家居系统】实现数据库登录注册+动画效果+网页跳转+短信发送!!!
  • 65、【OS】【Nuttx】任务休眠与唤醒:nxsig_clockwait
  • BeikeShop - 一个开源、用户友好的跨境电子商务平台
  • [学习] 深入解析Z变换:从数学基础到工程应用
  • 小程序是什么东西/seo教程排名第一
  • 设计之都/昆明网站seo公司
  • 网站怎样设计网址大全/叶涛网站推广优化
  • 云相册网站怎么做的/网店代运营骗局
  • 南阳网站关键词/网络营销发展现状与趋势
  • as3 xml 网站模板 下载/网络营销推广方法和手段