技术经验解读:【转】详细解析用C#写的小游戏《彩色连珠》(附源代码)

本文涉及的产品
全局流量管理 GTM,标准版 1个月
云解析 DNS,旗舰版 1个月
公共DNS(含HTTPDNS解析),每月1000万次HTTP解析
简介: 技术经验解读:【转】详细解析用C#写的小游戏《彩色连珠》(附源代码)

不久前写的一个小游戏,最近拿出来稍微修改完善了一下,因为自己现在“不得已”改行学Java了,这个小游戏就当是自己与C#的告别吧,不过以后如果自己有什么想写的小程序,C#仍然是首先考虑的语言了,因为Java做GUI太蛋疼了。


首先声明本人菜鸟一个,快毕业的学生党,这篇文章完全是记录自己的一些点滴吧。


游戏的规则很简单,大概是:10X10的方格,游戏开始时随机出5个球,颜色也是随机的,用户点击球让其移动,5个(或更多)相同颜色的球在一起就可以消掉,如果没有可以消的,就又随机出3个球,直到棋盘满为止。


游戏界面如下:


具体思路如下:


左边的是一个panel面板,用来当做棋盘,启动时把方格线画好,这些球都是一些事先弄好的图片文件(考虑过用图形学的方法代码生成,但是感觉效率太低,最重要的是不好看,所以还是放弃了),通过g.DrawImage()的方法画在面板上,清空的话就是用背景色填充,点击某个球会动态的变化大小,点击空白处会将之前点过的球动态的移动到那里,球每次移动时需要查找能够到达指定位置的最短路径,所以会用到《人工智能》课上用过的查找算法查找最短路径,出子就是用Random随机函数随机的在某个位置画某种颜色的球,每次移动球后都要判断在横、竖、左斜、右斜四个方向上是否有可以消的球,消完球后随机出3个球,出球的同时要判断棋盘是否满。


简单的实现了保存成绩的功能(以及对成绩进行加密),功能做的很简陋,其实还可以添加一些声音的,限于时间就没弄了,有兴趣的可以尝试一下。


好了,也不多写什么了,因为我觉得代码里面的注释已经够详细了,更多的问题还是看代码里面的注释吧。


下面把几个比较重要的地方单独写出来。


首先最重要的是画图要怎么画,也就是采用什么函数来画。


C#画图最常见的一般有3种方式:


一种是,这种方法优点是窗体最小化或者被其它窗体遮挡后画的图不会消失,缺点是每次画完图都要刷新整个区域,所以有可能闪屏很严重:


Bitmap bit = new Bitmap(panel游戏区.Width,panel游戏区.Height);//实例化一个Bitmap


Graphics g = Graphics.FromImage(bit);


g.DrawImage(Image.FromFile("picturePath"),left,top,width,height);//画图


panel游戏区.BackgroundImage = bit;


还有一种是用控件的CreateGraphics()方法创建一个Graphic对象,优点很明显,就是非常方便,不用每次都要刷新,所以一般不会出现闪屏现象,但是当窗体最小化还原或者被其它窗体遮挡后就一片空白了,到网上查过一些资料,好像是因为这种画图方式数据都是保存在缓存中的,窗体只要最小化就会触发paint事件重绘,系统自带的控件重绘的代码都写好了,但是我们自己的这个画图区域因为没有写重绘事件,所以还原后一片空白,解决办法就是在paint事件里手动对空白区域进行重绘,本游戏采用的就是这种方法:


Graphics g = panel游戏区.CreateGraphics();


g.DrawImage(Image.FromFile("picturePath"), left, top, width, height);


还有一种方法是写在控件的Paint事件里,缺点很明显,都是不方便,很多代码我们没办法写在这里,比如鼠标事件发生的一些画图代码。


Graphics g = e.Graphics;


g.DrawImage(Image.FromFile("picturePath"), left, top, width, height);


首先是画方格线,比较简单:


private void drawLine()//画方格线的函数


{


Graphics g = panel游戏区.CreateGraphics();


for (int i = 0; i < m; i++)


{


g.DrawLine(new Pen(Color.Black), 0, panel游戏区.Height / m i, panel游戏区.Width, panel游戏区.Height / m i);


g.DrawLine(new Pen(Color.Black), panel游戏区.Width / m i, 0, panel游戏区.Width / m i, panel游戏区.Height);


}


}


其次是在指定行和列处画指定颜色的球,因为后面有些地方有需要,重载了3次,这里只列出其中一个,其它类似。这里顺便讲一下关于资源文件的使用,因为把所以图片放在文件夹里不方便,所以我还是想把所以图片放到资源文件里面去,但是C#里根据资源文件名来查找资源文件还确实不是那么容易,找了很久的资料才解决,具体的就是ResourceManager里面的一个参数不好写,很容易写错,具体事项看下面代码和注释吧:



///


/// 画球的函数


///


///


行数


///


列数


///


要画的球的颜色


///


指定球比方格要小的像素个数


private void drawBall(int i, int j, Color color,int dx)


{


//关于图片:如果直接将这些不同颜色的球的图片放在程序根目录文件夹来操作比较简单,


//但是缺点就是老是要跟一个文件夹,不方便,所以将所有图片放入程序的资源文件


//至于怎样调用程序的资源文件,查找了很多资料后终于得到解决,具体方法看下面的代码。


Graphics g = panel游戏区.CreateGraphics();


g.InterpolationMode = InterpolationMode.HighQualityBicubic;//高质量显示图片


int x = panel游戏区.Width / m, y = panel游戏区.Height / m;//x,y分别为单个方块宽和高


string temp = color.ToString().Substring(7).Replace("】", "");//color的颜色值转换为字符串后形如:color【Red】,本句代码执行后的结果为Red


//string picturePath = Application.StartupPath + @"\球\" + temp + ".png";//到程序目录中查找指定颜色球的路径,如:C:\Documents and Settings\Administrator\桌面\刘显安\彩色连珠\bin\Debug\球\Red.png


//代码效果参考:http://www.lyjsj.net.cn/wz/art_22850.html

System.Resources.ResourceManager manager = new System.Resources.ResourceManager("彩色连珠.Properties.Resources", System.Reflection.Assembly.GetExecutingAssembly());

//上面一句话是实例化一个ResourceManager,这里一定要注意baseName的写法,为:命名空间+文件夹名+资源文件名(不带后缀名),不知道怎么写的可以到“Resources.Designer.cs”这个文件里去找


//用这个写法的目的是为了方便根据资源文件名来查找,如果不需要查找的画则比较简单,如下:


//首先添加以下引用:using 彩色连珠.Properties;然后直接写:Resources.Red就可以获取资源文件了。


g.DrawImage((Bitmap)manager.GetObject(temp), x j + dx, y i + dx, x - dx - dx, y - dx - dx);//将图片画在游戏区


ball【i, j】 = color;//同时更新ball数组


//g.FillEllipse(new SolidBrush(color),xj+5,yi+5,x-10,y-10);//如果是直接用系统函数画圆的画就用这句话


}


清空某个方格的代码:


///


/// 用背景色填充指定方格,以达到清除的目的


///


///



///



private void clearBall(int i,int j)


{


Graphics g = panel游戏区.CreateGraphics();


int x = panel游戏区.Width / m, y = panel游戏区.Height / m;


g.FillRectangle(new SolidBrush(panel游戏区.BackColor), x j + 2, y i + 2, x - 4, y - 4);


ball【i, j】= panel游戏区.BackColor;


}


随机出球的函数:


///


/// 游戏开始时随机出球,位置随机,颜色也随机(用于没有下一组提示的时候)


///


private void drawBallRandom()


{


if (!checkOver())


{


Random random = new Random();


bool flag = true;


while (flag)


{


int i = random.Next(0, 10);


int j = random.Next(0, 10);


if (ball【i, j】 == panel游戏区.BackColor)


{


flag = false;


int c = random.Next(0, colorNum);


//MessageBox.Show(i + "," + j + ":" + color【c】.ToString());


drawBall(i, j, color【c】);


checkSuccess(i, j);//出子后要判断是否有可以消的球


}


}


}


}


产生下一组随机球:


///


/// 产生下一组随机球


///


private void makeNextColor()


{


Graphics g = pictureBox下一组.CreateGraphics();


g.Clear(pictureBox下一组.BackColor);


Random random = new Random();


for (int i = 0; i < 3; i++)


{


nextColor【i】 = random.Next(0,colorNum);


drawBall(i,nextColor【i】);


}


}


panel的paint事件,作用在下面的注释已经写明了,有些函数是在后面定义的,这里暂时还没写出来:


//游戏区的重绘事件,这个事件的作用主要有2个:一个是让游戏第一次运行时画方格线


//以及随机出5个子(这些代码不能放在Form_Loaded事件里,因为窗体第一次生成会触发


//Paint事件进而覆盖原图),第二个作用是解决当窗体最小化或改变大小时绘图区一片空


//白的问题,解决的思路就是方格线和球全部重绘。


//用“Bitmap bit= new Bitmap(x,y);Graphics g=Graphics.FromImage(bit);”的方法


//不会出现最小化变空白的现象,但每次画完图后都必须刷新,因此闪屏现象严重。


private void panel游戏区_Paint(object sender, PaintEventArgs e)


{


drawLine();//画方格线


for (int i = 0; i < m; i++)


for (int j = 0; j < m; j++)


if (ball【i, j】 != panel游戏区.BackColor)


{


drawBall(i,j,ball【i,j】); //如果该位置的颜色不是背景色(即没有球)则按照指定颜色画球


}


makeNextColor();//防止窗口最小化后还原一片空白


if (isFirstRun)//如果是第一次运行


{


for (int i = 0; i < 5; i++)


drawBallRandom();//随机出5个球


makeNextColor();


isFirstRun = false;


}


}


鼠标的单击事件,游戏的主要驱动都来自这个事件:


private void panel游戏区_MouseClick(object sender, MouseEventArgs e)//游戏区的鼠标单击事件


{


timer缩放.Enabled = false;//结束球的缩放


int x = panel游戏区.Width / m, y = panel游戏区.Height / m;


if (ball【e.Y / y, e.X / x】 != panel游戏区.BackColor)//如果单击的是球


{


dx = 5;//让dx恢复到默认值


if(move_i>=0)


drawBall(move_i, move_j, ball【move_i, move_j】, dx);


//在新的球缩放时将上次点的球(如果有)重置为默认大小(因为球动态变换大


//小,所以停止缩放时可能不是默认大小,这句话是重新画一个默认大小的球)


move_i = e.Y / y;


move_j = e.X / x;


timer缩放.Enabled = true;//让单击过的球开始动态变换大小


}


else if (move_i >= 0 && move_j >= 0)//如果单击的是空白处,且有一个即将移动的球


{


bool【,】 isHaveBall = new bool【m, m】;//保存棋盘上每个位置是否有球的信息


for (int i = 0; i < m; i++)


for (int j = 0; j < m; j++)


{


if (ball【i, j】 == panel游戏区.BackColor)


isHaveBall【i, j】 = false;


else


isHaveBall【i, j】 = true;


}


int end_i = e.Y / y, end_j = e.X / x;//目标行与列


Search s = new Search(isHaveBall, m, move_i, move_j, end_i, end_j);//实例化一个查找类


path = s.start();//开始查找


if (path【0】【0】 != 0)//如果查找成功


{


path_idx = 2;//path数组第一组数据是长度,第二组数据是起点,所以要从第三组数据开始


timer移动.Enabled = true;


//string t = ""; //下面注释的代码用来查看文本形式的路径信息,仅供程序员调试看,玩家不需要管


//for (int i = 1; i <= path【0】【0】; i++)


//{


// t += path【i】【0】 + "," + path【i】【1】 + " ";


//}


// MessageBox.Show(t);


}


}


}


检查是否有5个(或更多)颜色相同的球在一起,并计算分数,5个子10分,6个子20分,以此类推:


///


/// 检查是否有5个颜色相同的球连在一起


///


///


起始查找位置的行


///


起始查找位置的列,为什么不用字母“l”呢?因为和数字“1”长得太像了!(汗)


/// 检查的结果


private bool checkSuccess(int h,int lie)


{


bool f = false;


int【】【】 res = new <span style="color: rgba(0, 0,

相关文章
|
2月前
|
机器学习/深度学习 人工智能 自然语言处理
AI技术深度解析:从基础到应用的全面介绍
人工智能(AI)技术的迅猛发展,正在深刻改变着我们的生活和工作方式。从自然语言处理(NLP)到机器学习,从神经网络到大型语言模型(LLM),AI技术的每一次进步都带来了前所未有的机遇和挑战。本文将从背景、历史、业务场景、Python代码示例、流程图以及如何上手等多个方面,对AI技术中的关键组件进行深度解析,为读者呈现一个全面而深入的AI技术世界。
197 10
|
2天前
|
机器学习/深度学习 人工智能 算法
DeepSeek技术报告解析:为什么DeepSeek-R1 可以用低成本训练出高效的模型
DeepSeek-R1 通过创新的训练策略实现了显著的成本降低,同时保持了卓越的模型性能。本文将详细分析其核心训练方法。
110 10
DeepSeek技术报告解析:为什么DeepSeek-R1 可以用低成本训练出高效的模型
|
21天前
|
缓存 算法 Oracle
深度干货 如何兼顾性能与可靠性?一文解析YashanDB主备高可用技术
数据库高可用(High Availability,HA)是指在系统遇到故障或异常情况时,能够自动快速地恢复并保持服务可用性的能力。如果数据库只有一个实例,该实例所在的服务器一旦发生故障,那就很难在短时间内恢复服务。长时间的服务中断会造成很大的损失,因此数据库高可用一般通过多实例副本冗余实现,如果一个实例发生故障,则可以将业务转移到另一个实例,快速恢复服务。
深度干货  如何兼顾性能与可靠性?一文解析YashanDB主备高可用技术
|
15天前
|
Web App开发 Linux C#
C# 网页截图全攻略:三种技术与 Chrome 路径查找指南
本文主要介绍了在 C# 中实现网页截图的几种技术及相关要点。涵盖了 PuppeteerSharp、Selenium 和 HtmlToImage 三种方式,分别阐述了它们的安装步骤及核心代码。同时,针对在 C# 中寻找 Windows 上 chrome.exe 路径这一问题,分析了未安装 Google Chrome 和已安装两种情况下的查找原因,并给出了相关参考链接,还列举了一系列与 C# 使用 Selenium、获取 chrome.exe 路径以及在 Linux 上部署相关的参考资料。
50 11
|
1月前
|
Serverless 对象存储 人工智能
智能文件解析:体验阿里云多模态信息提取解决方案
在当今数据驱动的时代,信息的获取和处理效率直接影响着企业决策的速度和质量。然而,面对日益多样化的文件格式(文本、图像、音频、视频),传统的处理方法显然已经无法满足需求。
83 4
智能文件解析:体验阿里云多模态信息提取解决方案
|
30天前
|
Kubernetes Linux 虚拟化
入门级容器技术解析:Docker和K8s的区别与关系
本文介绍了容器技术的发展历程及其重要组成部分Docker和Kubernetes。从传统物理机到虚拟机,再到容器化,每一步都旨在更高效地利用服务器资源并简化应用部署。容器技术通过隔离环境、减少依赖冲突和提高可移植性,解决了传统部署方式中的诸多问题。Docker作为容器化平台,专注于创建和管理容器;而Kubernetes则是一个强大的容器编排系统,用于自动化部署、扩展和管理容器化应用。两者相辅相成,共同推动了现代云原生应用的快速发展。
121 11
|
2月前
|
域名解析 负载均衡 安全
DNS技术标准趋势和安全研究
本文探讨了互联网域名基础设施的结构性安全风险,由清华大学段教授团队多年研究总结。文章指出,DNS系统的安全性不仅受代码实现影响,更源于其设计、实现、运营及治理中的固有缺陷。主要风险包括协议设计缺陷(如明文传输)、生态演进隐患(如单点故障增加)和薄弱的信任关系(如威胁情报被操纵)。团队通过多项研究揭示了这些深层次问题,并呼吁构建更加可信的DNS基础设施,以保障全球互联网的安全稳定运行。
|
2月前
|
缓存 网络协议 安全
融合DNS技术产品和生态
本文介绍了阿里云在互联网基础资源领域的最新进展和解决方案,重点围绕共筑韧性寻址、赋能新质生产展开。随着应用规模的增长,基础服务的韧性变得尤为重要。阿里云作为互联网资源的践行者,致力于推动互联网基础资源技术研究和自主创新,打造更韧性的寻址基础服务。文章还详细介绍了浙江省IPv6创新实验室的成立背景与工作进展,以及阿里云在IPv6规模化部署、DNS产品能力升级等方面的成果。此外,阿里云通过端云融合场景下的企业级DNS服务,帮助企业构建稳定安全的DNS系统,确保企业在数字世界中的稳定运行。最后,文章强调了全链路极致高可用的企业DNS解决方案,为全球互联网基础资源的创新提供了中国标准和数字化解决方案。
|
2月前
|
开发框架 算法 .NET
C#/.NET/.NET Core技术前沿周刊 | 第 15 期(2024年11.25-11.30)
C#/.NET/.NET Core技术前沿周刊 | 第 15 期(2024年11.25-11.30)
|
2月前
|
开发框架 Cloud Native .NET
C#/.NET/.NET Core技术前沿周刊 | 第 16 期(2024年12.01-12.08)
C#/.NET/.NET Core技术前沿周刊 | 第 16 期(2024年12.01-12.08)

推荐镜像

更多