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

本文涉及的产品
公共DNS(含HTTPDNS解析),每月1000万次HTTP解析
云解析 DNS,旗舰版 1个月
全局流量管理 GTM,标准版 1个月
简介: 技术经验解读:【转】详细解析用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,

相关文章
|
3天前
|
编译器 C# 开发者
C# 9.0 新特性解析
C# 9.0 是微软在2020年11月随.NET 5.0发布的重大更新,带来了一系列新特性和改进,如记录类型、初始化器增强、顶级语句、模式匹配增强、目标类型的新表达式、属性模式和空值处理操作符等,旨在提升开发效率和代码可读性。本文将详细介绍这些新特性,并提供代码示例和常见问题解答。
14 7
C# 9.0 新特性解析
|
6天前
|
机器学习/深度学习 人工智能 自然语言处理
思通数科AI平台在尽职调查中的技术解析与应用
思通数科AI多模态能力平台结合OCR、NLP和深度学习技术,为IPO尽职调查、融资等重要交易环节提供智能化解决方案。平台自动识别、提取并分类海量文档,实现高效数据核验与合规性检查,显著提升审查速度和精准度,同时保障敏感信息管理和数据安全。
40 11
|
2天前
|
Kubernetes Cloud Native 云计算
云原生技术深度解析:重塑企业IT架构的未来####
本文深入探讨了云原生技术的核心理念、关键技术组件及其对企业IT架构转型的深远影响。通过剖析Kubernetes、微服务、容器化等核心技术,本文揭示了云原生如何提升应用的灵活性、可扩展性和可维护性,助力企业在数字化转型中保持领先地位。 ####
|
2天前
|
C# 开发者
C# 10.0 新特性解析
C# 10.0 在性能、可读性和开发效率方面进行了多项增强。本文介绍了文件范围的命名空间、记录结构体、只读结构体、局部函数的递归优化、改进的模式匹配和 lambda 表达式等新特性,并通过代码示例帮助理解这些特性。
10 2
|
2天前
|
自然语言处理 并行计算 数据可视化
免费开源法律文档比对工具:技术解析与应用
这款免费开源的法律文档比对工具,利用先进的文本分析和自然语言处理技术,实现高效、精准的文档比对。核心功能包括文本差异检测、多格式支持、语义分析、批量处理及用户友好的可视化界面,广泛适用于法律行业的各类场景。
|
6天前
|
机器学习/深度学习 人工智能 自然语言处理
医疗行业的语音识别技术解析:AI多模态能力平台的应用与架构
AI多模态能力平台通过语音识别技术,实现实时转录医患对话,自动生成结构化数据,提高医疗效率。平台具备强大的环境降噪、语音分离及自然语言处理能力,支持与医院系统无缝集成,广泛应用于门诊记录、多学科会诊和急诊场景,显著提升工作效率和数据准确性。
|
9天前
|
监控 Cloud Native 持续交付
云原生技术深度解析:重塑现代应用开发与部署范式####
本文深入探讨了云原生技术的核心概念、关键技术组件及其在现代软件开发中的重要性。通过剖析容器化、微服务架构、持续集成/持续部署(CI/CD)等关键技术,本文旨在揭示云原生技术如何促进应用的敏捷性、可扩展性和高可用性,进而推动企业数字化转型进程。不同于传统摘要仅概述内容要点,本部分将融入具体案例分析,直观展示云原生技术在实际应用中的显著成效与挑战应对策略,为读者提供更加丰富、立体的理解视角。 ####
|
9天前
|
算法 Java 数据库连接
Java连接池技术,从基础概念出发,解析了连接池的工作原理及其重要性
本文详细介绍了Java连接池技术,从基础概念出发,解析了连接池的工作原理及其重要性。连接池通过复用数据库连接,显著提升了应用的性能和稳定性。文章还展示了使用HikariCP连接池的示例代码,帮助读者更好地理解和应用这一技术。
24 1
|
10天前
|
安全 测试技术 数据安全/隐私保护
原生鸿蒙应用市场开发者服务的技术解析:从集成到应用发布的完整体验
原生鸿蒙应用市场开发者服务的技术解析:从集成到应用发布的完整体验

推荐镜像

更多
下一篇
无影云桌面