【游戏开发答疑】马里奥派对选面积大作战玩法的功能实现(Unity | 算法 | 四邻域 | 连通块 | 面积比例分割)

2023-05-16

本文运行效果如下
请添加图片描述

文章目录

      • 一、前言
      • 二、实现方案
        • 1、构造二维数组
        • 2、顺序填充颜色
        • 3、交换格子颜色
        • 4、计算连通块个数(四邻域连通)
        • 5、运行起来
      • 三、工程源码
      • 四、完毕

一、前言

嗨,大家好,我是新发。
有同学私信问了我一个问题,如下
在这里插入图片描述
游戏视频如下

【超级马力欧派对】(四十六)选面积大作战

我以第一回合为例,也就是把5*9的方格分成9:11:12:13的面积,并且确保面积是四邻域连通的,什么是四邻域呢?一个格子的上下左右紧邻的格子就是它的四邻域。

好了,下面讲一下实现方案。

二、实现方案

1、构造二维数组

为了演示,我先做了一个简单的UI界面,如下,下面是一个5*9的方格阵列,
在这里插入图片描述
如果对应成代码,它就是一个二维数组,像这样子

/// <summary>
/// 行数
/// </summary>
private const int ROW_CNT = 5;
/// <summary>
/// 列数
/// </summary>
private const int COL_CNT = 9;

/// <summary>
/// 格子二维数组
/// </summary>
public Image[,] grid = new Image[ROW_CNT, COL_CNT];

2、顺序填充颜色

我们定义四种颜色,
在这里插入图片描述
把格子按9:11:12:13的比例顺序填充不同的颜色,像这样子
在这里插入图片描述
对应成代码就是这样子:

// 划分成4种颜色,9个color1, 11个color2, 12个color3, 13个color4
for (int i = 0; i < ROW_CNT; ++i)
  {
      for (int j = 0; j < COL_CNT; ++j)
      {
          var index = i * COL_CNT + j;
          if (index < 9)
          {
              grid[i, j].color = color1;
          }
          else if (index < 9 + 11)
          {
              grid[i, j].color = color2;
          }
          else if (index < 9 + 11 + 12)
          {
              grid[i, j].color = color3;
          }
          else
          {
              grid[i, j].color = color4;
          }
      }
  }

3、交换格子颜色

对某两个格子进行交换,写成代码是这样子,

int i1 = Random.Range(0, ROW_CNT);
int j1 = Random.Range(0, COL_CNT);

int i2 = Random.Range(0, ROW_CNT);
int j2 = Random.Range(0, COL_CNT);

var tmpColor = grid[i1, j1].color;
grid[i1, j1].color = grid[i2, j2].color;
grid[i2, j2].color = tmpColor;

交换后有两种结果:
情况1: 没有破坏连通性,依然是4个大的连通块:
在这里插入图片描述
情况2: 破坏了原有的连通性,像这样子,出现了7个连通块:
在这里插入图片描述

如果破坏了原来的连通性,这次交换就要作废。

那,我们如何检测有没有破坏原来的连通性呢?这个问题等效于:我们如何检查连通块的个数呢?只要确保连通块的个数是4,就说明没有破坏原来的连通性。

4、计算连通块个数(四邻域连通)

这里我用的是深度优先遍历,通过递归来实现。

首先我们定义格子的状态值:01,如果被遍历过,则标记为1;我们可以定义一个二维数组来存储格子状态:

/// <summary>
/// 格子状态,遍历过的标记为为1,否则为0
/// </summary>
int[,] ergodic = new int[ROW_CNT, COL_CNT];

为了存储四邻域连通的个数,我们再定义一个变量

/// <summary>
/// 统计连通块个数
/// </summary>
int connectGroupCnt = 0;

然后从[0, 0]的位置开始,如果发现格子状态为0,则让connectGroupCnt自增1,把格子标记为1,然后遍历格子的上下左右邻域的格子,如果发现颜色与当前格子相同,则标记为1,否则不操作,以此类推,直到全部遍历完毕。
为了方便大家对这个过程有个更直观的感受,我特意做了个动态图,如下
请添加图片描述
对应成代码如下

/// <summary>
/// 检测连通性
/// </summary>
/// <returns></returns>
bool CheckContinuous()
{
    int i = 0;
    connectGroupCnt = 0;
    ergodic = new int[ROW_CNT, COL_CNT];

    while (i < ROW_CNT)
    {
        int j = 0;
        while (j < COL_CNT)
        {
            Dfs(i, j, grid);
            j++;
        }
        i++;
    }

    // 如果四连通块超过4个,则说明产生了不连续颜色块
    if (connectGroupCnt > 4)
        return false;

    return true;
}


/// <summary>
/// 深度优先,递归调用,计算连通块数量
/// </summary>
void Dfs(int x, int y, Image[,] grid)
{
    if (x < 0 || y < 0 || x == ROW_CNT || y == COL_CNT)
    {
        return;
    }
    if (ergodic[x, y] == 0)
    {
        ergodic[x, y] = 1;
        connectGroupCnt++;

    }
    // 右
    if (y < COL_CNT - 1 && grid[x, y].color == grid[x, y + 1].color && ergodic[x, y + 1] == 0)
    {
        ergodic[x, y + 1] = 1;
        Dfs(x, y + 1, grid);
    }
    // 左
    if (y > 0 && grid[x, y].color == grid[x, y - 1].color && ergodic[x, y - 1] == 0)
    {
        ergodic[x, y - 1] = 1;
        Dfs(x, y - 1, grid);
    }
    // 下
    if (x < ROW_CNT - 1 && grid[x, y].color == grid[x + 1, y].color && ergodic[x + 1, y] == 0)
    {
        ergodic[x + 1, y] = 1;
        Dfs(x + 1, y, grid);
    }
    // 上
    if (x > 0 && grid[x, y].color == grid[x - 1, y].color && ergodic[x - 1, y] == 0)
    {
        ergodic[x - 1, y] = 1;
        Dfs(x - 1, y, grid);
    }
}

5、运行起来

现在,我们弄个协程,让它快速执行变化,看下效果吧~
请添加图片描述

三、工程源码

本文工程源码我以上传到GitCode,感兴趣的同学可自行下载。
地址:https://gitcode.net/linxinfa/GridBlockGame

注:完整代码见Assets/Scripts/Main.cs脚本

在这里插入图片描述

四、完毕

本文我的的实现方案只是我抽空写的一个简单的算法,并没有考虑最优解,大家可以思考一下其他更好的解决办法。

好了,我是林新发,https://blog.csdn.net/linxinfa
一个在小公司默默奋斗的Unity开发者,希望可以帮助更多想学Unity的人,共勉~

本文内容由网友自发贡献,版权归原作者所有,本站不承担相应法律责任。如您发现有涉嫌抄袭侵权的内容,请联系:hwhale#tublm.com(使用前将#替换为@)

【游戏开发答疑】马里奥派对选面积大作战玩法的功能实现(Unity | 算法 | 四邻域 | 连通块 | 面积比例分割) 的相关文章

  • 1002 A+B for Polynomials (25分) 详解+易错点

    注意点 xff1a 系数为0 xff0c 则不输出 xff0c 例 xff1a 其中 1和1相加为0 xff0c 则在输出时避免这一项 xff0c 而且要注意结果的K值 xff0c 不要包括这一项 xff0c 思路 xff0c 利用结构体存
  • Linux远程桌面的选择

    Linux的远程桌面主要分两个部分 xff1a Linux客户机连Linux服务器和Windows客户机连Linux服务器 xff0c 还有现在用平板电脑连远程桌面 Linux客户机连Windows服务器比较简单没啥可说的 xff0c rd
  • Kali Linux mdk3WiFi洪水攻击 攻击路由器 生成虚假WiFi WiFi身份验证攻击可使连接WiFi的手机掉线重连抓包

    将无线网卡转换为监听模式 airmon ng start wlan0 查找附近无线网络 airodump ng wlan0mon Authentication DoS xff1a xff08 洪水攻击 xff0c 又叫做身份验证攻击 xff
  • 大一java程序设计的某次作业题解

    题目描述 xff1a 设计程序实现输入日期及机票张数 xff0c 计算出应付金额 假设北京至上海的机票全价为 1200 元 张 xff0c 以 2017 年为例进行程序编写 xff0c 所有的法定假日 xff0c 机票无折扣 xff1b 除
  • D. Make It Round(1759D)

    要求n k后缀0数量最多 xff08 k lt 61 m xff09 xff0c 且n k尽可能大 比赛时思路 xff08 错误 xff09 xff1a 10是由2和5组成 xff0c 故先统计n的因子包含2的个数num2 包含5的个数nu
  • Codeforces Round #841 (Div. 2)

    B Kill Demodogs 分析 显然要选择和两斜线的元素相加 所以答案可以表示为 xff1a 即 xff1a 根据公式 得答案为 但答案不能直接得这个 因为n的范围为1e9 xff0c 而ull的范围为1e20 xff0c 答案的第一
  • Educational Codeforces Round 141 Editorial C~D

    1783C Yet Another Tournament 分析 正解思路是贪心 开始自己也想的贪心 xff1a 首先显然打败的人数越多越好 xff0c 然后选择权值最小的人打败 这个思路前半部分没问题 xff0c 后半部分过不了样例的第二个
  • Codeforces Round #844 (Div. 1 + Div. 2, based on VK Cup 2022 - Elimination Round) D

    1781D Many Perfect Squares 分析 对于每组 xff0c 若和均为完全平方数 xff0c 则存在 xff1a 所以枚举所有 xff0c 对于每个 xff0c 枚举其所有 双因子对 xff0c 若两个因子之差为偶数 x
  • 匹配已有字符串

    生活小妙招 通过set和substr函数 xff0c 方便快捷地写出匹配已有字符串的代码 前置芝士 xff1a set使用详解 题目 xff1a G Perfect Word 代码实现 通过set 43 string的substr的使用快速
  • 在vue中使用rules的定义和校验规则

    表单内容里面定义属性 lt Form ref 61 34 rulesForm 34 model 61 34 rulesForm 34 label width 61 34 100 34 rules 61 34 rules 34 gt lt F
  • Codeforces Raif Round 1 (Div. 1 + Div. 2) D

    D Bouncing Boomerangs 分析 一个stack用于存只有一个的物品的行的物品位置 xff0c 一个queue用于存有两个物品的行的左边物品位置 xff08 其实这两个容器用stack还是queue无所谓 xff0c 只是这
  • 使用django服务的前置操作

    注意 xff1a 这是一个用于小组作业说明的内部文章 xff0c 如果你在寻找部署django服务的完整流程 xff0c 请退出此文章 python版本 xff1a 3 7 输入命令 xff0c 安装django工具 xff1a pip i
  • Codeforces Round #853 (Div. 2) C题

    CF1789C Serval and Toxel 39 s Arrays 学弟的思路 思路清晰 xff0c 代码简洁明了 xff0c 吊打目前80 以上题解 分析 记录每个数字在多少个数组中出现过 xff0c 即记录每个数字出现的次数 然后
  • E. Carrots for Rabbits(一种神奇的数列维护技巧)

    题目 E Carrots for Rabbits 分析 将每个物品都放到大根堆里 xff0c 但每个物品有两个信息 xff1a 长度len 当前被切了几段part 根据这个物品当前状态的贡献 作为在堆里位置的依据 贡献由cal函数算出 注意
  • Codeforces Round 857 (Div. 1 + Div. 2) 2A - 2D

    A Likes 分析 首先数据保证了一定合法 xff0c 那只需要统计有几个负数 最大的策略是先把所有正数用完 xff0c 然后把所有负数用完 xff0c 可知答案一定是1 2 3 4 5 4 3这种形式 xff1b 最小策略是加一个就直接
  • Struts2校验框架<validators>配置报错

    问题 xff1a 新建了Actionname validation xml文件写校验 xff0c 发现 lt validators gt 及其子标签爆红 解决 1 找到部署Struts2时在官网下载的一堆 jar包 如图 xff1a 解压圈
  • 树莓派操作系统

    树莓派操作系统 树莓派操作系统 介绍更新和升级树莓派操作系统 使用 APT使用 rpi 更新播放音频和视频 OMXPlayer 应用程序如何播放音频如何播放视频播放期间的选项在后台播放使用 USB 网络摄像头 基本用法自动化图像捕获延时拍摄
  • KVM虚拟机的多种启动方式

    KVM 全称是基于内核的虚拟机 xff08 Kernel based Virtual Machine xff09 xff0c 它是一个 Linux的一个内核模块 xff0c 该内核模块使得 Linux变成了一个Hypervisor xff1
  • ARM平台FS6818/s5p6818开发板实验6 —— 按键中断实验

    按键中断实验 xff1a 实验内容 xff1a 通过简单事例说明s5p6818处理器的GIC中断处理的应用 xff0c 设置key2按键连接的引脚为中断模式 xff0c 当识别按键被按下时进入相应的中断处理函数 实验目的 xff1a 熟悉开
  • QuadrotorFly-四旋翼无人机动力学仿真环境介绍

    QuadrotorFly四旋翼无人机动力学模型 主要目的是开发一个用于无人机动力学仿真的简单易用 功能相对齐全的仿真环境 xff08 也许是水论文环境 xff09 这个仿真是基于python编写的 xff0c GPL开源 git的地址在 x

随机推荐