1、1C#课程设计报告题目:6. 扑克牌游戏学 院 自动化学院_专 业_网络工程 _年级班别_08 _学 号 学生姓名_ _ _ _指导教师_ _成 绩 2009 年 11 月 21 系统设计要求1.1 需求分析该系统要求在 Windows 平台下实现扑克牌游戏中的 21 点,模拟现实生活中的牌类游戏模式。该系统需要的主要功能有以下几个:A. 扑克牌游戏中的常规功能:1) 洗牌,发牌。牌向玩家显示的是正面或反面。统计赢了、输了、平了多少局的信息。2) 在每一个回合,玩家可根据自己已获得的牌以及对方摊开的牌选择某一个操作(如取牌) 。3) 对方(电脑)每个回合根据情况自动选择某个操作。4) 每个回合
2、结束后系统自动判断该局游戏是否结束以及输赢情况。B. 21 点游戏的功能:1) 玩家在每回合可选择“Hit 拿牌” 、 “Stand 停牌”的操作。当游戏结束后禁用这些操作2) 以数字的形式显示玩家获得的牌的大小总和,以及对方(电脑)获得的牌中已摊开给玩家看的牌的大小总和。3)在信息栏中显示与游戏相关的信息。包括“游戏正在进行” 、“游戏进行中。对方已停牌” 、 “恭喜你,你赢了” 、 “很遗憾,你输了” 、“还不错,平局” 。1.2 界面要求要求界面简洁美观,简单易用。1.3 设计环境及调试环境Visual Studio 2008 SP1、Windows 7.2 设计思路2.1 用面向对象的
3、方法设计系统中主要的类有:Card、Player、Game、G21、Form1.类名 作用Card 实现牌模块Player 实现玩家模块Game 实现游戏模块G21 实现 21 点游戏模块Form1 实现整个系统的模块3对象的包含关系.Form1 formG21 agamePlayer a Player b Card cardCard owncards Card owncards系统运行后,首先实例化 Form1 的一个对象,实现窗体模块,如窗体布局、label 控件、按钮控件、 “关于”菜单等。通过窗体界面“开始”按钮的点击,生成由 Game 类派生的 G21 类的对象 agame,开始游戏
4、流程。随即 agame 实例化两个 Player 类的对象 a 与 b(分别对应于电脑与玩家)以及 Card 类的对象数组 card。然后 a 与 b 分别实例化他们的 Card 类对象数组 owncards。a) Card 类主要属性:public int number; / 牌的序号(152)public int num_x = 1; / 牌的数字(1、2 、313)public int num_y = 1; / 牌花(方块1、梅花2、红桃3、黑桃4 )public bool visibility; / 牌是否可见(牌面朝上或朝下)public int top = 20; / 牌左上角的纵
5、坐标public int left = 20; / 牌左上角的横坐标private Bitmap bmp; /内存位图引用private Form1 form; /窗体引用主要方法:private void define_num_x_y()/从序号明确牌的数字与牌花public void ShowOn( ) / 牌面朝上public void ShowOff( ) / 牌面朝下private void Paint( ) / 在游戏框内显示牌面public void Put(int x, int y) /摆放、 移动牌面b) Player 类主要属性:private Form1 form; /引
6、用窗体对象private Card owncards; /玩家手上的牌private int quantity; /拥有牌的数量public bool IsThisPlayerOne; /值为 true 代表此 Player 对象是玩家 1。玩家 1 的4牌在上方,玩家 2 的在下方。主要方法:public void getcard(Card thecard) /Player 取牌private void setCardPosition()/设置玩家手上每张牌的摆放位置.arraylastNum 为最后取的一张牌在 owncards数组的位置public void showallcards()
7、/摊开所有的牌public void showOnthecard(int n) /摊开第 n 张牌public void showOnthecard()/摊开最后拿的一张牌public int sum()/手中牌数字的总和c) G21 类主要属性:public int state; /游戏状态(0为正在游戏,1为a 赢,2为b 赢,3 为平局)private bool a_IfNotTakeCard; /玩家状态(true为玩家停牌)private bool b_IfNotTakeCard;主要方法:public void start()/开始游戏public void playerchoos
8、e(int x) /玩家在窗口点击操作按钮将调用此方法,参数代表不同的按钮。返回值为 True 代表取了牌public void pcplayerchoose()/电脑玩家的操作(该方法只用于 pcround()里)public void judge()/判断输赢private bool ifDraw()/判定是否平局(在已知其中一人赢了或玩家都不取牌的情况下才能使用此方法)private Player whowin(Player boy,Player girl) /判定谁赢(在已知其中一人赢了的情况下才能使用此方法)public void end()/结束游戏d) Game 类主要属性:pr
9、otected Bitmap bmp; /内存位图引用protected int takencardnum; /已抽出的牌数public Card card = new Card52; /牌数组(设为52张)protected Player a; /声明两个 Player对象protected Player b;主要方法:public void shuffle()/洗牌,打乱 card数组内的元素顺序(可重复执行几次.发牌后决不能执行)public void givecardto(Player aplayer) /发一张牌给 Player 对象e) Form1 类5主要属性:public Bi
10、tmap DrawingSurface;/内存位图。所有绘制在此进行,随后复制到窗体上。目的是使窗体重绘时保持已绘制的图案。public G21 agame;public int win;/玩家赢的次数public int lose;/玩家输的次数public int draw;/平局次数主要方法:public void InitializeSurface() /初始化内存位图private void start()/开始新一局类的层次图:2.2 流程图6新一局3 调试过程运行窗体开始游戏发牌是否需要结束拿牌或停牌结束下个回合判断、统计输赢情况并显示结果游戏结束7程序界面:开始游戏:游戏结束:
11、8对方(电脑)停牌:4 关键程序代码9a) Card 类这个类主要是实现每一张牌的应有功能,包括牌本身的数字与牌花的属性、把一张牌“放”在屏幕上并显示其正面或背面的方法。首先从参数获取三个必要的数据:内存位图、窗体 Form1 对象、此牌在所有扑克牌中的序号。内存位图为 Bitmap 类的对象,提供给 Card 的对象在上面 画画,把该对象所代表的牌画在上面。所有的 Card 对象均画在同一幅内存位图上。可把这幅内存位图看做是一个原件。在窗体 Form1 类的Paint()方法中加入“把这幅图印在窗体上”,每次系统调用 Paint()方法时(即窗体某些区域被掩盖而无效化时)便要印一次。可把窗体
12、中看到的图看做是刚才原件的复印件。此方法比直接采用 GDI+把牌画在窗体上要优胜,能够保持窗体所显示的图形。Form1 对象则是提供给 Card 类对象改变原件 位图时使窗体无效化,自动更新复印件。扑克牌的序号用来初始化该牌的数字与牌花。public Card(ref Bitmap DrawingSurface, Form1 form1, int serial_number) /构造函数bmp = DrawingSurface;form = form1;number = serial_number + 1; /从Game的对象获得该牌的序号.define_num_x_y();private v
13、oid define_num_x_y() /从序号明确牌的数字与牌花num_y = number % 4+1;num_x = (number - num_y-1) / 4 + 1;private void Paint( ) / 在游戏框内显示牌面if (visibility = true) /牌可见时显示正面string x = num_x.ToString();/ 牌的数字与牌花转换为字符串型用于下面的路径中string y = “a“; / 初始化为a(方块)switch (num_y)case 1:y = “a“;break;case 2:y = “b“;break;10case 3:y
14、 = “c“;break;case 4:y = “d“;break;Image myImage = Image.FromFile(“Resourcesz“ + x + y + “.jpg“); / 创建以所给路径的jpg为图形的对象. 例如:“z3b.jpg“为“ 梅花3“,其中“3“代表数字“3”,“b“代表“梅花“Graphics gg = Graphics.FromImage(bmp);gg.DrawImage(myImage, left, top,78,116); / 把牌画在bmp 上。最后两个参数是宽,高。gg.Dispose(); / 释放Graphics 对象ggform.In
15、validate();else /牌不可见时显示背面Image myImage = Image.FromFile(“Resourcesback.jpg“); / 以牌背的图像为Image对象Graphics gg = Graphics.FromImage(bmp);gg.DrawImage(myImage, left, top,78,116); / 把牌的背面画在bmp 上gg.Dispose();/ 释放Graphics 对象ggform.Invalidate();b) Player 类该类可实现玩家对手中的牌进行操作,如从 Game 类对象获取一只牌,手上的各张牌如何摆放在屏幕上,计算手上
16、的牌大小总和。public void getcard(Card thecard) /Player取牌owncardsquantity = thecard;setCardPosition();owncardsquantity.ShowOff();quantity+;private void setCardPosition()/设置玩家手上每张牌的摆放位置 .arraylastNum为最后取的一张牌在owncards数组的位置int basepoint_x=20; /以第一张牌的左上角点为基准点basepoint,用于计算各牌在窗体的位置int basepoint_y;if (IsThisPlay
17、erOne = true)basepoint_y = 30;11elsebasepoint_y = 200;for (int i = 0; i 21 else if (girlsum 21 elsereturn null;e) Form1 类该类实现系统的主要操作,如显示界面、提供接口供用户进行操作等。其中,初始化内存位图时显示出一幅绿色台面图片。public void InitializeSurface()/初始化内存位图Graphics gg;gg = Graphics.FromImage(DrawingSurface);gg.Clear(SystemColors.Control);Ima
18、ge table = Image.FromFile(“Resourcestable.jpg“);gg.DrawImage(table, 0, 0,760,533);gg.Dispose();this.Invalidate();private void Form1_Paint(object sender, PaintEventArgs e)e.Graphics.DrawImage(DrawingSurface, 0, 0, DrawingSurface.Width, DrawingSurface.Height);e.Graphics.Dispose();private void start()/
19、开始新一局buttonStart.Enabled = false; /禁用Start按钮agame = new G21(ref DrawingSurface, this); /建立游戏对象agame.start();label1.Text = “游戏正在进行“;buttonHit.Enabled = true; /启用Hit按钮buttonStand.Enabled = true; /启用Stand按钮14label7.Enabled = true; /显示“统计“二字5 总结对该软件的补充说明:根据系统的设计,用 C#语言编写出来的源码最终能够顺利编译并稳定运行,达到了预期效果。基于灵活性的
20、考虑,牌的显示不用 PictureBox 控件来实现,而采用GDI+以及内存位图来实现。从 Game 类还可以派生出其他扑克游戏类,并且牌的显示应该能够通过 Card 类的 put()方法结合定时控件 Timer 来产生出更丰富的形式,如动态式移动。由于时间关系,很多游戏效果未能设计并实现出来。心得与体会:在课堂上,我学到了 C#的皮毛中的皮毛,以及学习编程技术的方法、Visual Studio 逐语句调试程序等。而在这个课程设计中,我就学到了 C#的大部分皮毛了。C# 或许是我以后发展的方向。这个课程设计以及报告应该是我有史以来投入的精力以及时间最多的一次了,从一开始担心是否能完成这个题目,
21、到一天一天看着自己编的这个程序慢慢健全,就好像自己在抚养一个渐渐长大的孩子。如今看到这个程序长大成人了,心里也觉得很安慰。回想起整个编写过程,就好像是经历一关一关的解谜游戏。首先是牌的图像素材,这肯定要从网上找了,结果找到的是一张包括所有牌的矢量图,于是装了个 Adobe Illustrator CS4 研究如何把素材编程 jpg。然后又用 Photoshop 把图片分割成一张牌为一张图,然后调整大小等等。游戏界面的绿色桌面图片是从 Windows7 自带的纸牌游戏中用 QQ 的截图工具截取的。接着,遇到了在代码中要获取素材,那个路径就有问题了。后来,发现要用相对路径,于是把相对路径的一些知识
22、也学了。然后到了一个困扰多天的问题,就是窗体的图像如何保持不变,不受到窗体区域无效化的影响。幸好在图书馆找到Visual C# 2005 入门经典这本书,里面就有介绍如何用内存位图的方法解决这个问题。然后就是如何在其他类的对象中调用 Form1 类的对象,这本是一个简单的问题,却因为初时误以为 Form1 是一个对象,结果找了一些窗体句柄的资料看了一下,后来就意识到可以用 Form1 类的对象作为参数传给其他类的对象。到最后就是输赢的判断,对算法比较讲究。整个过程,用得最多的工具就是互联网和 MSDN。互联网用来查找出现错误的原因、实现某种方法需要用到Visual Studio 自带的什么类;MSDN 则用来查某个类的使用格式以及注意事项是什么。总之,这门选修课让我获益良多。6 参考书目Visual C# 2005 入门经典美 James Foxall 著,陈秋萍 译,2007C#程序设计简明教程 陈佛敏 潘春华 吕洋波 编著,200815