• 1.27 MB
  • 2022-04-22 13:33:02 发布

智能斗地主课程设计论文.doc

  • 82页
  • 当前文档由用户上传发布,收益归属用户
  1. 1、本文档共5页,可阅读全部内容。
  2. 2、本文档内容版权归属内容提供方,所产生的收益全部归内容提供方所有。如果您对本文有版权争议,可选择认领,认领后既往收益都归您。
  3. 3、本文档由用户上传,本站不保证质量和数量令人满意,可能有诸多瑕疵,付费之前,请仔细先通过免费阅读内容等途径辨别内容交易风险。如存在严重挂羊头卖狗肉之情形,可联系本站下载客服投诉处理。
  4. 文档侵权举报电话:19940600175。
'武汉工程大学计算机科学与工程学院综合设计报告智能斗地主课程设计摘要这次的智能斗地主综合设计是在VC++开发环境下编译的,旨在深入强化可视化编程课程的学习,提高综合设计能力,初步掌握独立设计一个小软件的过程,包括界面设计,功能设计等,培养学生可视化编程的能力。整个游戏采用结构化的方式进行编译,逐步完善系统功能。系统采用CSocket实现连网游戏。CSocket是MFC在CAsyncSocket基础上派生的一个同步阻塞Socket的封装类。而Socket是Windows中得到广泛应用的、开放的、支持多协议的网络编程接口。一个CSocket对象代表了一个比CAsyncSocket对象更高层次的WindowsSocket的抽象,CSocket类与CSocketFile类和CArchive类一起工作来发送和接收数据,因此使它更加容易使用。VirtualC++实现斗地主游戏主要有三部分。第一部分是界面设计;第二部分是游戏内核(包括出牌大小、如何过牌、出牌等)设计;第三部分是网络部分。解决了这三部分的问题,程序也就基本完成了。在程序中定义了比较出牌大小的Managers算法,对发牌、点牌进行设计的LBUTTONDOWN响应等来实现斗地主程序。本程序以斗地主为例,编程并实现了CSocket功能,达到了预期连网打牌的效果。运用软件工程的知识对程序开发过程进行详细介绍。经过详细设计、系统检测等方法来保证程序的稳定运行。本论文主要介绍了智能斗地主的开发背景,开发的过程和所要完成的功能。包括游戏界面的开发、基于CSocket网络游戏的实现、核心算法的实现。重点的说明了系统设计思想,设计的步骤、难点技术和解决方案。关键词:斗地主;游戏界面;游戏核心算法;网络连接;Socket-80- 武汉工程大学计算机科学与工程学院综合设计报告AbstractTheintelligentdoudizhuintegrateddesignisinvc++developmentenvironment,aimstofurtherstrengthenthecompilervisualprogrammingcourses,improvethecomprehensivedesignability,preliminarydesignofasmallhaveindependentsoftwareprocess,includinginterfacedesign,functionaldesign,cultivatingstudents"abilityofvisualprogramming.Thegameusingstructured,systematiccompilation.SystemusesCSockettoachievenetworkinggame.CSocketisasynchronousblockingSocketwrappersderivedbyMFCbasedonCAsynncSocket.TheSocketiswidelyusedforopen,multi-protocolnetworkprogramminginterfaceinwindows.ACSocketobjectrepresentsaWindowsSocketabstractatahigherlevelthanCAsyncSocket.ClassCSocket、CSocketFileandCArchiveworktogethertosendandreceivedata,soitismoreeasilyused.VirtualC++realizedoudizhueconomicalthreemaingame.Thefirstpartistheinterfacedesign,Thesecondpartisthekernel(includingacardgametosize,etc.),thebranddesign,Thethirdpartisthenetworkpart.Tosolvetheproblemofthreeparts,theprogramiscompleted.IntheprocessofthedefinitionofabrandManagerssizecomparisonalgorithmforlicensing,somebranddesignLBUTTONDOWNresponsetorealizedoudizhuproceduresetc.ThisprogramusesLandlordsasanexample,programmersimplementCSocketfunctionstoachievesthedesiredeffect.Usingknowledgeofsoftwareengineering,describesthedevelopmentprocessoftheprogramindetails.Afterdetaildesigning、systemtestingandothermethods,itensurethestableoperationoftheprogram.Thisarticlewillmainlyintroducethebackgroundofthiscoursedesig,theprocessofitsdevelopmentandthefunctionitshouldaccomplish,includingthedevelopmentofthegameinterface,onlinegamebasedonCSocketandthecorealgorithm.Iwillattachimportancetothemindofsystemdesign,procedure,difficulttechnologyandthesolution.Keywords:Doulandlord;interface;Gamecorealgorithm;Internetconnection;Socket-80- 武汉工程大学计算机科学与工程学院综合设计报告第一章概述1.1引言随着计算机的普及和网络技术的发展,各种各样的网络游戏在人们的生活中扮演越来越重要的角色。很多人都把一些小游戏作为工作之余的休闲活动,斗地主就在其中扮演了相当重要的角色,大部分人都有玩过各式各样的斗地主游戏。游戏就是在不停的完善当中才能越做越好,本程序只是作为一个简单的原型,虽然具备大部分斗地主游戏的功能,却有很多欠缺。1.1.1斗地主简介斗地主起源于湖北,据传是一位叫吴修全的年轻人,根据当地流行的扑克玩法“跑的快”改编的。斗地主玩法简单,娱乐性强,老少皆宜,如今已风靡整个中国,并流行于互联网上。四人斗地主的规则是由中国象棋棋王胡荣华总结和定型的,92181棋牌更是多次用这套规则举行网络斗地主比赛,上海也曾经用这套规则举办过多次电视转播的群众比赛。  斗地主对抗性和配合性都很强。该游戏由三个人玩(四人也能玩),用一副牌共54张牌。每局牌有一个玩家是“地主”,地主为一方,其余两家农民为另一方,双方对战,地主的目标是(以合法的出牌方式)先出完手里所有的牌,而农民的目标是在地主出完牌以前,先出完手里所有的牌。先出完牌的人所代表的一方获胜。斗地主属于基础类扑克游戏的范畴。斗地主后期又增加了网络斗地主,纳入了比赛制,已竞技为中心。如:淘汰赛制、循环赛制、双败淘汰赛制、积分晋级赛制、分组出线赛制、打立出局赛制、瑞士移位赛制、复活赛制等,以上的赛制在JJ比赛中得到的充分体现[1]。1.1.2斗地主规则一、发牌一副牌54张,一人17张,留3张做底牌,在确定地主之前玩家不能看底牌。二、叫牌叫牌按出牌的顺序轮流进行,叫牌时可以选择“叫地主”、“不叫”。如果有玩家选择“叫地主”则立即结束叫牌,该玩家为地主;如果都“不叫”,则重新发牌,重新叫牌,直到有人“叫地主”为止。三、第一个叫牌的玩家1、第一轮叫牌的玩家由系统随机选定。2、如果有玩家在叫牌前选择“明牌”,则第一个选择“明牌”的玩家优先获得叫牌权。3、如果有玩家在叫牌前选择“明牌”,且三名玩家都不选择“叫地主”,则系统选择第一个“明牌”的玩家为地主。四、抢地主1、当某位玩家叫完地主后,按照次序每位玩家均有且只有一次“抢地主”的机会。玩-80- 武汉工程大学计算机科学与工程学院综合设计报告家选择“抢地主”后,如果没有其他玩家继续“抢地主”则地主权利属于该名“抢地主”的玩家。2、如果没有任何玩家选择“抢地主”,则地主权利属于“叫地主”的玩家。3、每“抢地主”一次,游戏倍数*2。4、凡是有过“不叫地主”操作的玩家无法进行“抢地主”的操作。五、明牌1、明牌为亮明手上所有牌进行游戏,主要分三种:“明牌开始”、“发牌明牌”、“明牌”。2、明牌开始:在还没发牌时,就选择明牌并保持开始游戏,游戏倍数*5。3、发牌明牌:在发牌的过程中选择明牌游戏,根据发牌数量多少游戏倍数*4和*3。4、明牌:在收完三张底牌后可以选择明牌并开始游戏,游戏倍数*2。5、若同时有多名玩家选择“明牌”则按照最大的明牌倍数计算。六、加倍1、在选择抢完地主后,地主出牌前增加一个翻倍选择功能。在抢完地主后地主把底牌拿到手中,出现翻倍选择功能,用户可以选择加倍或不加倍。但若要进行加倍操作时,玩家必须符合特定条件。2、在限制时间内完成加倍或不加倍的操作后,必须等待其他玩家进行完相关操作或直到限制时间到,则游戏开始由地主出牌。3、加倍后游戏得分计算为:倍数*每分对应欢乐豆关系*自己加倍数*对手加倍数,若有加倍则*2,若没加倍则*1。4、加倍条件为规定的用户欢乐豆数量超过该房间规定的值即可。5、规定对象如下:1、加倍用户为地主时,必须全部玩家的欢乐豆数量全部超过房间规定数值。2、加倍用户为农民时,必须自己和地主玩家的欢乐豆数量全部超过房间规定数值。七、出牌将三张底牌交给地主,并亮出底牌让所有人都能看到。地主首先出牌,然后按逆时针顺序依次出牌,轮到用户跟牌时,用户可以选择“不出”或出比上一个玩家大的牌。某一玩家出完牌时结束本盘。八、牌型火箭:即双王(大王和小王),最大的牌。炸弹:四张同数值牌(如四个7)。单牌:单个牌(如红桃5)。对牌:数值相同的两张牌(如梅花4+方块4)。三张牌:数值相同的三张牌(如三个J)。三带一:数值相同的三张牌+一张单牌或一对牌。例如:333+6或444+99单顺:五张或更多的连续单牌(如:45678或78910JQK)。不包括2点和双王。双顺:三对或更多的连续对牌(如:334455、7788991010JJ)不包括2点和双王。三顺:二个或更多的连续三张牌(如:333444、555666777888)不包括2点和双王。飞机带翅膀:三顺+同数量的单牌(或同数量的对牌)。如:444555+79或333444555+7799JJ四带二:四张牌+两手牌。(注意:四带二不是炸弹)。如:5555+3+8或4444+55+77。九、牌型的大小火箭最大,可以打任意其他的牌。炸弹比火箭小,比其他牌大。都是炸弹时按牌的分值比大小。-80- 武汉工程大学计算机科学与工程学院综合设计报告除火箭和炸弹外,其他牌必须要牌型相同且总张数相同才能比大小。单牌按分值比大小,依次是大王>小王>2>A>K>Q>J>10>9>8>7>6>5>4>3,不分花色。对牌、三张牌都按分值比大小。顺牌按最大的一张牌的分值来比大小。飞机带翅膀和四带二按其中的三顺和四张部分来比,带的牌不影响大小。十、积分和级别基础分:叫牌的底分地主胜:地主得2*叫牌的底分,其余两家各得-叫牌的底分;地主败:  地主得-2*叫牌的底分分,其余两家各得叫牌的底分分。  ·每出一个炸弹或火箭,翻一倍;  ·地主出完牌,其余两家一张牌都未出,翻一倍级别:一级乞丐二级乞丐三级乞丐一级贫农二级贫农01004009001600三级贫农一级中农二级中农三级中农一级富农25003600490064008100二级富农三级富农小地主大地主保长1000012100144001690022500乡长镇长县长县太爷 256002890033800~~~ 图1-1级别1.2VisualC++基础知识1.2.1VisualC++简介面向对象编程具有三大特征,即封装性、继承性、多态性。VisualC++(简称VC++)是被公认为比较难入门的编程工具,它使用的编程语言是C++,但是由于VC++的平台依赖性,决定了它的使用必须要跟Windows操作系统紧密联系。这种操作系统相关性,大大增加了VC++的学习难度。主要原因包括Windows操作系统的复杂性和封闭性。复杂性包括操作系统的各类消息及其处理流程、令人眼花缭乱的API函数及宏定义和复杂的应用程序结构等;封闭性主要是指操作系统本身的非开放性。所以,如果缺少有效的学习引导,容易造成对VC++学习的“浅尝辄止”,被它的高难度所吓倒。-80- 武汉工程大学计算机科学与工程学院综合设计报告VisualC++作为一种程序设计语言,它同时也是一个集成开发工具,提供了软件代码自动生成和可视化的资源编辑功能。微软基本类库MFC(MicrosoftFoundationClassLibrary)含C++的基类、WinMain函数、支持标准菜单、常见消息处理、窗口滚动等元素API函数,在使用VisualC++开发应用程序过程中,系统为我们生成了大量的各种类型的文件,在本节中将要详细介绍VisualC++中这些不同类型的文件分别起到什么样的作用,在此基础上对VisualC++如何管理应用程序所用到的各种文件有一个全面的认识。首先要介绍的是扩展名为dsw的文件类型,这种类型的文件在VC中是级别最高的,称为Workspace文件。在VC中,应用程序是以Project的形式存在的,Project文件以.dsp扩展名,在Workspace文件中可以包含多个Project,由Workspace文件对它们进行统一的协调和管理。与dsw类型的Workspace文件相配合的一个重要的文件类型是以opt为扩展名的文件,这个文件中包含的是在Workspace文件中要用到的本地计算机的有关配置信息,所以这个文件不能在不同的计算机上共享,当我们打开一个Workspace文件时,如果系统找不到需要的opt类型文件,就会自动地创建一个与之配合的包含本地计算机信息的opt文件。上面提到Project文件的扩展名是dsp,这个文件中存放的是一个特定的工程,也就是特定的应用程序的有关信息,每个工程都对应有一个dsp类型的文件。以clw为扩展名的文件是用来存放应用程序中用到的类和资源的信息的,这些信息是VC中的ClassWizard工具管理和使用类的信息来源。对应每个应用程序有一个readme.txt文件,这个文件中列出了应用程序中用到的所有的文件的信息,打开并查看其中的内容就可以对应用程序的文件结构有一个基本的认识。在应用程序中大量应用的是以h和cpp为扩展名的文件,以h为扩展名的文件称为头文件。以cpp为扩展名的文件称为实现文件,一般说来h为扩展名的文件与cpp为扩展名的文件是一一对应配合使用的,在h为扩展名的文件中包含的主要是类的定义,而在cpp为扩展名的文件中包含的主要是类成员函数的实现代码。在应用程序中经常要使用一些位图、菜单之类的资源,VC中以rc为扩展名的文件称为资源文件,其中包含了应用程序中用到的所有的windows资源,要指出的一点是rc文件可以直接在VC集成环境中以可视化的方法进行编辑和修改。最后要介绍的是以rc2为扩展名的文件,它也是资源文件,但这个文件中的资源不能在VC的集成环境下直接进行编辑和修改,而是由我们自己根据需要手工地编辑这个文件。对于以ico,bmp等为扩展名的文件是具体的资源,产生这种资源的途径很多。使用rc资源文件的目的就是为了对程序中用到的大量的资源进行统一的管理。1.2.2VisualC++开发环境1.VisualC++6.0主界面-80- 武汉工程大学计算机科学与工程学院综合设计报告图1-2VisualC++6.0主界面2.应用向导(使用MFCAppWizard(exe)制作程序框架)第一步:选择程序类型l单文档应用程序SDI(一次只允许打开一个文档)l多文档应用程序MDI(允许同时打开多个文档)l基于单文档的应用程序(支持文档/视图结构,也可显示简单对话框)第二步:程序对数据库的支持•选择应用程序所需的数据库支持(4选项)、默认None(不需要)•全局应用程序对象theApp,theApp的构造函数->Winmain()•Winmain()->theApp的成员函数InitInstance()虚函数(要覆盖),构造主窗体,并显示更新,•->Run()(一般不要覆盖),就进入消息循环。第三步:程序对OLE和ActiveX控件的支持第四步:程序外观和对通信的支持第五步:程序的和风格、代码加注释、链接库设置第六步:选择视类的基类图1-3MFCAppWizard(exe)制作程序框架3.应用程序主要的类-80- 武汉工程大学计算机科学与工程学院综合设计报告4.用ClassWizard(建立类向导)添加消息响应函数•MFC提供了工具ClassWizard来帮助实现消息映射,在处理消息的类中添加一些有关消息映射的内容和处理消息的成员函数。程序员将完成消息处理函数,实现所希望的消息处理能力。•如果派生类要覆盖基类的消息处理函数,就用ClassWizard在派生类中添加一个消息映射条目,用同样的原型定义一个函数,然后实现该函数。这个函数覆盖派生类的任何基类的同名处理函数。•Windows消息,前缀以“WM_”打头,WM_COMMAND例外。Windows消息直接送给MFC窗口过程处理,窗口过程调用对应的消息处理函数。一般,由窗口对象来处理这类消息,也就是说,这类消息处理函数一般是MFC窗口类的成员函数。•能处理消息映射的类必须从CCmdTarget类派生。•如果一个类继承CCmdTarget,包含消息处理函数•头文件加上//{{AFX_MSG(CTttApp)afx_msgvoidOnAppAbout();//}}AFX_MSGDECLARE_MESSAGE_MAP()•实现文件加上BEGIN_MESSAGE_MAP(CTApp,CWinApp)//{{AFX_MSG_MAP(CTttApp)ON_COMMAND(ID_APP_ABOUT,OnAppAbout)//}}AFX_MSG_MAPEND_MESSAGE_MAP()•DECLARE_MESSAGE_MAP宏#defineDECLARE_MESSAGE_MAP()-80- 武汉工程大学计算机科学与工程学院综合设计报告private:staticconstAFX_MSGMAP_ENTRY_messageEntries[];protected:staticAFX_DATAconstAFX_MSGMAPmessageMap;virtualconstAFX_MSGMAP*GetMessageMap()const;•BEGIN_MESSAE_MAP宏#defineBEGIN_MESSAGE_MAP(theClass,baseClass)constAFX_MSGMAP*theClass::GetMessageMap()const{return&theClass::messageMap;}AFX_DATADEFconstAFX_MSGMAPtheClass::messageMap=//这是链表{&baseClass::messageMap,&theClass::_messageEntries[0]};constAFX_MSGMAP_ENTRYtheClass::_messageEntries[]=•ON_COMMAND宏#defineON_COMMAND(id,memberFxn){WM_COMMAND,CN_COMMAND,(WORD)id,(WORD)id,AfxSig_vv,(AFX_PMSG)memberFxn};•structAFX_MSGMAP{//得到基类的消息映射入口地址的数据或者函数#ifdef_AFXDLL//pfnGetBaseMap指向_GetBaseMessageMap函数constAFX_MSGMAP*(PASCAL*pfnGetBaseMap)();#else//pBaseMap保存基类消息映射入口_messageEntries的地址constAFX_MSGMAP*pBaseMap;#endif//lpEntries保存消息映射入口_messageEntries的地址constAFX_MSGMAP_ENTRY*lpEntries;};-80- 武汉工程大学计算机科学与工程学院综合设计报告图1-4ClassWizard添加消息响应函数5.退出应用•当用户从“文件”菜单选择执行“退出”时,将发送MFC标准命令消息ID_APP_EXIT。MFC实现了函数CWinApp::OnAppExit()来完成对该命令消息的缺省处理。voidCWinApp::OnAppExit(){//sameasdouble-clickingonmainwindowcloseboxASSERT(m_pMainWnd!=NULL);m_pMainWnd->SendMessage(WM_CLOSE);}•可以看出,其实现是向主窗口发送WM_CLOSE消息。主窗口处理完WM_CLOSE消息之后,关闭窗口,发送WM_QUIT消息,退出消息循环(见图5-3),进而退出整个应用程序。-80- 武汉工程大学计算机科学与工程学院综合设计报告图1-5Winmain函数流程图-80- 武汉工程大学计算机科学与工程学院综合设计报告第二章设计简介及设计方案论述2.1设计简介本程序是在MicrosoftVisualC++6.0语言中由MFC开发制作,基于单文档应用程序进行设计的,其目的是设计出一个三人斗地主程序;设计过程中可以把程序分为3部分。第一部分是界面;第二部分是游戏内核,用来计算是否可以出牌,由谁出牌,比较所出牌的大小,游戏是否结束等;第三部分是网络部分。网络加载桌面位图智能斗地主综合设计加载54张牌游戏界面发牌动画制作按钮功能实现鼠标移动设置加载套接字库创建用于监听套接字网络编程创建客户机和服务器绑定套接字及设定端口号发送或接收数据关闭套接字游戏数据的数据结构描述确定是否可以出牌游戏核心确定由谁出牌比较出牌大小出牌合理检测游戏是否结束图2-1设计简介图2.2设计方案2.2.1游戏界面设计方案一、加载位图加载桌面背景位图(background)和54张牌位图(card);-80- 武汉工程大学计算机科学与工程学院综合设计报告加载出牌、过牌、确定、退出按钮控件。图2-2桌面背景位图(background)图2-354张牌位图(card)二、绘制牌1、实现在还没发牌的时候,牌全部集中在中间时,在视类中定义一个函数voidCProgramView::CardReady()2.画作为底牌的三张牌当在叫地主的时候,牌只显示背面;当确定地主后,作为底牌的三张牌将显示给所有玩家-80- 武汉工程大学计算机科学与工程学院综合设计报告voidCProgramView::DrawLeft()3.画出已出的牌用K来控制画的类型,当K==0表示为左边出牌,K==1时为当前玩家出牌,K==2时为右边出牌,K==3时全部已出的牌都重画。4.画出当前玩家手中还没出的牌程序需要遍历一遍当前玩家手中还没出的牌,当牌被点起后,需要向上突起,用if(manager.PlayCards[manager.PlayerAc][i].Click来实现上面被选中牌的效果。5.画出从当前玩家视角看到的其它玩家手中剩的牌for(i=0;i<20&&cardleft[i].Num<=15;i++)三、动画制作在绘制动画的过程中采用了局部重画技术。局部重画就是在背景上截一块和想要覆盖的图像大小一样的背景贴在图上。在每画一张牌的时候把上次画的牌用背景覆盖掉,就形成了一个牌的飞行动画。当所有牌画完后删除定时器。当发牌动画播放完成后,调用PrintAll()进行重绘,交还程序控制权。那么,发牌动画基本制作完成。程序一共有3个地方需要发牌:1.3个玩家都点击了准备,主机发牌并在主机播放发牌动画;2.客户机收到发牌信息,在客户机播放发牌动画;3.最后一名玩家点击确定后播放发牌动画。发牌效果用Windows本身的定时器(Timer)和常用的游戏循环来实现;-80- 武汉工程大学计算机科学与工程学院综合设计报告2.2.2游戏核心算法设计方案过牌绘图控件动画制作游戏设计思想确定取消出牌OnOkOnCancleOnSendcardOnPass画底牌画已出牌画未出牌化CardReadyDrawOtherCardDrawLeftDrawCardOut发牌动画化出牌动画化OnTimerPrintAll牌在中间界面窗口初始化位图加载化确定鼠标位置化OnCreate等PreCreateWindow等OnMouseMove等图2-4游戏核心算法方案流程图-80- 武汉工程大学计算机科学与工程学院综合设计报告1、54张牌的处理有一种方法是把牌按照黑桃->红桃->梅花->方块的顺序摆放,每种花色都可以采用升序或者降序排列;而另一种方法就是把牌摆放成一个矩阵,而牌的排列顺序由数据结构中的纸牌类Card来决定。下面是Card类函数声明:classCard{public:Card();virtual~Card();intNum;//牌面数目2-10J=11Q=12K=13A=1Jok(小)=14Jok(大)=15大与15表示此牌不存在intPow;//牌的实际大小,比如斗地主中2就比A大//3-10JQKA2Jo小Jo大//1-89101112131415intType;//牌的类型黑桃=0红桃=1梅花=2方块=3boolClick;//被玩家选种的牌将是true,没被选种是false};从Card类函数声明中看出,一张牌的大小、花色是由Num和Type决定(而大小王只需要Num),同时再按照Num和Type对应的数字进行整理,就可以把54张牌集中起来。因为函数中定义的参数不多,而且也比较简单,所以采用按顺序排列的方式进行,而不是用矩阵的方式来排列。2、Managers核心算法#include"Card.h"classManagers{public:boolDoMsg(intnum,intaction);//消息响应voidGameStart();//游戏初始化,发牌。boolMainComputer;//主机,是主机则是true不是则为false;Managers();virtual~Managers();CardPlayCards[3][20];//最多20张牌intPlayerAc;//这台机器上的玩家intPlayerMain;//地主CardOutCards[20];//走的牌,一次也最多出20张牌intOutPlayer;//走牌的玩家CardSendleft[3];//记录剩下的3张牌intGame_State;//-2游戏没开始//-1游戏准备中,选地主//0-2游戏玩家出//3-5对应0-2玩家胜利voidUpdata();//更新intPower;//计算当前游戏如果农民胜利则每人得的分intPlayerMaininfo;//记录有几个玩家选择放弃地主如果都放弃则游戏结束voidSendCard();//发牌voidSortCard(Cardca[]);//给牌排序private:voidCardsInfo(Cardca[],int&num,int&min,int&type);-80- 武汉工程大学计算机科学与工程学院综合设计报告boolCheckCard(intpl);//检查出牌的合法性CardPreOut[20];};DoMsg(intnum,intaction)准备过牌/出牌/单击牌/放弃地主/接受地主退出游戏用户操作点击则改变Click属性Game_state=-1时选地主PlayCards[x][y].Click改变PlayMain,改变谁是地主点牌则改-1TextOut(400,5,st);ReleaseDc(pDc);CView::OnMouseMove(nFlags,point);3.1.2按钮的创建与实现1、按钮的创建利用CButton的初始化函数来创建Button:BOOLCreate(LPCTSTRlpszCaption,DWORDdwStyle,constRECT&rect,CWND*pParentWnd,UNITnId)CBUTTON.Creat(_T("确定"),//按钮的caption属性,按钮的显示WS_CHILD|WS_VISIBLE|BS_PUSHBUTTON,//按钮也是一种窗体,同样有不同//风格,通过对常量或运算进行组合,达到一定的效果,这些常量的含义可以参考MSDNCRect(660,410,765,450),//这个参数指出按钮在视图中左上角和右下角坐标,//在确定了按钮位置的同时也确定了其大小this,//这个指针指向按钮这个窗体的父窗体ID_OK);//这是刚才为按钮定义的常量,按钮的控制IDintCProgramView::OnCreate(LPCREATESTRUCTlpCreateStruct){if(CView::OnCreate(lpCreateStruct)==-1)return-1;//TODO:Addyourspecializedcreationcodehere//创建按钮OKm_ok.Create(_T("确定"),WS_CHILD|WS_VISIBLE|BS_PUSHBUTTON,CRect(660,420,765,460),this,ID_OK);//创建按钮CANCELm_cancel.Create(_T("退出"),WS_CHILD|WS_VISIBLE|BS_PUSHBUTTON,CRect(660,502,765,542),this,ID_CANCEL);//出牌m_sendcard.Create(_T("出牌"),WS_CHILD|WS_VISIBLE|BS_PUSHBUTTON,CRect(532,387,637,427),this,ID_SENDCARD);//过牌m_pass.Create(_T("过牌"),WS_CHILD|WS_VISIBLE|BS_PUSHBUTTON,CRect(533,460,638,500),this,ID_PASS);当输入参数为SW_SHOW表示显示按钮,当为SW_HIDE表示隐藏按钮//按钮的显示控制m_ok.ShowWindow(SW_SHOW);m_cancel.ShowWindow(SW_SHOW);-80- 武汉工程大学计算机科学与工程学院综合设计报告m_sendcard.ShowWindow(SW_SHOW);m_pass.ShowWindow(SW_SHOW);2、按钮的实现添加相关的消息响应函数:把按钮和函数进行关联就实现了确定、取消、发牌、过牌四个不同的动作。下面分析四个按钮具体代码:voidCProgramView::OnOK(){//确定按钮if(manager.Game_State!=-2)return;//判断是否为主机if(!pControl->m_Isseverse){pControl->SendGetReady();//如果不是主机则发送“准备的消息”}else{pControl->m_ready[1]=true;//如果是主机则准备完毕//如果三个玩家都准备完毕后if(pControl->m_ready[0]&&pControl->m_ready[1]&&pControl->m_ready[2]){pControl->m_ready[0]=false;pControl->m_ready[1]=false;pControl->m_ready[2]=false;manager.GameStart();//游戏开始pControl->StartCards();//发牌}}CDC*pDC=GetDC();ReleaseDC(pDC);}////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////voidCProgramView::OnCancel(){//取消按钮Exit(0);//退出程序}////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////voidCProgramView::OnSendCard(){//发牌按钮if(manager.DoMsg(15,4)//如果DoMsg为TRUE,则需要发生改变{PrintAll();//重绘pControl->SendCards(manager.OutCards,4)};//将玩家出牌信息发给其它玩家////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////voidCProgramView::OnPass(){//过牌按钮if(manager.DoMsg(16,3))//如果DoMsg为TRUE,则需发生改变{PrintAll();//重绘pControl->SendCards(NULL,3);//将玩家出的牌发送给其它玩家,此时发送的是空信息LBUTTONDOWN事件响应:-80- 武汉工程大学计算机科学与工程学院综合设计报告if(mx>=100&&my>=440&&mx<=455&&my<=575){CDC*pDC=GetDC();for(i=0;manager.PlayCards[manager.PlayAc][i].Num<=15;i++);//判断玩家手中还有多少牌if(mx<=100+(i-1)*15+71&&my<=576&&mx>=100&&my>=440){i=SelectNum(i,mx,my);//判断点中的是第几张牌if(manager.DoMsg(i,1)//判断点中这张牌后是否需要改变PrintAll();}ReleaseDC(pDC);}3.1.3绘制1.在还没发牌的时候,牌全部集中在中间voidCProgramView::CardReady(){CDC*pDC=GetDC();for(inti=0;i<54;i++)pDC->BitBlt(300+i*2,220,72,97,&Mcard,142,384,SRCCOPY);//截取的是牌的背面ReleaseDC(pDC);}2.画作为底牌的三张牌当在叫地主的时候,牌只显示背面;当确定地主后,作为底牌的三张牌将显示给所有玩家voidCProgramView::DrawLeft(){CDC*pDC=GetDC();inti;if(manager.Game_State==-1)//当还在选地主的时候{for(i=0;i<3;i++)pDC->BitBlt(300+i*40,25,72,97,&Mcard,142,384,SRCCOPY);//画的是牌的背面}elseif(manager.Game_State>=0&&manager.Game_State<=5)//当确定地主后{for(i=0;i<3;i++){if(manager.Sendleft[i].Num<14)pDC->BitBlt(300+i*40,25,71,96,&Mcard,(maneger.Sendleft[i].Num-1)*71,manager.Sendleft[i].Type*96,SRCCOPY);elseif(manager.SendLeft[i].Num<=15)pDC->BitBlt(300+i*40,25,71,96,&mCard,(manager.SendLeft[i].Num-14)*71,384,SRCCOPY);}}ReleaseDC(pDC);}3.画出已出的牌用K来控制画的类型,当K==0表示为左边出牌,K==1时为当前玩家出牌,K==2时为右边出牌,K==3时全部已出的牌都重画。4.画出当前玩家手中还没出的牌-80- 武汉工程大学计算机科学与工程学院综合设计报告程序需要遍历一遍当前玩家手中还没出的牌,当牌被点起后,需要向上突起,用if(manager.PlayCards[manager.PlayerAc][i].Click来实现上面被选中牌的效果。5.画出从当前玩家视角看到的其它玩家手中剩的牌for(i=0;i<20&&cardleft[i].Num<=15;i++){pDC->BitBlt(55,55+i*10,97,75,&Mcard,214,408,SRCCOPY);}for(i=0;i<20&&cardright[i].Num<=15;i++){pDC->BitBlt(630,55+i*10,97,75,&Mcard,214,408,SRCCOPY);}6.在桌面绘出的名字CName::CName(CWnd*pParent/*=NULL*/):CDialog(CName::IDD,pParent){//{{AFX_DATA_INIT(CName)m_name=_T("阳美玲");//}}AFX_DATA_INIT}图3-2在桌面绘出名字3.1.4动画制作在绘制动画的过程中采用了局部重画技术。局部重画就是在背景上截一块和想要覆盖的图像大小一样的背景贴在图上。在每画一张牌的时候把上次画的牌用背景覆盖掉,就形成了一个牌的飞行动画。当所有牌画完后删除定时器。当发牌动画播放完成后,调用PrintAll()进行重绘,交还程序控制权。那么,发牌动画基本制作完成。voidCProgramView::PrintAll(){CDC*pDC=GetDC();pDC->BitBlt(0,0,800,600,&Background,0,0,SRCCOPY);if(manager.Game_State==-2)CardReady();DrawLeft();DrawCardOut(3);DrawMyCard();DrawOtherCard();PrintState();//按钮重绘m_ok.Invalidate(true);m_pass.Invalidate(true);m_cancel.Invalidate(true);m_sendcard.Invalidate(true);ReleaseDC(pDC);}/////////////////////重载PrintAll()实现发牌动画///////////////////////voidCProgramView::PrintAll(inttype)-80- 武汉工程大学计算机科学与工程学院综合设计报告{timer=0;isgoon=false;SetTimer(1,20,NULL);//在程序中设置间隔为20ms、ID为1的定时器。制作这个定时器的目的是为了保证发牌动作的完整,连续,不会在发牌的间隔停留不一样的时间。}////////////////////////////////发牌动画//////////////////////////////voidCProgramView::OnTimer(UINTnIDEvent){CDC*pdc=GetDC();staticinti(1);intj;staticintx,y;//静态变量i用来记录当前牌的步数,设定为10步,即一张牌需要经过10步发到自己的位置。这样做的目的是为了保证所发的牌不会胡乱排放在玩家面前,而使牌按一定的顺序排列。j是一个循环控制变量。x和y用来记录当前牌起飞的左上角的坐标,根据x和y的值可以计算出每一帧牌左上角的坐标。x=300+54*2,y=220;if(timer<18){//画没发出去的牌,飞行途中//在发牌的时候要设定一个timer值。这个值的作用是保证每位玩家的牌不超过17张(在三张底//牌揭开前)。timer值每加1便发一次牌,由于一副扑克牌总共有54张,而底牌有3张,所以//每位玩家在发底牌前牌的张数不能超过17,所以设定timer<18。pdc->BitBlt(300+(53-timer*3)*2,220,100,200,&Background,300+(53-timer*3)*2,220,SRCCOPY);for(j=0;j<54-timer*3;j++)pdc->BitBlt(300+j*2,220,72,97,&Mcard,142,384,SRCCOPY);x-=timer*3*2;//画发出去的牌if(manager.PlayCards[manager.PlayerAc][timer].Num<14){//擦除上次画的牌,用背景覆盖if(i-1>0)pdc->BitBlt(x+(100+timer*15-x)/10*(i-1),y+(480-y)/10*(i-1),71,96,&Background,x+(100+timer*15-x)/10*(i-1),y+(480-y)/10*(i-1),SRCCOPY);//画当前显示的牌pdc->BitBlt(x+(100+timer*15-x)/10*i,y+(480-y)/10*i,71,96,&Mcard,(manager.PlayCards[manager.PlayerAc][timer].Num-1)*71,manager.PlayCards[manager.PlayerAc][timer].Type*96,SRCCOPY);}elseif(manager.PlayCards[manager.PlayerAc][timer].Num<=15)//画大小鬼{if(i-1>0)pdc->BitBlt(x+(100+timer*15-x)/10*(i-1),y+(480-y)/10*(i-1),71,96,&Background,-80- 武汉工程大学计算机科学与工程学院综合设计报告x+(100+timer*15-x)/10*(i-1),y+(480-y)/10*(i-1),SRCCOPY);pdc->BitBlt(x+(100+timer*15-x)/10*i,y+(480-y)/10*i,71,96,&Mcard,(manager.PlayCards[manager.PlayerAc][timer].Num-14)*71,384,SRCCOPY);}if(cardleft[timer].Num<=15){if(i-1>0)pdc->BitBlt(x+(55-x)/10*(i-1),y+(55+timer*10-y)/10*(i-1),97,75,&Background,x+(55-x)/10*(i-1),y+(55+timer*10-y)/10*(i-1),SRCCOPY);pdc->BitBlt(x+(55-x)/10*i,y+(55+timer*10-y)/10*i,97,75,&Mcard,214,408,SRCCOPY);}if(cardright[timer].Num<=15){if(i-1>0)pdc->BitBlt(x+(630-x)/10*(i-1),y+(55+timer*10-y)/10*(i-1),97,75,&Background,x+(630-x)/10*(i-1),y+(55+timer*10-y)/10*(i-1),SRCCOPY);pdc->BitBlt(x+(630-x)/10*i,y+(55+timer*10-y)/10*i,97,75,&Mcard,214,408,SRCCOPY);}i++;if(i==10)//牌已经飞到指定位置{//檫除上一帧画的牌if(manager.PlayCards[manager.PlayerAc][timer].Num<14){pdc->BitBlt(x+(100+timer*15-x)/10*(i-1),y+(480-y)/10*(i-1),71,96,&Background,x+(100+timer*15-x)/10*i,y+(480-y)/10*i,SRCCOPY);}elseif(manager.PlayCards[manager.PlayerAc][timer].Num<=15){pdc->BitBlt(x+(100+timer*15-x)/10*(i-1),y+(480-y)/10*(i-1),71,96,&Background,x+(100+timer*15-x)/10*i,y+(480-y)/10*i,SRCCOPY);}if(cardleft[timer].Num<=15){pdc->BitBlt(x+(55-x)/10*(i-1),y+(55+timer*10-y)/10*(i-1),97,75,&Background,x+(55-x)/10*(i-1),y+(55+timer*10-y)/10*(i-1),SRCCOPY);}if(cardright[timer].Num<=15){pdc->BitBlt(x+(630-x)/10*(i-1),y+(55+timer*10-y)/10*(i-1),97,75,&Background,x+(630-x)/10*(i-1),y+(55+timer*10-y)/10*(i-1),SRCCOPY);}i=0;-80- 武汉工程大学计算机科学与工程学院综合设计报告//重画被背景覆盖的牌if(timer>13){if(manager.PlayCards[manager.PlayerAc][(timer-1)].Num<14){pdc->BitBlt(100+(timer-1)*15,480,71,96,&Mcard,(manager.PlayCards[manager.PlayerAc][(timer-1)].Num-1)*71,manager.PlayCards[manager.PlayerAc][(timer-1)].Type*96,SRCCOPY);}elseif(manager.PlayCards[manager.PlayerAc][(timer-1)].Num<=15){pdc->BitBlt(100+(timer-1)*15,480,71,96,&Mcard,(manager.PlayCards[manager.PlayerAc][(timer-1)].Num-14)*71,384,SRCCOPY);}}//画出飞到的牌if(manager.PlayCards[manager.PlayerAc][timer].Num<14){pdc->BitBlt(100+timer*15,480,71,96,&Mcard,(manager.PlayCards[manager.PlayerAc][timer].Num-1)*71,manager.PlayCards[manager.PlayerAc][timer].Type*96,SRCCOPY);}elseif(manager.PlayCards[manager.PlayerAc][timer].Num<=15){pdc->BitBlt(100+timer*15,480,71,96,&Mcard,(manager.PlayCards[manager.PlayerAc][timer].Num-14)*71,384,SRCCOPY);}if(cardleft[timer].Num<=15){pdc->BitBlt(55,55+timer*10,97,75,&Mcard,214,408,SRCCOPY);pdc->BitBlt(630,55+timer*10,97,75,&Mcard,214,408,SRCCOPY);}timer++;}}else{KillTimer(1);for(j=0;j<3;j++)manager.SortCard(manager.PlayCards[j]);PrintAll();isgoon=true;}-80- 武汉工程大学计算机科学与工程学院综合设计报告ReleaseDC(pdc);}3.2游戏核心算法设计游戏核心算法Managers部分主要包含从游戏开始到游戏结束这一部分,主要有如下一些操作:记录牌的信息发牌游戏开始GameStart()SendCard()CardsInfo(Cardca[],int&num,int&min,int&type)出牌CheckCard(intpl)DoMSG(intnum,intaction)检查出牌的合法性判断牌的行为过牌接受或放弃当地主图3-3简单游戏核心算法流程3.2.1游戏开始首先要解决如何判断游戏开始的问题。用两个参数manager.Game_State=-2或者manager.Game_State=-1,来判断是否有两个玩家加入到主机中。返回的信息是安排加入玩家是几号,并把玩家的名字发送给服务器。然后用m_pView->DrawPlayname()来绘出玩家名字。在得到加入玩家的名字后,客户机向主机发送已准备的消息,用SendGetReady()函数来概括准备信息。voidNetControl::SendGetReady()chartem[20];sprint(tem,”1818%c%c%c”,99,99,manager.PlayerAc);SendMsg(m_pSocket,tem);1、运行服务器初始化游戏假设所有人都已经点击准备按钮,服务器会运行GameStart()来初始化游戏,然后把游戏信息发送到每台客户机。voidManagers::GameStart(){-80-武汉工程大学计算机科学与工程学院综合设计报告intk;for(k=0;k<20;k++)PlayCards[1][k].Click=false;for(k=0;k<3;k++)Sendleft[k].Click=true;if(MainComputer){Power=10;OutCards[0].Num=16;PlayerMaininfo=0;SendCard();PlayerMain=rand()%3;Game_State=-1;}-80- 武汉工程大学计算机科学与工程学院综合设计报告2、发牌游戏初始化后进入发牌阶段,那么如何实现所发的牌是随机的?这里用一个SendCard来实现随机发牌。voidManagers::SendCard(){-80-武汉工程大学计算机科学与工程学院综合设计报告inti,j,k;boolCards[55]={false};//对应54张扑克,其中Cards[54]做初始化用必须为true;//其中0-51为4个1-1352是小王53是大王Cards[54]=true;for(j=0;j<17;j++)for(i=0;i<3;i++){Card&Ca=PlayCards[i][j];k=54;//保证必进入While循环进行随机while(Cards[k])k=rand()%54;Cards[k]=true;Ca.Click=false;if(k==53||k==52){Ca.Num=k-38;Ca.Pow=k-38;Ca.Type=4;Ca.Click=false;}else{Ca.Click=false;Ca.Num=k%13+1;Ca.Type=k/13;if(Ca.Num==1||Ca.Num==2)Ca.Pow=Ca.Num+11;elseCa.Pow=Ca.Num-2;}Sendleft[i].Num=16;PlayCards[0][17].Num=16;PlayCards[1][17].Num=16;PlayCards[2][17].Num=16;}-80-武汉工程大学计算机科学与工程学院综合设计报告从0~53中随机得到一个数,如果这数已经用过则产生新的随机数;如果没有就把这个数对应的牌发给PlayCards[i][j]。用if(k==53||k==52)来判断发的牌是不是王,如果不是则用Ca.Num=k%13+1来判断得到牌的大小,用Ca.Type=k/13来判断得到的牌是什么牌型。发完牌以后将剩下的三张牌存放在Sendleft中,等选出地主后把这三张牌发给地主。3、给牌排序等牌全部发完后,要整理玩家手中的牌序。那么如何来实现理牌这一操作呢?这里用SortCard(PlayCards[i])这函数来实现。voidManagers::SortCard(Cardca[])inti,j;Cardtemp;for(i=0;i<20&&ca[j].Num<=15;i++)for(j=i+1;j<20&&ca[j].Num<=15;j++)if(ca[i].Pow>ca[j].Pow){Temp=ca[i];Ca[i]=ca[j];Ca[j]=temp;3.2.2游戏运行1、判断牌的行为-80- 武汉工程大学计算机科学与工程学院综合设计报告boolManagers::DoMsg(intnum,intaction){//消息响应action含义:1点牌3放弃出牌4出牌(或接受当地主)牌发好了,那么如何来选地主呢?在区分是出牌还是接受地主、放弃地主、或者放弃出牌需要依靠Game_State,当GameStart()运行之后Game_State=-1,表示正在选地主;而在游戏中,Game_State一直保持在0~3之间。选择完地主后把原来剩下的3张牌发给地主,然后Game_State变成相应的数字让地主出牌。-80-武汉工程大学计算机科学与工程学院综合设计报告if(action==1)//唯一用得到前面1个参数的地方{Card&Ca=PlayCards[PlayerAc][num];if(Ca.Click)Ca.Click=false;elseCa.Click=true;returntrue;}if(Game_State==-1&&PlayerMain==PlayerAc){if(action==4){PlayCards[PlayerAc][17]=Sendleft[0];PlayCards[PlayerAc][18]=Sendleft[1];PlayCards[PlayerAc][19]=Sendleft[2];SortCard(PlayCards[PlayerAc]);Game_State=PlayerAc;OutPlayer=PlayerAc;//改变returntrue;}if(action==3){PlayerMain=(PlayerMain+1)%3;PlayerMaininfo++;if(PlayerMaininfo==3)Game_State=-2;returntrue;}}if(Game_State!=PlayerAc)returnfalse;elseif(action==4){if(CheckCard(Game_State)){//能出牌当然出牌inti,j;for(i=0;i<20&&PreOut[i].Num<=15;i++)OutCards[i]=PreOut[i];if(i!=20)OutCards[i].Num=16;j=0;Card*Ca=PlayCards[Game_State];for(i=0;i<20&&Ca[i].Num<=15;i++)if(!Ca[i].Click){Ca[j]=Ca[i];j++;}OutPlayer=Game_State;Ca[j].Num=16;Updata();returntrue;}elsereturnfalse;}elseif(action==3&&OutPlayer!=PlayerAc){Game_State=(Game_State+1)%3;//直接更改游戏玩家returntrue;}returnfalse;}-80-武汉工程大学计算机科学与工程学院综合设计报告2、出牌规则-80-武汉工程大学计算机科学与工程学院综合设计报告把ca中的牌信息反应出来,ca[]需要反应的牌信息num表示有多少张牌,min表示起作用的牌中值最小的一个的大小例如3个5带一个8,那么起作用的就是5min=5,num=3,type表示类型1:3带1、22:4带2(4带2、两对)3:连子4:全相同5:双鬼炸弹6:飞机7:三顺0:错牌!不能走出去的牌发好了如何来比较是否能出牌呢?用函数CardsInfo来判断。-80- 武汉工程大学计算机科学与工程学院综合设计报告voidManagers::CardsInfo(Cardca[],int&num,int&min,int&type){inti,k,n;intsame[10]={0};intnsame[10]={0};for(n=0;n<20&&ca[n].Num<=15;n++);type=0;num=n;if(n>=5){for(k=0;ki)//三顺for(tem=0;tem<=i;tem++)//飞机if(i<2)//3带n或4带nsame用来记录相同牌的pow;nsame用来记录相同牌的数量;i记录有多少种大小不同的牌;n记录牌的数量。将n分为n>=5、5>n>2、n<=2三种情况。用判断牌是否相连来判断所出的是否为连牌。当牌的数量大于5时,所出的牌可能是连牌、3带n、4带n、三顺或者飞机。三顺的判断类似连牌,但多了个所有的牌必须有且仅有两张。不同的牌超过两种的另一种情况是飞机。在程序中定义了intty1=0,ty2=0,num3=0.ty1记录了单张牌有多少张;ty2记录如果带的是对子则带了多少个对子;num3记录了有多少个三张牌。用CheckCard来计算是否可以出牌。p1选中的牌(Click=1)存放在PreOut中,然后和上次所出的牌OutCards进行比较,看能否出牌。num1、min1、type1用于记录OutCards的信息,mun2、min2、type2用于记录PreOut的信息。3、出完牌后的理牌boolManagers::CheckCard(intpl){Card*Ca=PlayCards[pl];//用Ca指针来代替Player[pl],使程序简单容易理解//CardPlayCards[3][20]记录的是3个玩家的牌,会不断地更新。CardOutCards[20]记录的是//已经出掉的牌,一次最多出20张牌。IntOutPlayer表示走牌的玩家的号数,服务器是0号,//后面加入的依次是1号,2号玩家。inti,j;intnum1,min1,type1;intnum2,min2,type2;j=0;for(i=0;i<20&&Ca[i].Num<=15;i++)if(Ca[i].Click){PreOut[j]=Ca[i];j++;}if(j==0)returnfalse;elseif(j!=20){PreOut[j].Num=16;//表示此后的都没有牌了}Ca=PreOut;//现在把CA指到这里CardsInfo(Ca,num2,min2,type2);if(OutCards[0].Num==16)//上次没有人走牌{-80- 武汉工程大学计算机科学与工程学院综合设计报告if((type2==4&&num2==4)||type2==5)Power*=2;if(type2!=0)returntrue;}if(OutPlayer==PlayerAc)//上次走牌的人OutPlayer就是自己,那么自己可以随便走什么{//改变if((type2==4&&num2==4)||type2==5)Power*=2;if(type2!=0)returntrue;}3.3网络编程设计3.3.1加载套接字库CMainFrame::CMainFrame(){//TODO:addmemberinitializationcodehereWORDwVersionRequested;WSADATAwsaData;interr;wVersionRequested=MAKEWORD(2,2);err=WSAStartup(wVersionRequested,&wsaData);if(err!=0){MessageBox("网络有故障,请检查网络情况!");return;}}3.3.2设置监听套接字NetControl::NetControl(){m_pSocket=NULL;m_Server="";m_Port=100;m_pListening=NULL;m_pList.RemoveAll();}voidNetControl::OnSet()-80- 武汉工程大学计算机科学与工程学院综合设计报告{m_pListening=newCNet(this);if(m_pListening->Create(m_Port)){if(!m_pListening->Listen()){MessageBox(GetActiveWindow(),"端口设置错误!","网络信息",MB_OK);}}else{MessageBox(GetActiveWindow(),"服务器设置成功,请等待玩家加入!","网络信息",MB_OK);}}3.3.3客户机和服务器的创建在网络部分,主机和客户机的区别是参数boolm_Isserver,参数boolm_ready[3]用来记录3个玩家是否准备就绪。Boolm_ready[3]这个参数中有在服务器上才有存在的意义,因为只有服务器才能开始游戏。服务器的玩家是0号,依次加入的分别为1号和2号。1、客户机设置过程CGetin::CGetin(CWnd*pParent/*=NULL*/):CDialog(CGetin::IDD,pParent){//{{AFX_DATA_INIT(CGetin)m_ip=_T("127.0.0.1");m_Port=_T("100");//}}AFX_DATA_INIT}1、客户机设置过程2、服务器设置和连接voidCGetin::OnOK(){CMainFrame*m_pMF=(CMainFrame*)AfxGetApp()->m_pMainWnd;UINTk;k=atoi(m_Port);if(k<1||k>60000){MessageBox("输入端口无效,采用默认端口","错误");m_Port="100";-80- 武汉工程大学计算机科学与工程学院综合设计报告}CDialog::OnOK();}CNet*NetControl::ConnectServer(){CNet*pSocket=newCNet(this);if(!(pSocket->Create())){deletepSocket;MessageBox(GetActiveWindow(),"创建Socket失败","警告信息",MB_OK);returnNULL;}//连接到服务器if(!pSocket->Connect(m_Server,m_Port)){deletepSocket;MessageBox(GetActiveWindow(),"请求连接到服务器失败","警告信息",MB_OK);returnNULL;}returnpSocket;}3.3.4数据传输1、数据传输的方法连网打牌需要传递牌、游戏状态等信息,所以需要把牌的信息和游戏状态压缩到一个字符串中,同时需要把一个字符串中的信息解码回到原来的状态供游戏使用。那么每张牌都有哪些信息呢?每张牌的信息包含Num、Pow、Type、Click。Click状态不用传输;Num和Pow只需要传输其中的一个;而Type是必须要传递的内容。具体方法如下:cha=(card.Pow+card.Type*20)2、数据的接收与发送voidCNet::OnAccept(intnErrorCode){CNet*pSocket=newCNet(m_Nc);if(m_Nc->m_pList.GetCount()<=1){//接收客户端发送的连接请求函数if(m_Nc->m_pListening->Accept(*pSocket)){if(m_Nc->m_pList.IsEmpty())m_Nc->m_pList.AddHead(pSocket);elsem_Nc->m_pList.AddTail(pSocket);}elsedeletepSocket;}elsedeletepSocket;CSocket::OnAccept(nErrorCode);}voidCNet::OnReceive(intnErrorCode){//从一个已连接的套接字接收数据函数m_Nc->FetchMsg(this);CSocket::OnReceive(nErrorCode);}-80- 武汉工程大学计算机科学与工程学院综合设计报告第四章设计结果及分析4.1游戏界面设计结果与分析一,程序运行情况:(1)程序正常的响应voidCProgramView::OnDraw(CDC*pDC)函数,实现了在相应位置显示我们自己创建的桌面位图、54张牌的位图及四个按钮;(2)在发牌和打牌的过程中也出现了也达到了预期的动画效果;(3)出过的牌也按其顺序排在相应的位置;二,分析(1)这一部分网上都有怎样实现的代码与过程,所以没有什么错误;(2)在界面设计的过程中,需要注意的是:按钮的添加与平常的按钮的添加不一样,平常按钮的添加是直接用控件拖拽完成的,但这里按钮相当于一个对话框,添加它时,是创建窗口的方法实现的;(3)这个程序的不足之处就是没有像网上的欢乐斗地主那样可以记分、可以托管等;(4)在发牌前把牌全部集中在中间是为了让界面更加清晰,以免的发牌的时候因为玩家面前有牌,又有未发完的牌而产生发牌动作的不连续。(5)在发牌结束后将未发的牌存放在Sendleft中以便于在选地主结束后能把剩下的三张牌直接发给地主。(6)画玩家手中未出的牌要遍历所有手中未出的牌然后排序,是为了保持玩家手中牌排序的美观。(7)遍历和每隔一段时间更新数据在实际的编程中也经常使用,比如进程守护中的两个程序,要不停的遍历进程运行表来获得对方程序的运行状态。(8)游戏的主界面会因为电脑原因而重新开始的时候有牌面重叠等现象,可能是因为程序的算法不够经典,不能很好的节省内存。4.2游戏核心算法设计结果与分析一,程序运行情况(1)通过调试后基本的操作都可以实现出来,像开始游戏后,发牌,出牌都可以实现等,唯一的缺点就是出牌没有时间限制;(2)出牌的大小顺序也能正常运行,像斗地主的规则等基本的都可以实现了;(3)在游戏结束后,能够更新数据库,重新新的游戏;二,分析(1)游戏无法实现记录比分、系统提示出牌、限制每位玩家的出牌时间等功能。在游戏功能上有所欠缺,这些都是因为自己没有掌握那么多的知识;(2)在对话框中可以通过向按钮添加响应函数实现链接,这种方法证明是可行的(3)这一个模块是斗地主游戏中的核心部分,也是最难的一部分,但是由于自己能力有限,大部分只能是粘贴网上代码,因为虽然我能看懂那些代码,但是我自己却写不出来,所以这也造成了有很多功能实现不了啊;-80- 武汉工程大学计算机科学与工程学院综合设计报告4.3网络连接设计结果与分析一,程序运行情况:(1)程序正常的响应响应CGetin::CGetin(CWnd*pParent)函数,实现了在相应位置显示我们自己规定的m_ip=_T("127.0.0.1");m_Port=_T("100")IP地址和端口号;(2)点击运行程序,程序能正常运行,并能按要求连网实现游戏,实现斗地主游戏;(3)服务器及客户机设置和连接过程也能实现,致使该程序必须是两个及两个以上人才能玩,不能进行单人游戏;二,分析(1)虽然CSocket解决了结束阻塞线程的方法,调用CancelBlockingCall,但是它并不适合多线程模式;(2)CSocket和CAsyncSocket利用Windows的消息模式将前台的界面处理和后台的网络通信都整合到消息传递模型但是,一旦后台的网络过于繁忙,则前台的处理可能就无法顾及。(3)连网打牌的时候需要每个玩家输入端口号、IP地址、无法像QQ斗地主游戏一样点击进入而自动进入游戏。-80- 武汉工程大学计算机科学与工程学院综合设计报告总结最初开始这个程序的时候我觉得无从下手,完全像不明白该怎样去做。后来,仔细阅读课程设计的要求与目的提示并认真阅读课本上的相关知识,再上网查了些相关资料,终于渐渐的找到了各个问题解决的方法,并通过数次调试完成了程序的设计过程。通过程序的设计过程我感触颇深,我想也许没有什么事情是真正的困难的,只要我们静下来认真思考,不放弃,我们总会成功。课程设计是培养学生综合运用所学知识,发现,提出,分析和解决实际问题,锻炼实践能力的重要环节,是对学生实际工作能力的具体训练和考察过程.随着科学技术发展的日新日异,软件开发已经成为当今计算机应用中空前活跃的领域,在生活中可以说得是无处不在。因此作为二十一世纪的大学来说掌握软件的开发技术是十分重要的。回顾起此次智能斗地主的课程设计,至今我仍感慨颇多,的确,从选题到定稿,从理论到实践,在整整两星期的日子里,可以说得是苦多于甜,但是可以学到很多很多的的东西,同时我不仅巩固了以前所学过的知识,而且学到了很多在书本上所没有学到过的知识。通过这次课程设计使我懂得了理论与实际相结合是很重要的,只有理论知识是远远不够的,只有把所学的理论知识与实践相结合起来,从理论中得出结论,才能真正为社会服务,从而提高自己的实际动手能力和独立思考的能力。在设计的过程中,我遇到过各种各样的问题,同时在设计的过程中发现了自己的不足之处,对以前所学过的知识理解得不够深刻,掌握得不够牢固,在程序的编写中也表现出很多不足的地方,比如没有记分功能,不能像QQ斗地主一样对每个玩家的出牌时间做限制,界面制作也不够美观,在接下来的学习,编程中要慢慢的努力,去完成更好的程序。但是通过这次课程设计之后,我不仅把以前所学过的知识重新温故了一遍,而且还学到了很多以前都不知道的东西,比如说,网络编程这一块,我们以前都没有学过,但是通过这次设计后,我也学会了如何去进行网络游戏的连接,并且也学会了如何去好好利用网上的资源等。在做的过程中,有很多问题都是书本上不能解决的,这时,我们不能就此而止,而是要有一种勇往直前的精神,不懂的就问,不能怕这个怕那个的,可以问老师,也可以利用网络资源解决自己遇到的困难,其实编程的过程是体现个人遇到问题时如何去面对的过程,也是反映一个人对待问题的态度的过程。通过这次课程设计使我对VC++有了更深的了解,在多次反复的实践过程中我对它有了更深的兴趣,这不仅仅是一次考试,同时又是对我的一种考验,体会如何真正地去做好一件事。总之,这次课程设计使我的编程能力得到了极大的提高,也使我在处理问题的态度方面得到了极大的转变,进而使我的人生得到了进一步的升华。这次课程设计终于顺利完成了,在设计中遇到了很多编程问题,但最后在刘老师和蔡老师的辛勤指导下,终于游逆而解。同时,在刘老师和蔡老师的身上我学得到很多实用的知识,在这里我再次表示感谢!-80- 武汉工程大学计算机科学与工程学院综合设计报告致谢在这里特别感谢刘老师和蔡老师在课堂上的讲解和引导,使我对VC++语言有强烈的兴趣,从而促使我更进一步的学习VC++语言,并将知识应用于实际问题的解决中,比如,网络连接这一块,我学会了如何加载套接字库、创建用于监听套接字、绑定套接字、发送数据、接收数据、关闭套接字,如何让三个人进入到一个游戏软件里等等,同时,我也对给过我帮助的所有同学和各位指导老师再次表示忠心的感谢!-80- 武汉工程大学计算机科学与工程学院综合设计报告参考文献[1]斗地主简介.http://baike.baidu.com/view/5574.htm?fr=ala0_1[2]VisualC++介绍.http://baike.baidu.com/view/100377.htm[3]CSocket简介.http://jiaozhenjiesong.blog.163.com/blog/static[4]JohnE.Swanke.VisualC++MFC编程实例.机械工业出版社.2008年6月[5]侯俊杰.深入浅出MFC【M】.北京:华中科技大学出版社.2007.[6]孙鑫.VC++深入详解【M】.北京:电子工业出版社,2006.[7]葛垚.VisualC++MFC棋牌类游戏编程实例【M】.北京:人民邮电出版社.2008年7月.[8]黄晓蕾.单机游戏如何重振旗鼓.民营经济报.2007年8月[9]萧道曦.单机游戏的前程与“钱程”.中国文化报.2004年6月[10]刘洪星,谢玉山.Eclipse开发平台及其应用[J].武汉理工大学学报.2005年4月[11]钱乐秋等.软件工程.清华大学出版社.2007年3月-80- 武汉工程大学计算机科学与工程学院综合设计报告附录程序的主要代码//Card.h:interfacefortheCardclass.//////////////////////////////////////////////////////////////////////classCard{public:Card();virtual~Card();intNum;//牌面数目2-10J=11Q=12K=13A=1Jok(小)=14Jok(大)=15大与15表示此牌不存在intPow;//牌的实际大小,比如斗地主中2就比A大//3-10JQKA2Jo小Jo大//1-89101112131415intType;//牌的类型黑桃=0红桃=1梅花=2方块=3boolClick;//被玩家选种的牌将是true,没被选种是false};//Getin.cpp:implementationfileCGetin::CGetin(CWnd*pParent/*=NULL*/):CDialog(CGetin::IDD,pParent){//{{AFX_DATA_INIT(CGetin)m_ip=_T("127.0.0.1");m_Port=_T("100");//}}AFX_DATA_INIT}voidCGetin::OnOK(){CMainFrame*m_pMF=(CMainFrame*)AfxGetApp()->m_pMainWnd;UINTk;k=atoi(m_Port);if(k<1||k>60000){MessageBox("输入端口无效,采用默认端口","错误");m_Port="100";}CDialog::OnOK();}//MainFrm.cpp:implementationoftheCMainFrameclassCMainFrame::CMainFrame()-80- 武汉工程大学计算机科学与工程学院综合设计报告{//TODO:addmemberinitializationcodehereWORDwVersionRequested;WSADATAwsaData;interr;wVersionRequested=MAKEWORD(2,2);err=WSAStartup(wVersionRequested,&wsaData);if(err!=0){MessageBox("网络有故障,请检查网络情况!");return;}}BOOLCMainFrame::PreCreateWindow(CREATESTRUCT&cs){//theCREATESTRUCTcscs.style=WS_CAPTION|FWS_ADDTOTITLE|WS_SYSMENU|WS_MINIMIZEBOX;cs.hMenu=0;cs.x=100;cs.y=50;cs.cx=810;cs.cy=620;returnTRUE;}voidManagers::GameStart(){intk;for(k=0;k<20;k++)PlayCards[1][k].Click=false;for(k=0;k<3;k++)Sendleft[k].Click=true;if(MainComputer){Power=10;OutCards[0].Num=16;PlayerMaininfo=0;SendCard();PlayerMain=rand()%3;Game_State=-1;}else{//GetCard();-80- 武汉工程大学计算机科学与工程学院综合设计报告}}boolManagers::CheckCard(intpl){Card*Ca=PlayCards[pl];//用Ca指针来代替Player[pl],使程序简单容易理解inti,j;intnum1,min1,type1;intnum2,min2,type2;j=0;for(i=0;i<20&&Ca[i].Num<=15;i++)if(Ca[i].Click){PreOut[j]=Ca[i];j++;}if(j==0)returnfalse;elseif(j!=20){PreOut[j].Num=16;//表示此后的都没有牌了}Ca=PreOut;//现在把CA指到这里CardsInfo(Ca,num2,min2,type2);if(OutCards[0].Num==16)//上次没有人走牌{if((type2==4&&num2==4)||type2==5)Power*=2;if(type2!=0)returntrue;}if(OutPlayer==PlayerAc)//上次走牌的人OutPlayer就是自己,那么自己可以随便走什么{//改变if((type2==4&&num2==4)||type2==5)Power*=2;if(type2!=0)returntrue;}if(type2==0)returnfalse;CardsInfo(OutCards,num1,min1,type1);if(type1==5)//双鬼returnfalse;if(type2==5){Power*=2;-80- 武汉工程大学计算机科学与工程学院综合设计报告returntrue;}if(type1==4&&type2==4){if(num2==num1){if(min1=5){for(k=0;k2)break;same[i]=ca[k].Pow;nsame[i]++;}if(i>=2){inttem;for(tem=0;temi)//三顺{type=7;min=same[0];}intty1=0,ty2=0,num3=0;intkmin=0;for(tem=0;tem<=i;tem++)//飞机if(nsame[tem]==1){ty1++;}elseif(nsame[tem]==2){ty2++;}elseif(nsame[tem]==3&&kmin==0){kmin=same[tem];for(;temi){if((num3==ty1||num3==ty2||ty1==ty2)&&num3!=0){type=6;min=kmin;}}}if(i<2)//3带n或4带n{intmaxnum=-1;for(k=0;k<=2;k++)if(nsame[k]>maxnum){maxnum=nsame[k];i=k;}if(maxnum==3&&n==5){type=1;min=same[i];return;-80- 武汉工程大学计算机科学与工程学院综合设计报告}elseif(maxnum==4){type=2;min=same[i];return;}}}elseif(n>2){i=-1;for(k=0;k2)break;same[i]=ca[k].Pow;nsame[i]++;}if(i<=2){intmaxnum=-1;for(k=0;k<=2;k++)if(nsame[k]>maxnum){maxnum=nsame[k];i=k;}if(maxnum==3&&n==4){type=1;min=same[i];return;}elseif(maxnum==3&&n==3){type=4;min=same[i];return;}elseif(maxnum==4&&n==4){type=4;min=same[i];return;}-80- 武汉工程大学计算机科学与工程学院综合设计报告}}elseif(n==2){if(ca[0].Pow==ca[1].Pow){type=4;min=ca[0].Pow;}elseif(ca[0].Pow==14&&ca[1].Pow==15){type=5;min=ca[1].Pow;}}elseif(n==1){min=ca[0].Pow;type=4;}}voidManagers::SortCard(Cardca[]){inti,j;Cardtemp;for(i=0;i<20&&ca[i].Num<=15;i++)for(j=i+1;j<20&&ca[j].Num<=15;j++)if(ca[i].Pow>ca[j].Pow){temp=ca[i];ca[i]=ca[j];ca[j]=temp;}}//Managers.cpp:implementationoftheManagersclass.Managers::Managers(){Game_State=-2;}-80- 武汉工程大学计算机科学与工程学院综合设计报告Managers::~Managers(){}voidManagers::GameStart(){intk;for(k=0;k<20;k++)PlayCards[1][k].Click=false;for(k=0;k<3;k++)Sendleft[k].Click=true;if(MainComputer){Power=10;OutCards[0].Num=16;PlayerMaininfo=0;SendCard();PlayerMain=rand()%3;Game_State=-1;}else{//GetCard();}}boolManagers::CheckCard(intpl){Card*Ca=PlayCards[pl];//用Ca指针来代替Player[pl],使程序简单容易理解inti,j;intnum1,min1,type1;intnum2,min2,type2;j=0;for(i=0;i<20&&Ca[i].Num<=15;i++)if(Ca[i].Click){PreOut[j]=Ca[i];j++;}if(j==0)returnfalse;elseif(j!=20){PreOut[j].Num=16;//表示此后的都没有牌了}Ca=PreOut;//现在把CA指到这里-80- 武汉工程大学计算机科学与工程学院综合设计报告CardsInfo(Ca,num2,min2,type2);if(OutCards[0].Num==16)//上次没有人走牌{if((type2==4&&num2==4)||type2==5)Power*=2;if(type2!=0)returntrue;}if(OutPlayer==PlayerAc)//上次走牌的人OutPlayer就是自己,那么自己可以随便走什么{//改变if((type2==4&&num2==4)||type2==5)Power*=2;if(type2!=0)returntrue;}if(type2==0)returnfalse;CardsInfo(OutCards,num1,min1,type1);if(type1==5)//双鬼returnfalse;if(type2==5){Power*=2;returntrue;}if(type1==4&&type2==4){if(num2==num1){if(min1=5){for(k=0;k2)break;same[i]=ca[k].Pow;nsame[i]++;}if(i>=2){inttem;for(tem=0;temi)//三顺{type=7;min=same[0];}-80- 武汉工程大学计算机科学与工程学院综合设计报告intty1=0,ty2=0,num3=0;intkmin=0;for(tem=0;tem<=i;tem++)//飞机if(nsame[tem]==1){ty1++;}elseif(nsame[tem]==2){ty2++;}elseif(nsame[tem]==3&&kmin==0){kmin=same[tem];for(;temi){if((num3==ty1||num3==ty2||ty1==ty2)&&num3!=0){type=6;min=kmin;}}}if(i<2)//3带n或4带n{intmaxnum=-1;for(k=0;k<=2;k++)if(nsame[k]>maxnum){maxnum=nsame[k];i=k;}if(maxnum==3&&n==5){type=1;min=same[i];return;}elseif(maxnum==4){type=2;min=same[i];return;-80- 武汉工程大学计算机科学与工程学院综合设计报告}}}elseif(n>2){i=-1;for(k=0;k2)break;same[i]=ca[k].Pow;nsame[i]++;}if(i<=2){intmaxnum=-1;for(k=0;k<=2;k++)if(nsame[k]>maxnum){maxnum=nsame[k];i=k;}if(maxnum==3&&n==4){type=1;min=same[i];return;}elseif(maxnum==3&&n==3){type=4;min=same[i];return;}elseif(maxnum==4&&n==4){type=4;min=same[i];return;}}}elseif(n==2){if(ca[0].Pow==ca[1].Pow){-80- 武汉工程大学计算机科学与工程学院综合设计报告type=4;min=ca[0].Pow;}elseif(ca[0].Pow==14&&ca[1].Pow==15){type=5;min=ca[1].Pow;}}elseif(n==1){min=ca[0].Pow;type=4;}}voidManagers::SortCard(Cardca[]){inti,j;Cardtemp;for(i=0;i<20&&ca[i].Num<=15;i++)for(j=i+1;j<20&&ca[j].Num<=15;j++)if(ca[i].Pow>ca[j].Pow){temp=ca[i];ca[i]=ca[j];ca[j]=temp;}}//Managers.h:interfacefortheManagersclass.#include"Card.h"classManagers{public:boolDoMsg(intnum,intaction);voidGameStart();//游戏初始化,发牌。boolMainComputer;//主机,是主机则是true不是则为false;Managers();virtual~Managers();CardPlayCards[3][20];//最多20张牌intPlayerAc;//这台机器上的玩家intPlayerMain;//地主-80- 武汉工程大学计算机科学与工程学院综合设计报告CardOutCards[20];//走的牌,一次也最多出20张牌intOutPlayer;//走牌的玩家CardSendleft[3];//记录剩下的3张牌intGame_State;voidUpdata();//-2游戏没开始//-1游戏准备中,选地主//0-2游戏玩家出牌//3-5对应0-2玩家胜利intPower;//计算当前游戏如果农民胜利则每人得的分intPlayerMaininfo;//记录有几个玩家选择放弃地主如果都放弃则游戏结束voidSendCard();//发牌voidSortCard(Cardca[]);private://voidSortCard(Cardca[]);voidCardsInfo(Cardca[],int&num,int&min,int&type);//voidSendCard();//发牌boolCheckCard(intpl);CardPreOut[20];};voidCNet::OnAccept(intnErrorCode){CNet*pSocket=newCNet(m_Nc);if(m_Nc->m_pList.GetCount()<=1){if(m_Nc->m_pListening->Accept(*pSocket)){if(m_Nc->m_pList.IsEmpty())m_Nc->m_pList.AddHead(pSocket);elsem_Nc->m_pList.AddTail(pSocket);}elsedeletepSocket;}elsedeletepSocket;CSocket::OnAccept(nErrorCode);}voidCNet::OnReceive(intnErrorCode){m_Nc->FetchMsg(this);-80- 武汉工程大学计算机科学与工程学院综合设计报告CSocket::OnReceive(nErrorCode);}//Net.cpp:implementationfile/////////////////////////////////////////////////////////////////////////////voidCNet::OnAccept(intnErrorCode){CNet*pSocket=newCNet(m_Nc);if(m_Nc->m_pList.GetCount()<=1){if(m_Nc->m_pListening->Accept(*pSocket)){if(m_Nc->m_pList.IsEmpty())m_Nc->m_pList.AddHead(pSocket);elsem_Nc->m_pList.AddTail(pSocket);}elsedeletepSocket;}elsedeletepSocket;CSocket::OnAccept(nErrorCode);}voidCNet::OnReceive(intnErrorCode){m_Nc->FetchMsg(this);CSocket::OnReceive(nErrorCode);}//NetControl.cpp:implementationoftheNetControlclass.//Construction/Destruction//////////////////////////////////////////////////////////////////////NetControl::NetControl(){m_pSocket=NULL;m_Server="";m_Port=100;-80- 武汉工程大学计算机科学与工程学院综合设计报告m_pListening=NULL;m_pList.RemoveAll();}NetControl::~NetControl(){if(m_pSocket)deletem_pSocket;deletem_pListening;}voidNetControl::FetchMsg(CNet*pRequest){CStringpMsg;//用CString代替Char*方便charMsg[10000],tempMsg[1000];intByteCount;intEnd=0;CStringArray*temp=newCStringArray;strcpy(Msg,"");do{strcpy(tempMsg,"");ByteCount=pRequest->Receive(tempMsg,1000);if(ByteCount>1000||ByteCount<=0){MessageBox(GetActiveWindow(),"接受网络信息发生错误","警告信息",MB_OK);return;}elseif(ByteCount<1000&&ByteCount>0){End=1;}tempMsg[ByteCount]=0;strcat(Msg,tempMsg);}while(End==0);//MessageBox(GetActiveWindow(),Msg,"网络信息",MB_OK);if(!strcmp("退出游戏",Msg)){//if(m_pList.GetHead()MessageBox(GetActiveWindow(),"有人退出了","警告信息",MB_OK);if(m_Isserver)Broadcast(Msg);exit(0);}if(!m_Isserver){-80- 武汉工程大学计算机科学与工程学院综合设计报告if(!strcmp(Msg,sMsg))return;}pMsg=Msg;//接受信息if(m_Isserver)//服务器的处理{if(!strncmp(pMsg,"1818",4)){if(manager.Game_State<0||manager.Game_State>2)//改变{if(pMsg[4]==1)//如果是服务器,接收到的信息第4个是1则表示次信息用来获得服务器信息,返回服务器信息{if(pRequest==(CNet*)m_pList.GetHead()){chartem[100]="1811";strcpy(tem+4,m_pView->PlayerName[1]);m_pView->PlayerName[2]=pMsg.Right(pMsg.GetLength()-5);SendMsg(pRequest,tem);//+主机姓名m_pView->DrawPlayername();}elseif(pRequest==(CNet*)m_pList.GetTail()){chartem[100]="1812";strcpy(tem+4,m_pView->PlayerName[1]);m_pView->PlayerName[0]=pMsg.Right(pMsg.GetLength()-5);SendMsg(pRequest,tem);//+主机姓名m_pView->DrawPlayername();}if(m_pList.GetCount()==2)//如果2个玩家都到了就广播所有玩家的名字{charp[200];sprintf(p,"1818%c%s%c%s",1,m_pView->PlayerName[2],1,m_pView->PlayerName[0]);//把名字按照这样的顺序写进P("1818%c%s%c%s",1,name1,1,name2)Broadcast(p);}return;}//服务器接收到的是游戏准备开始的信息-80- 武汉工程大学计算机科学与工程学院综合设计报告elseif(pMsg[4]==99&&pMsg[5]==99){//计数当3个都按下开始了就游戏开始if(pMsg[6]==1)m_ready[2]=true;elseif(pMsg[6]==2)m_ready[0]=true;if(m_ready[0]&&m_ready[1]&&m_ready[2]){m_ready[0]=false;m_ready[1]=false;m_ready[2]=false;manager.GameStart();StartCards();m_pView->PlayerPos();m_pView->PrintAll(1);}}elseif(pMsg[5]>100&&pMsg[5]<106&&manager.Game_State==-1)//服务器接收到的是选择地主信息{Broadcast(Msg);intaction=pMsg[5]-100;if(action==4){manager.PlayCards[manager.PlayerMain][17]=manager.Sendleft[0];manager.PlayCards[manager.PlayerMain][18]=manager.Sendleft[1];manager.PlayCards[manager.PlayerMain][19]=manager.Sendleft[2];manager.Game_State=manager.PlayerMain;m_pView->PrintAll();return;}elseif(action==3){manager.PlayerMain=(manager.PlayerMain+1)%3;manager.PlayerMaininfo++;if(manager.PlayerMaininfo==3)manager.Game_State=-2;return;}}}if(manager.Game_State>=0||manager.Game_State<3)//接收游戏中的数据-80- 武汉工程大学计算机科学与工程学院综合设计报告{//改变inttemp=manager.Game_State;temp=(temp+1)%3;if(pMsg[5]==104)//action==4;{intk;DeMakeCard(Msg,manager.OutCards,6,pMsg.GetLength());manager.OutPlayer=manager.Game_State;for(k=0;k<20&&manager.OutCards[k].Num<=15;k++)m_pView->OutCards[temp][k]=manager.OutCards[k];if(k!=20)m_pView->OutCards[temp][k].Num=16;//manager.Updata();m_pView->DrawCardOut(temp);}elseif(pMsg[5]==103){m_pView->OutCards[temp][0].Num=16;manager.Game_State=(manager.Game_State+1)%3;}if(manager.Game_State!=pMsg[4]-100){manager.Game_State=pMsg[4]-100;}Broadcast(Msg);}if(manager.Game_State>=3){//某猪胜利if(manager.Game_State-3==manager.PlayerMain)MessageBox(GetActiveWindow(),"地主胜利","游戏结束",0);//改变elseMessageBox(GetActiveWindow(),"农民胜利","游戏结束",0);//改变manager.Game_State=-2;}}}else//非服务器的处理{if(!strncmp(pMsg,"1811",4)){//获得主机姓名传给Player0-80- 武汉工程大学计算机科学与工程学院综合设计报告manager.PlayerAc=1;m_pView->PlayerName[0]=pMsg.Right(pMsg.GetLength()-4);m_pView->DrawPlayername();return;}elseif(!strncmp(pMsg,"1812",4)){//获得主机姓名传给Player0manager.PlayerAc=2;m_pView->PlayerName[2]=pMsg.Right(pMsg.GetLength()-4);m_pView->DrawPlayername();return;}if(manager.Game_State==-1||manager.Game_State==-2){if(strncmp(pMsg,"1818",4))return;if(pMsg[4]==1)//获得FWQ上的信息{intk;//获得第2个分隔符的位置for(k=5;pMsg[k]!=1;k++);//如果这台机器的玩家是1号if(manager.PlayerAc==1){m_pView->PlayerName[2]=pMsg.Mid(k+1);m_pView->DrawPlayername();}//如果这台机器的玩家是2号elseif(manager.PlayerAc==2){m_pView->PlayerName[0]=pMsg.Mid(5,k-5);m_pView->DrawPlayername();}return;}if(pMsg[4]==99&&pMsg[5]==1)//收到发牌信息{DeMakeCard(pMsg,manager.PlayCards[0],6,23);DeMakeCard(pMsg,manager.PlayCards[1],23,40);DeMakeCard(pMsg,manager.PlayCards[2],40,57);DeMakeCard(pMsg,manager.Sendleft,57,60);manager.PlayerMain=Msg[60]-100;m_pView->PlayerPos();-80- 武汉工程大学计算机科学与工程学院综合设计报告m_pView->PrintAll(1);manager.Game_State=-1;return;}if(pMsg[5]>100&&pMsg[5]<106)//收到选地主信息{intaction=pMsg[5]-100;if(action==4){manager.PlayCards[manager.PlayerMain][17]=manager.Sendleft[0];manager.PlayCards[manager.PlayerMain][18]=manager.Sendleft[1];manager.PlayCards[manager.PlayerMain][19]=manager.Sendleft[2];manager.Game_State=manager.PlayerMain;m_pView->PrintAll();MessageBox(GetActiveWindow(),"选地主了","选地主了",0);//改变return;}elseif(action==3){manager.PlayerMain=(manager.PlayerMain+1)%3;manager.PlayerMaininfo++;if(manager.PlayerMaininfo==3)manager.Game_State=-2;return;}}}if(manager.Game_State>=0&&manager.Game_State<3){//游戏进行中改变inttemp=manager.Game_State;if(manager.PlayerAc==2)temp=(temp+2)%3;if(pMsg[5]==104)//action==4;{DeMakeCard(Msg,manager.OutCards,6,pMsg.GetLength());manager.OutPlayer=manager.Game_State;intk;for(k=0;k<20&&manager.OutCards[k].Num<=15;k++)m_pView->OutCards[temp][k]=manager.OutCards[k];if(k!=20)m_pView->OutCards[temp][k].Num=16;//manager.Updata();m_pView->DrawCardOut(temp);-80- 武汉工程大学计算机科学与工程学院综合设计报告}elseif(pMsg[5]==103){m_pView->OutCards[temp][0].Num=16;manager.Game_State=(manager.Game_State+1)%3;}if(manager.Game_State!=pMsg[4]-100){manager.Game_State=pMsg[4]-100;}}if(manager.Game_State>=3){if(manager.Game_State-3==manager.PlayerMain)MessageBox(GetActiveWindow(),"地主胜利","游戏结束",0);//改变elseMessageBox(GetActiveWindow(),"农民胜利","游戏结束",0);//改变manager.Game_State=-2;}}}voidNetControl::OnSet(){m_pListening=newCNet(this);if(m_pListening->Create(m_Port)){if(!m_pListening->Listen()){MessageBox(GetActiveWindow(),"端口设置错误!","网络信息",MB_OK);}}else{MessageBox(GetActiveWindow(),"服务器设置成功,请等待玩家加入!","网络信息",MB_OK);}}voidNetControl::SendMsg(CNet*pSend,char*pMsg){sMsg=pMsg;if(pMsg!=NULL)pSend->Send(pMsg,strlen(pMsg));}-80- 武汉工程大学计算机科学与工程学院综合设计报告voidNetControl::OnSorc(){intk;k=MessageBox(GetActiveWindow(),"你是否建立主机?(主机/客户机Y/N)","建立主机",MB_OKCANCEL);if(k==1)//主机{CServerser1;ser1.DoModal();m_Port=atoi(ser1.m_Port);OnSet();m_Isserver=true;manager.MainComputer=true;//manager}else{CGetindlg1;if(dlg1.DoModal()==IDOK){CString*p=new(CString);*p=dlg1.m_ip;m_Server=*p;m_Port=atoi(dlg1.m_Port);OnOpen();m_Isserver=false;manager.MainComputer=false;}}}CNet*NetControl::ConnectServer(){CNet*pSocket=newCNet(this);if(!(pSocket->Create())){deletepSocket;MessageBox(GetActiveWindow(),"创建Socket失败","警告信息",MB_OK);returnNULL;}//连接到服务器if(!pSocket->Connect(m_Server,m_Port)){-80- 武汉工程大学计算机科学与工程学院综合设计报告deletepSocket;MessageBox(GetActiveWindow(),"请求连接到服务器失败","警告信息",MB_OK);returnNULL;}returnpSocket;}voidNetControl::OnOpen(){if(m_pSocket){MessageBox(GetActiveWindow(),"已经连接到服务器,请关闭连接再试一次!","警告信息",MB_OK);return;}//m_pSocket=newCNet(this);if(!(m_pSocket=ConnectServer())){m_pSocket=NULL;return;}else//连接成功就发送信息到服务器,获得服务器上的信息{chartem[100]="1818";tem[4]=1;strcpy(tem+5,m_pView->PlayerName[1]);SendMsg(m_pSocket,tem);}}voidNetControl::Broadcast(char*pMsg){CNet*pNet;if(!m_pList.IsEmpty()){pNet=(CNet*)m_pList.GetHead();SendMsg(pNet,pMsg);if(m_pList.GetCount()==2){pNet=(CNet*)m_pList.GetTail();SendMsg(pNet,pMsg);}}//if((p=m_pList)!=NULL)-80- 武汉工程大学计算机科学与工程学院综合设计报告}NetControl::NetControl(CProgramView*p){m_pView=p;m_pSocket=NULL;m_Server="";m_Port=100;m_pListening=NULL;m_pList.RemoveAll();m_ready[0]=false;m_ready[1]=false;m_ready[2]=false;}voidNetControl::MakeCard(char*st,Card*c){intk;for(k=0;k<20&&c[k].Num<=15;k++)st[k]=(c[k].Pow+c[k].Type*20);st[k]="";}voidNetControl::DeMakeCard(constCStringst,Card*c,intsstart,inteend){intk,m;m=0;for(k=sstart;k11)c[m].Num-=13;}elsec[m].Num=c[m].Pow;m++;}if(m!=20)c[m].Num=16;}voidNetControl::SendCards(Card*c,intaction){charp[100]="1818";p[4]=manager.Game_State+100;p[5]=action+100;p[6]="";if(m_Isserver){-80- 武汉工程大学计算机科学与工程学院综合设计报告if(action==4)MakeCard(p+6,c);Broadcast(p);}else{if(action==4)MakeCard(p+6,c);SendMsg(m_pSocket,p);}}voidNetControl::SendGetReady(){chartem[20];sprintf(tem,"1818%c%c%c",99,99,manager.PlayerAc);SendMsg(m_pSocket,tem);}voidNetControl::StartCards(){manager.GameStart();chartem1[22],tem2[22],tem3[22],tem0[22];MakeCard(tem0,manager.PlayCards[0]);MakeCard(tem1,manager.PlayCards[1]);MakeCard(tem2,manager.PlayCards[2]);MakeCard(tem3,manager.Sendleft);charst[100];sprintf(st,"1818%c%c%s%s%s%s%c",99,1,tem0,tem1,tem2,tem3,manager.PlayerMain+100);Broadcast(st);}//ProgramView.cpp:implementationoftheCProgramViewclass/////////////////////////////////////////////////////////////////////////////CProgramView::CProgramView(){//TODO:addconstructioncodeherepControl=newNetControl(this);//创建一个指向NetControl的指针isgoon=true;srand(time(NULL));-80- 武汉工程大学计算机科学与工程学院综合设计报告}CProgramView::~CProgramView(){if(!pControl->m_Isserver)pControl->SendMsg(pControl->m_pSocket,"退出游戏");elsepControl->Broadcast("退出游戏");deletepControl;}BOOLCProgramView::PreCreateWindow(CREATESTRUCT&cs){//TODO:ModifytheWindowclassorstylesherebymodifying//theCREATESTRUCTcs//加载位图m_background.LoadBitmap(IDB_BACKGROUND);m_card.LoadBitmap(IDB_CARD);returnCView::PreCreateWindow(cs);}///////////////////////////////////////////////////////////////////////////////CProgramViewdrawingvoidCProgramView::OnDraw(CDC*pDC){CProgramDoc*pDoc=GetDocument();ASSERT_VALID(pDoc);//TODO:adddrawcodefornativedatahere//初始化CDCstaticboolst=TRUE;if(st){Background.CreateCompatibleDC(pDC);Background.SelectObject(m_background);Mcard.CreateCompatibleDC(pDC);Mcard.SelectObject(m_card);st=FALSE;}PrintAll();}/////////////////////////////////////////////////////////////////////////////intCProgramView::OnCreate(LPCREATESTRUCTlpCreateStruct){-80- 武汉工程大学计算机科学与工程学院综合设计报告if(CView::OnCreate(lpCreateStruct)==-1)return-1;//TODO:Addyourspecializedcreationcodehere////////////////////////////////////////////////////////////////////////**函数名称:CBUTTON.Creat(_T("确定"),//按钮的caption属性,按钮的显示WS_CHILD|WS_VISIBLE|BS_PUSHBUTTON,//按钮也是一种窗体,同样有不同//风格,通过对常量或运算进行组合,达到一定的效果,这些常量的含义可以参考MSDNCRect(660,410,765,450),//这个参数指出按钮在视图中左上角和右下角坐标,在//确定了按钮位置的同时也确定了其大小this,//这个指针指向按钮这个窗体的父窗体ID_OK);//这是刚才为按钮定义的常量,按钮的控制ID*函数介绍:创建按钮*输入参数:见上*输出参数:无*返回值:无*///创建按钮OKm_ok.Create(_T("确定"),WS_CHILD|WS_VISIBLE|BS_PUSHBUTTON,CRect(660,420,765,460),this,ID_OK);//创建按钮CANCELm_cancel.Create(_T("退出"),WS_CHILD|WS_VISIBLE|BS_PUSHBUTTON,CRect(660,502,765,542),this,ID_CANCEL);//出牌m_sendcard.Create(_T("出牌"),WS_CHILD|WS_VISIBLE|BS_PUSHBUTTON,CRect(532,387,637,427),this,ID_SENDCARD);//过牌m_pass.Create(_T("过牌"),WS_CHILD|WS_VISIBLE|BS_PUSHBUTTON,CRect(533,460,638,500),this,ID_PASS);///////////////////////////////////////////////////////////////////////////**函数名称:CBUTTON.ShowWindow(SW_SHOW)*函数介绍:按钮的显示控制*输入参数:当输入参数为SW_SHOW表示显示按钮,当为SW_HIDE表示隐藏按钮*输出参数:无*返回值:无*///显示按钮m_ok.ShowWindow(SW_SHOW);m_cancel.ShowWindow(SW_SHOW);m_sendcard.ShowWindow(SW_SHOW);m_pass.ShowWindow(SW_SHOW);-80- 武汉工程大学计算机科学与工程学院综合设计报告//在游戏界面开始前强制输入用户名称,如果用户点的是确定,则将用户名存入PlayerName[manager.PlayAc]中//点取消的话则用户名为默认用户名。CNamedlg3;if(dlg3.DoModal()==IDOK){PlayerName[1]=dlg3.m_name;}elsePlayerName[1]="路人甲";//选择时候为主机/客户机pControl->OnSorc();return0;}voidCProgramView::OnMouseMove(UINTnFlags,CPointpoint){//TODO:Addyourmessagehandlercodehereand/orcalldefault//跟踪光标坐标intmx=point.x;intmy=point.y;CStringst;CDC*pdc=GetDC();st.Format("%d,%d",point.x,point.y);//pdc->SetBkMode(TRANSPARENT);//pDC->SetTextColor(RGB(255,255,255));pdc->TextOut(400,5,st);ReleaseDC(pdc);CView::OnMouseMove(nFlags,point);}///////////////////////////////////////////////////////////////////*函数名称:OnOk()函数介绍:响应确定按钮的点击输入参数:无输出参数:无返回值:无*/voidCProgramView::OnOK(){//MessageBox("你点击了确定按钮");//改变if(manager.Game_State>=0&&manager.Game_State<3)-80- 武汉工程大学计算机科学与工程学院综合设计报告return;if(manager.Game_State>=3){manager.Game_State=-2;isgoon=true;}if(isgoon){OutCards[0][0].Num=16;OutCards[1][0].Num=16;OutCards[2][0].Num=16;PrintAll();if(!pControl->m_Isserver){pControl->SendGetReady();}else{pControl->m_ready[1]=true;if(pControl->m_ready[0]&&pControl->m_ready[1]&&pControl->m_ready[2]){pControl->m_ready[0]=false;pControl->m_ready[1]=false;pControl->m_ready[2]=false;manager.GameStart();pControl->StartCards();PlayerPos();PrintAll(1);}}CDC*pdc=GetDC();pdc->SetBkMode(TRANSPARENT);pdc->TextOut(545,435,"准备");ReleaseDC(pdc);}}/////////////////////////////////////////////////////////////////////*函数名称:OnCancel()函数介绍:响应取消按钮的点击输入参数:无输出参数:无-80- 武汉工程大学计算机科学与工程学院综合设计报告返回值:无*/voidCProgramView::OnCancel(){//MessageBox("你点击了取消按钮");if(!pControl->m_Isserver)pControl->SendMsg(pControl->m_pSocket,"退出游戏");elsepControl->Broadcast("退出游戏");exit(0);}////////////////////////////////////////////////////////////////////////*函数名称:PrintAll(CDC*pdc)函数介绍:用来整体重画输入参数:绘图用CDC输出参数:无返回值:无*/voidCProgramView::PrintAll(){CDC*pdc=GetDC();pdc->BitBlt(0,0,800,600,&Background,0,0,SRCCOPY);if(manager.Game_State==-2)CardReady();if(manager.Game_State==-1){pdc->SetBkMode(TRANSPARENT);pdc->TextOut(600,435,"准备");pdc->TextOut(630,435,"准备");}DrawLeft();DrawCardOut(3);DrawMyCard();DrawOtherCard();PrintState();ReleaseDC(pdc);}///////////////////////////////////////////////////////////////////*函数名称:CardReady()函数介绍:画发牌前牌的摆放输入参数:无输出参数:无-80- 武汉工程大学计算机科学与工程学院综合设计报告返回值:无*/voidCProgramView::CardReady(){CDC*pdc=GetDC();for(inti=0;i<54;i++)pdc->BitBlt(300+i*2,220,72,97,&Mcard,142,384,SRCCOPY);ReleaseDC(pdc);}///////////////////////////////////////////////////////////////////*函数名称:DrawMyCard()函数介绍:画出当前玩家手中的牌输入参数:无输出参数:无返回值:无*/voidCProgramView::DrawMyCard(){CDC*pdc=GetDC();inti;for(i=0;i<20&&manager.PlayCards[manager.PlayerAc][i].Num<=15;i++){if(manager.PlayCards[manager.PlayerAc][i].Num<14){if(manager.PlayCards[manager.PlayerAc][i].Click)pdc->BitBlt(100+i*15,480-40,71,96,&Mcard,(manager.PlayCards[manager.PlayerAc][i].Num-1)*71,manager.PlayCards[manager.PlayerAc][i].Type*96,SRCCOPY);elsepdc->BitBlt(100+i*15,480,71,96,&Mcard,(manager.PlayCards[manager.PlayerAc][i].Num-1)*71,manager.PlayCards[manager.PlayerAc][i].Type*96,SRCCOPY);}elseif(manager.PlayCards[manager.PlayerAc][i].Num<=15){if(manager.PlayCards[manager.PlayerAc][i].Click)pdc->BitBlt(100+i*15,480-40,71,96,&Mcard,(manager.PlayCards[manager.PlayerAc][i].Num-14)*71,384,SRCCOPY);elsepdc->BitBlt(100+i*15,480,71,96,&Mcard,(manager.PlayCards[manager.PlayerAc][i].Num-14)*71,384,SRCCOPY);}}-80- 武汉工程大学计算机科学与工程学院综合设计报告ReleaseDC(pdc);}///////////////////////////////////////////////////////////////////*函数名称:DrawOtherCard函数介绍:画出其他玩家的牌(包括其还剩下多少张牌及当前出的牌)输入参数:Card*card为传入的对方出的牌即OutCards输出参数:无返回值:无*/voidCProgramView::DrawOtherCard(){CDC*pdc=GetDC();inti;if(manager.Game_State==-2)return;//画其他玩家剩下的牌/反面for(i=0;i<20&&cardleft[i].Num<=15;i++){pdc->BitBlt(55,55+i*10,97,75,&Mcard,214,408,SRCCOPY);}for(i=0;i<20&&cardright[i].Num<=15;i++){pdc->BitBlt(630,55+i*10,97,75,&Mcard,214,408,SRCCOPY);}ReleaseDC(pdc);}voidCProgramView::OnLButtonDown(UINTnFlags,CPointpoint){//TODO:Addyourmessagehandlercodehereand/orcalldefaultintmx=point.x;intmy=point.y;inti;//点到中间若轮到主机发牌则发牌(暂无动画)/*if(isgoon&&mx>=300&&my>=220&&mx<=476&&my<=312&&(pControl->m_Isserver)&&manager.Game_State==-1){MessageBox("主机发牌");pControl->StartCards();}*/-80- 武汉工程大学计算机科学与工程学院综合设计报告//将牌点起来if(isgoon&&mx>=100&&my>=440&&mx<=455&&my<=575){CDC*pdc=GetDC();for(i=0;manager.PlayCards[manager.PlayerAc][i].Num<=15;i++);if(mx<=100+(i-1)*15+71&&my<=576&&mx>=100&&my>=440){i=SelectNum(i,mx,my);//判断点中的是第几张牌if(manager.DoMsg(i,1))PrintAll();}ReleaseDC(pdc);}CView::OnLButtonDown(nFlags,point);}///////////////////////////////////////////////////////////////////*函数名称:SelectNum(intnum,intmx,intmy)函数介绍:判断点中的是第几张牌输入参数:intnum,intmx,intmy(当前玩家手中牌的数量,光标横坐标,光标纵坐标)输出参数:无返回值:无*/intCProgramView::SelectNum(intnum,intmx,intmy){if(mx>=100+(num-1)*15)returnnum-1;elsereturn(mx-100)/15;}///////////////////////////////////////////////////////////////////*函数名称:OnSendCard()函数介绍:响应出牌按钮输入参数:无输出参数:无返回值:无*/voidCProgramView::OnSendCard(){if(isgoon&&manager.DoMsg(15,4)){-80- 武汉工程大学计算机科学与工程学院综合设计报告intk;for(k=0;k<20&&manager.OutCards[k].Num<=15;k++)OutCards[1][k]=manager.OutCards[k];if(k!=20)OutCards[1][k].Num=16;PrintAll();pControl->SendCards(manager.OutCards,4);}}///////////////////////////////////////////////////////////////////*函数名称:OnPass()函数介绍:响应过牌按钮输入参数:无输出参数:无返回值:无*/voidCProgramView::OnPass(){if(isgoon&&manager.DoMsg(16,3)){OutCards[1][0].Num=16;PrintAll();pControl->SendCards(NULL,3);}}///////////////////////////////////////////////////////////////////*函数名称:DrawPlayername(char*s)函数介绍:绘出玩家的姓名输入参数:玩家姓名的字符串输出参数:无返回值:无*/voidCProgramView::DrawPlayername(){CDC*pdc=GetDC();pdc->SetBkMode(TRANSPARENT);//设置背景为透明//pDC->SetTextColor(RGB(255,255,255));//设置字体颜色pdc->TextOut(40,400,PlayerName[0]);pdc->TextOut(90,500,PlayerName[1]);pdc->TextOut(660,400,PlayerName[2]);-80- 武汉工程大学计算机科学与工程学院综合设计报告ReleaseDC(pdc);}///////////////////////////////////////////////////////////////////*函数名称:DrawLeft()函数介绍:绘出地主牌的情况,如果还没叫主,则是牌的背面,如果叫主,则为牌的正面输入参数:无输出参数:无返回值:无*/voidCProgramView::DrawLeft(){CDC*pdc=GetDC();inti;if(manager.Game_State==-1){for(i=0;i<3;i++)pdc->BitBlt(300+i*40,25,72,97,&Mcard,142,384,SRCCOPY);}elseif(manager.Game_State>=0&&manager.Game_State<=5){for(i=0;i<3;i++){if(manager.Sendleft[i].Num<14)pdc->BitBlt(300+i*40,25,71,96,&Mcard,(manager.Sendleft[i].Num-1)*71,manager.Sendleft[i].Type*96,SRCCOPY);elseif(manager.Sendleft[i].Num<=15)pdc->BitBlt(300+i*40,25,71,96,&Mcard,(manager.Sendleft[i].Num-14)*71,384,SRCCOPY);}}ReleaseDC(pdc);}///////////////////////////////////////////////////////////////////*函数名称:DrawCardOut()函数介绍:绘出当前玩家出的牌输入参数:无输出参数:无返回值:无*/voidCProgramView::DrawCardOut(intk){inti;-80- 武汉工程大学计算机科学与工程学院综合设计报告CDC*pdc=GetDC();if(k==1||k==3){pdc->BitBlt(100,330,360,96,&Background,0,0,SRCCOPY);for(i=0;i<20&&OutCards[1][i].Num<=15;i++){if(OutCards[1][i].Num<=13)pdc->BitBlt(100+i*15,330,71,96,&Mcard,(OutCards[1][i].Num-1)*71,OutCards[1][i].Type*96,SRCCOPY);elseif(OutCards[1][i].Num<=15)pdc->BitBlt(100+i*15,330,71,96,&Mcard,(OutCards[1][i].Num-14)*71,384,SRCCOPY);}}if(k==2||k==3){pdc->BitBlt(550,0,71,300,&Background,0,0,SRCCOPY);for(i=0;i<20&&OutCards[2][i].Num<=15;i++){if(OutCards[2][i].Num<14){pdc->BitBlt(550,i*15,71,96,&Mcard,(OutCards[2][i].Num-1)*71,OutCards[2][i].Type*96,SRCCOPY);}elseif(OutCards[2][i].Num<=15){pdc->BitBlt(550,i*15,71,96,&Mcard,(OutCards[2][i].Num-14)*71,384,SRCCOPY);}}}if(k==0||k==3){pdc->BitBlt(170,0,71,300,&Background,0,0,SRCCOPY);for(i=0;i<20&&OutCards[0][i].Num<=15;i++){if(OutCards[0][i].Num<14){pdc->BitBlt(170,i*15,71,96,&Mcard,(OutCards[0][i].Num-1)*71,OutCards[0][i].Type*96,SRCCOPY);}-80- 武汉工程大学计算机科学与工程学院综合设计报告elseif(OutCards[0][i].Num<=15){pdc->BitBlt(170,i*15,71,96,&Mcard,(OutCards[0][i].Num-14)*71,384,SRCCOPY);}}}ReleaseDC(pdc);}voidCProgramView::PrintState(){CDC*pdc=GetDC();pdc->SetBkMode(TRANSPARENT);if(manager.Game_State==-2)pdc->TextOut(266,5,"游戏还没开始");elseif(manager.Game_State==-1){pdc->TextOut(266,5,"还在选择地主");}if(manager.PlayerMain==(manager.PlayerAc+1)%3)pdc->TextOut(490,5,"右边的是地主");elseif(manager.PlayerMain==manager.PlayerAc)pdc->TextOut(490,5,"你现在是地主");elseif(manager.PlayerMain==(manager.PlayerAc+2)%3)pdc->TextOut(490,5,"左边的是地主");if(manager.Game_State==manager.PlayerAc)pdc->TextOut(100,5,"到你出牌了");elseif(manager.Game_State==(manager.PlayerAc+1)%3)pdc->TextOut(100,5,"右边的出牌");elseif(manager.Game_State==(manager.PlayerAc+2)%3)pdc->TextOut(100,5,"左边的出牌");DrawPlayername();ReleaseDC(pdc);}voidCProgramView::PlayerPos(){cardmiddle=manager.PlayCards[manager.PlayerAc];if(manager.PlayerAc==0){cardleft=manager.PlayCards[2];-80- 武汉工程大学计算机科学与工程学院综合设计报告cardright=manager.PlayCards[1];}elseif(manager.PlayerAc==1){cardleft=manager.PlayCards[0];cardright=manager.PlayCards[2];}elseif(manager.PlayerAc==2){cardleft=manager.PlayCards[1];cardright=manager.PlayCards[0];}}//重载PrintAll()实现发牌动画voidCProgramView::PrintAll(inttype){timer=0;isgoon=false;SetTimer(1,20,NULL);}//发牌动画voidCProgramView::OnTimer(UINTnIDEvent){CDC*pdc=GetDC();staticinti(1);intj;staticintx,y;x=300+54*2,y=220;if(timer<18){//画没发出去的牌,飞行途中pdc->BitBlt(300+(53-timer*3)*2,220,100,200,&Background,300+(53-timer*3)*2,220,SRCCOPY);for(j=0;j<54-timer*3;j++)pdc->BitBlt(300+j*2,220,72,97,&Mcard,142,384,SRCCOPY);x-=timer*3*2;//画发出去的牌if(manager.PlayCards[manager.PlayerAc][timer].Num<14){//擦除上次画的牌,用背景覆盖if(i-1>0)pdc->BitBlt(x+(100+timer*15-x)/10*(i-1),y+(480-y)/10*(i-1),71,96,&Background,x+(100+timer*15-x)/10*(i-1),y+(480-y)/10*(i-1),SRCCOPY);-80- 武汉工程大学计算机科学与工程学院综合设计报告//画当前显示的牌pdc->BitBlt(x+(100+timer*15-x)/10*i,y+(480-y)/10*i,71,96,&Mcard,(manager.PlayCards[manager.PlayerAc][timer].Num-1)*71,manager.PlayCards[manager.PlayerAc][timer].Type*96,SRCCOPY);}elseif(manager.PlayCards[manager.PlayerAc][timer].Num<=15)//画大小鬼{if(i-1>0)pdc->BitBlt(x+(100+timer*15-x)/10*(i-1),y+(480-y)/10*(i-1),71,96,&Background,x+(100+timer*15-x)/10*(i-1),y+(480-y)/10*(i-1),SRCCOPY);pdc->BitBlt(x+(100+timer*15-x)/10*i,y+(480-y)/10*i,71,96,&Mcard,(manager.PlayCards[manager.PlayerAc][timer].Num-14)*71,384,SRCCOPY);}if(cardleft[timer].Num<=15){if(i-1>0)pdc->BitBlt(x+(55-x)/10*(i-1),y+(55+timer*10-y)/10*(i-1),97,75,&Background,x+(55-x)/10*(i-1),y+(55+timer*10-y)/10*(i-1),SRCCOPY);pdc->BitBlt(x+(55-x)/10*i,y+(55+timer*10-y)/10*i,97,75,&Mcard,214,408,SRCCOPY);}if(cardright[timer].Num<=15){if(i-1>0)pdc->BitBlt(x+(630-x)/10*(i-1),y+(55+timer*10-y)/10*(i-1),97,75,&Background,x+(630-x)/10*(i-1),y+(55+timer*10-y)/10*(i-1),SRCCOPY);pdc->BitBlt(x+(630-x)/10*i,y+(55+timer*10-y)/10*i,97,75,&Mcard,214,408,SRCCOPY);}i++;if(i==10)//牌已经飞到指定位置{//檫除上一帧画的牌if(manager.PlayCards[manager.PlayerAc][timer].Num<14){pdc->BitBlt(x+(100+timer*15-x)/10*(i-1),y+(480-y)/10*(i-1),71,96,&Background,x+(100+timer*15-x)/10*i,y+(480-y)/10*i,SRCCOPY);}elseif(manager.PlayCards[manager.PlayerAc][timer].Num<=15){pdc->BitBlt(x+(100+timer*15-x)/10*(i-1),y+(480-y)/10*(i-1),71,96,&Background,x+(100+timer*15-x)/10*i,y+(480-y)/10*i,SRCCOPY);}-80- 武汉工程大学计算机科学与工程学院综合设计报告if(cardleft[timer].Num<=15){pdc->BitBlt(x+(55-x)/10*(i-1),y+(55+timer*10-y)/10*(i-1),97,75,&Background,x+(55-x)/10*(i-1),y+(55+timer*10-y)/10*(i-1),SRCCOPY);}if(cardright[timer].Num<=15){pdc->BitBlt(x+(630-x)/10*(i-1),y+(55+timer*10-y)/10*(i-1),97,75,&Background,x+(630-x)/10*(i-1),y+(55+timer*10-y)/10*(i-1),SRCCOPY);}i=0;//重画被背景覆盖的牌if(timer>13){if(manager.PlayCards[manager.PlayerAc][(timer-1)].Num<14){pdc->BitBlt(100+(timer-1)*15,480,71,96,&Mcard,(manager.PlayCards[manager.PlayerAc][(timer-1)].Num-1)*71,manager.PlayCards[manager.PlayerAc][(timer-1)].Type*96,SRCCOPY);}elseif(manager.PlayCards[manager.PlayerAc][(timer-1)].Num<=15){pdc->BitBlt(100+(timer-1)*15,480,71,96,&Mcard,(manager.PlayCards[manager.PlayerAc][(timer-1)].Num-14)*71,384,SRCCOPY);}}//画出飞到的牌if(manager.PlayCards[manager.PlayerAc][timer].Num<14){pdc->BitBlt(100+timer*15,480,71,96,&Mcard,(manager.PlayCards[manager.PlayerAc][timer].Num-1)*71,manager.PlayCards[manager.PlayerAc][timer].Type*96,SRCCOPY);}elseif(manager.PlayCards[manager.PlayerAc][timer].Num<=15){pdc->BitBlt(100+timer*15,480,71,96,&Mcard,(manager.PlayCards[manager.PlayerAc][timer].Num-14)*71,384,SRCCOPY);}if(cardleft[timer].Num<=15){-80- 武汉工程大学计算机科学与工程学院综合设计报告pdc->BitBlt(55,55+timer*10,97,75,&Mcard,214,408,SRCCOPY);pdc->BitBlt(630,55+timer*10,97,75,&Mcard,214,408,SRCCOPY);}timer++;}}else{KillTimer(1);for(j=0;j<3;j++)manager.SortCard(manager.PlayCards[j]);PrintAll();isgoon=true;}ReleaseDC(pdc);}//ProgramView.h:interfaceoftheCProgramViewclass///////////////////////////////////////////////////////////////////////////////public:CProgramDoc*GetDocument();NetControl*pControl;//Operationspublic://Overrides//ClassWizardgeneratedvirtualfunctionoverrides//{{AFX_VIRTUAL(CProgramView)public:virtualvoidOnDraw(CDC*pDC);//overriddentodrawthisviewvirtualBOOLPreCreateWindow(CREATESTRUCT&cs);protected://}}AFX_VIRTUAL//定义画图用CDCCDCBackground;CDCMcard;//定义画图用CBitmapCBitmapm_background;CBitmapm_card;//定义BUTTON对象CButtonm_ok;-80- 武汉工程大学计算机科学与工程学院综合设计报告CButtonm_cancel;CButtonm_sendcard;CButtonm_pass;//测试CButtonm_test;//定义指针Card*cardleft;Card*cardmiddle;Card*cardright;CardOutCards[3][20];//Implementationpublic:boolisgoon;voidOnTimer(UINTnIDEvent);voidPrintAll(inttype);voidPlayerPos();voidPrintState();voidDrawCardOut(intk);voidDrawLeft();//绘出剩下的地主的牌,当地主还没决定的时候画的是牌的背面,决定地主//后画出地主的牌voidDrawPlayername();//根据传入的字符串,绘出玩家的名称voidOnPass();//点击过牌按钮后的响应函数voidOnSendCard();//画出当前玩家所出的牌intSelectNum(intnum,intmx,intmy);//判断玩家点牌后具体点的是哪一张voidDrawOtherCard();//画出另外两个玩家还剩下的牌,以及//他们刚刚出牌voidDrawMyCard();//画出当前玩家手中牌voidOnCancel();//点击退出按钮后的响应函数voidOnOK();//点击确定按钮后的响应函数virtual~CProgramView();CStringPlayerName[3];//用来存放三个玩家姓名的字符串voidPrintAll();//整体重画friendclassNetControl;private:inttimer;voidCardReady();//用来画还没发牌时牌的情况};-80-'