lab03—unity制作简易数独

2023-10-12 02:20
文章标签 制作 unity 简易 数独 lab03

本文主要是介绍lab03—unity制作简易数独,希望对大家解决编程问题提供一定的参考价值,需要的开发者们随着小编来一起学习吧!

        身为数独发烧友的我在接触到了unity之后,产生的第一个念头就是用unity制作一个数独。但是,在跟着网上一大堆教程搭了半天还失败之后,我决定改用纯C#代码的形式搭建我的数独游戏。前置步骤为在unity中新建项目并打开,创建C# script并将其拖动至MainCamera中;接下来就是对C# script的正式编写。

                //游玩视频放在文末,其中涉及到放置数字、撤回、重新生成题目等活动

一,生成9*9棋盘

        为了在屏幕上显示9*9的数独表格,需要一个同样为9*9尺寸的二维数组,与OnGUI函数中循环读取-显示相配合。

        首先,我们需要在整个public class中定义好二维数组。格式如下:

private int[,] sudokuBoard = new int[9, 9];
int count;

        其次,同样在public class中,我们需要定义OnGUI函数,这个函数会在整个项目运行时的每帧执行一次,负责(数独表格的)实时显示。

        //在其中提到的函数都会在后续进行补充

        //num_str这个一维数组仅用于按钮上文本的显示,即数独每个小格子的内容

    void OnGUI(){GUI.Box(new Rect(50, 25, 750, 750), "");//整个棋盘if (GUI.Button(new Rect(60, 270, 100, 30), "Restart")) Init();//如果点了restrat按钮就会重新初始化if (!GameOver()){//在格子填满前,循环判断每个格子应该显示什么内容string[] num_str = {"0","1","2","3","4","5","6","7","8","9" };for (int i = 0; i < 9; i++) {for (int j = 0; j < 9; j++){if (sudokuBoard[i, j] == 0 && GUI.Button(new Rect(170+j*50+j/3*10,50+i*50+i/3*10,50,50), "")){PutChess(i, j);//点击空白区域时调用PutChess函数}else if(sudokuBoard[i, j] !=0)//遍历到了非空白区域,显示数字{//显示的内容GUI.Button(new Rect(170+j*50+j/3*10,50+i*50+i/3*10,50,50), num_str[sudokuBoard[i,j] ]);//如果在撤回状态下(number==0)被点击:if ((number == 0) && (last_i==i)&&(last_j==j)){sudokuBoard[i, j] = 0;if(count>0)count--;number = 1;}}}}for (int i = 0; i < 10; i++)//显示界面下方待填入的数字(0-9){if (GUI.Button(new Rect(155 + i * 50, 550, 50, 50), num_str[i])){FixNumber(i);}}}}

为了更好地让大家理解,我先放出最终的运行图:

在我的OnGUI函数中,前一个嵌套循环对应着:每一帧都遍历数独表格上所有格子,分别进行显示所有格子和修改空格两件事;后一个循环对应着:若点击下方按钮,则调用FixNumber函数,准备修改数独表格上某些格子的内容。下方十个按钮中,0代表撤回前一步。

二,函数 Init() 

        顾名思义,Init()这个函数的主要功能就是初始化整个数独表格。在这里我放出两版Init()函数,分别是初始化空数独 / 初始化含题目数独的Init()。

        没有任何数字的空数独表格Init():

for(int i=0;i<9;i++)
{for(int j=0;j<9;j++){sudokuBoard[i, j] = 0;}
}
count = 0;

        //理论上来说,初始化自带题目的Init()有更好的做法(每次都随机生成新题目),但我在编写时发现我的做法会导致unity运行卡死,暂时不知道怎么解决。因此,我先手动放入了一个数独的完整解,再将能够推理得到的格子挖空,最终得到一份数独题目:

void Init()//此处完成各个参数和数独题目的初始化{count = 0;int[,] copytable = new int[9, 9]{{1,2,3,4,5,6,7,8,9 },{8,6,9,7,3,1,5,4,2 },{7,4,5,9,2,8,6,1,3 },{5,9,8,1,7,2,3,6,4 },{6,3,4,8,9,5,1,2,7 },{2,7,1,6,4,3,9,5,8 },{9,5,7,2,6,4,8,3,1 },{4,8,6,3,1,7,2,9,5 },{3,1,2,5,8,9,4,7,6 }};//挖空,使得数独题目有唯一解,且最简。实际上就是用解数独策略反推哪些格子可以挖掉//如果能从行+列+宫三种约束条件中推导出一格的内容,则这一格可以挖掉//注:仍然可以有更多策略,如用4个同种数字排除一个数字等。int row;int column;int my_count = 0;for (int time = 600; time > 0; time--)//这么写是当时找卡死的原因,可以改成while循环{row = Random.Range(0, 9);column = Random.Range(0, 9);//随机生成行列的数字for (int g = 0; g < 9; g++)//恢复 geweishu,用于反推该格子能否挖掉{geweishu[g] = g + 1;}sum = 0;for (int p = 0; p < 9; p++){if ((copytable[column, p] > 0) && (p != row))//同行有数字,且不是本人{geweishu[copytable[column, p] - 1] = 0;//这个数字不可能被填入这个格子}if ((copytable[p, row] > 0) && (p != column))//同列有数字,不是本人{geweishu[copytable[p, row] - 1] = 0;}if (copytable[column / 3 * 3 + p % 3, row / 3 * 3 + p / 3] > 0)//同九宫格{if ((column / 3 * 3 + p%3 != column) || (row / 3 * 3 + p/3 != row)){geweishu[copytable[column /3*3 + p%3, row /3*3 + p/3] - 1] = 0;}}}//利用邻近格子完全筛除了所有不可能的数字,再看是否可能填别的数字)for (int q = 0; q < 9; q++){sum += geweishu[q];}if (copytable[column, row] == sum)//本行中只能填原来这个数字,不能填别的数字{//这个格子能推理出,直接擦掉copytable[column, row] = 0;my_count++;}}for (int s = 0; s < 9; s++){for (int d = 0; d < 9; d++){sudokuBoard[s, d] = copytable[s, d];//将副本覆盖到棋盘上}}count = 81-my_count;//count即为当前数独表格中已有的数字个数}

三,函数PutChess

        函数PutChess的功能是将数字放入数独表格。为此,我们需要有10个按键(1-9,以及撤回前一步),以及完成“点击即填入数字”的设计。

        PutChess函数的设计如下:

        //需要在public class的开头定义last_i和last_j

void PutChess(int i, int j){sudokuBoard[i, j] = number;//标记//记录上一次放置数字的位置,用于撤回last_i = i;last_j = j;//记录本局放了多少数字,看游戏是否结束count++;}

        10个按键的设计如下:

        //要将这段代码放在OnGUI的if(!GameOver){  }中

        //FixNumber函数会在后续补充定义,功能为记录“即将放入空格的数字”。

for (int i = 0; i < 10; i++)//显示界面下方待填入的数字(0-9)
{if (GUI.Button(new Rect(155 + i * 50, 550, 50, 50), num_str[i])){FixNumber(i);}
}

四,GameOver函数

功能为判定游戏是否结束、以什么方式结束(胜/负)

//仅当数独表格填满、count为81时才有可能胜利,也有可能失败,但都返回true意味着游戏结束

//未填满时都返回false意味着未结束

bool GameOver()//判断游戏结束(不够严谨){if(count>=81)//填满棋盘时才判定{for (int i = 0; i < 9; i++)//判断每行每列{int sum1 = 0;//统计每行int sum2 = 0;//统计每列int sum3 = 0;//统计每个九宫格for (int j = 0; j < 9; j++){sum1 += sudokuBoard[i, j];sum2 += sudokuBoard[j, i];//此处是统计第i个九宫格里的所有九个数字sum3 += sudokuBoard[(i * 3) % 9 + j % 3, j / 3 + (i / 3) * 3];}if ((sum1 == 45) || (sum2 == 45) || (sum3==45)){continue;}//发现和不为45的,提示数独失败GUI.Box(new Rect(520, 100, 400, 400), "\n\n\n\n\nI'm Sorry\n You has lost.");return true;//结束了,但是输了}//能离开循环说明填对了GUI.Box(new Rect(520, 100, 400, 400), "\n\n\n\n\nCongratulations!\n You has won.");return true;//结束且胜利}return false;//没填满棋盘就是没结束}

五,FixNumber函数

顾名思义,其实就是修改number这个变量,用于每次鼠标点击时点击填入数字

    void FixNumber(int i){number = i;}

六,Start函数

        Start函数是unity初始化游戏的唯一入口。在此函数中,我们只需将Init函数放入,实现初始化

void Start(){Init();}

改进方向

        至此,一个“预设好答案并随机挖空生成题目”的数独游戏就完成啦!

        b站视频链接:

只是一个还没长开的unity数独游戏罢了_哔哩哔哩bilibili

Unity数独视频

        当然,还可以从以下几个方面进行改进:

        1.用更多方式进行挖空,提升游戏难度;

        2.随机生成答案,而不仅仅是对固定的答案进行随机挖空;

        3.让撤回的范围从“只能撤回前一步”变为“撤回更多步”,或者“擦除固定一格的数据”,提升玩家的游玩体验;

        4.美化界面;

        5.加入点击音效/点击动画等操作的反馈;

        6.加入规则介绍。

这篇关于lab03—unity制作简易数独的文章就介绍到这儿,希望我们推荐的文章对编程师们有所帮助!



http://www.chinasem.cn/article/192553

相关文章

python实现简易SSL的项目实践

《python实现简易SSL的项目实践》本文主要介绍了python实现简易SSL的项目实践,包括CA.py、server.py和client.py三个模块,文中通过示例代码介绍的非常详细,对大家的学习... 目录运行环境运行前准备程序实现与流程说明运行截图代码CA.pyclient.pyserver.py参

使用PyQt实现简易文本编辑器

《使用PyQt实现简易文本编辑器》这篇文章主要为大家详细介绍了如何使用PyQt5框架构建一个简单的文本编辑器,文中的示例代码讲解详细,感兴趣的小伙伴可以跟随小编一起学习一下... 目录分析主窗口类 (MyWindow)菜单操作语法高亮 (SyntaxHighlighter)运行程序主要组件代码图示分析实现

5分钟获取deepseek api并搭建简易问答应用

《5分钟获取deepseekapi并搭建简易问答应用》本文主要介绍了5分钟获取deepseekapi并搭建简易问答应用,文中通过示例代码介绍的非常详细,对大家的学习或者工作具有一定的参考学习价值,需... 目录1、获取api2、获取base_url和chat_model3、配置模型参数方法一:终端中临时将加

用Java打造简易计算器的实现步骤

《用Java打造简易计算器的实现步骤》:本文主要介绍如何设计和实现一个简单的Java命令行计算器程序,该程序能够执行基本的数学运算(加、减、乘、除),文中通过代码介绍的非常详细,需要的朋友可以参考... 目录目标:一、项目概述与功能规划二、代码实现步骤三、测试与优化四、总结与收获总结目标:简单计算器,设计

如何用Python绘制简易动态圣诞树

《如何用Python绘制简易动态圣诞树》这篇文章主要给大家介绍了关于如何用Python绘制简易动态圣诞树,文中讲解了如何通过编写代码来实现特定的效果,包括代码的编写技巧和效果的展示,需要的朋友可以参考... 目录代码:效果:总结 代码:import randomimport timefrom math

使用Python制作一个PDF批量加密工具

《使用Python制作一个PDF批量加密工具》PDF批量加密‌是一种保护PDF文件安全性的方法,通过为多个PDF文件设置相同的密码,防止未经授权的用户访问这些文件,下面我们来看看如何使用Python制... 目录1.简介2.运行效果3.相关源码1.简介一个python写的PDF批量加密工具。PDF批量加密

通过C#和RTSPClient实现简易音视频解码功能

《通过C#和RTSPClient实现简易音视频解码功能》在多媒体应用中,实时传输协议(RTSP)用于流媒体服务,特别是音视频监控系统,通过C#和RTSPClient库,可以轻松实现简易的音视... 目录前言正文关键特性解决方案实现步骤示例代码总结最后前言在多媒体应用中,实时传输协议(RTSP)用于流媒体服

用Unity2D制作一个人物,实现移动、跳起、人物静止和动起来时的动画:中(人物移动、跳起、静止动作)

上回我们学到创建一个地形和一个人物,今天我们实现一下人物实现移动和跳起,依次点击,我们准备创建一个C#文件 创建好我们点击进去,就会跳转到我们的Vision Studio,然后输入这些代码 using UnityEngine;public class Move : MonoBehaviour // 定义一个名为Move的类,继承自MonoBehaviour{private Rigidbo

OpenStack离线Train版安装系列—0制作yum源

本系列文章包含从OpenStack离线源制作到完成OpenStack安装的全部过程。 在本系列教程中使用的OpenStack的安装版本为第20个版本Train(简称T版本),2020年5月13日,OpenStack社区发布了第21个版本Ussuri(简称U版本)。 OpenStack部署系列文章 OpenStack Victoria版 安装部署系列教程 OpenStack Ussuri版

OpenStack镜像制作系列5—Linux镜像

本系列文章主要对如何制作OpenStack镜像的过程进行描述记录 CSDN:OpenStack镜像制作教程指导(全) OpenStack镜像制作系列1—环境准备 OpenStack镜像制作系列2—Windows7镜像 OpenStack镜像制作系列3—Windows10镜像 OpenStack镜像制作系列4—Windows Server2019镜像 OpenStack镜像制作