vc++多人对战平台(连连看)系统毕业设计(含源文件) 下载本文

摘要

因特网的发展使人类进入了一个全新的世界,人与人之间可以远隔万里为了同一兴趣爱好而交流,做到了网络无国界,信息无国界。随着因特网的不断发展,网络游戏作为一个新的名词融入到了人们的日常生活当中。网络游戏来源于“onlinegame”,更直接的翻译是“在线游戏”,亦即必须在大家联网而且都在线的时候,才能够团队互动,否则就属于单机游戏了。

网络游戏产业作为现代电脑电子技术的产物,正在以其独特的魅力在全世界的娱乐领域占据主流位置,我们在承认广大娱乐网民的选择空间狭小的同时,也必须明确的一点就是网络游戏本身所具有的强大的吸引力。网络游戏的吸引力主要在于,它在让玩家打发时间的同时,可以让人实现在显示生活中不能实现的理想,得到在显示中不能得到的东西。而且网游产业促动高科技技术不断升级,作为经济增长的一大支撑点,已经成为经济腾飞的“第四产业”。近年来,世界网络游戏市场高速发展。根据统计,全球网络玩家所占互联网人群的比例已经超过30%。网络游戏凭借其信息双向交流,速度快,不受空间限制等互联网有时,具有诱人的互动性、仿真性和竞技性,已经成为网络业盈利优厚的三大领域之一。网络平台的发展,为网络游戏奠定了坚实的“物质”基础。宽带的迅猛发展为网络游戏提供了“高速公路”,而专用游戏服务器则为网络游戏提供了容量巨大的“加油站”。前不久,网络游戏还被视为一个“高风险”的行业,但随着人们对网络游戏的重新认识,网络游戏正在恢复其应有的地位。

本文在基于VC++开发平台的多人对战平台系统的工作基础上采用基于B/S三层架构模式,选取VC++6.0作为开发工具,以Access2007为后台数据库,来实现多人对战平台的基本功能。

关键词:连连看、网络游戏、网络对战

1

目录

摘要 .................................................................................................................................................. 1 目录 .................................................................................................................................................. 2 第1章 绪论 .................................................................................................................................. 3

1.1目的 ..................................................................................................................................... 3 1.2意义 ..................................................................................................................................... 3 1.3主要问题 ............................................................................................................................. 3 1.4技术要求 ............................................................................................................................. 3 1.5发展概况 ............................................................................................................................. 3 1.6指导思想 ............................................................................................................................ 4 第2章 系统解决方案的选择 ...................................................................................................... 5

2.1 C/S结构 .............................................................................................................................. 5 2.2 三层架构 ............................................................................................................................ 5

2.2.1什么是“三层架构” .............................................................................................. 6 2.2.2三层架构的优缺点 .................................................................................................. 6

第3章 需求分析 ............................................................................................................................ 7

3.1产品描述 ............................................................................................................................. 7 3.2产品功能 ............................................................................................................................. 7 3.3具体功能需求 ..................................................................................................................... 8 3.4协议设计 ........................................................................................................................... 11

3.4.1控制消息UDP数据包格式 .................................................................................... 11 3.4.2客户端到服务器端(C->S)UDP数据包 ............................................................. 12 3.4.3服务器端到客户端 (S->C)UDP数据包 ........................................................... 13 3.4.4数据库设计 ............................................................................................................ 13 3.4.5详细设计 ................................................................................................................ 13

第4章 总体设计 .......................................................................................................................... 14

4.1开发环境 ........................................................................................................................... 14 4.2相关表设计图 ................................................................................................................... 14 第5章 详细设计 ........................................................................................................................ 31

5.1用户注册功能 ................................................................................................................... 31 5. 2登录页面 .......................................................................................................................... 40 5.3游戏大厅 ........................................................................................................................... 48 5.4游戏房间 ........................................................................................................................... 57 5.5游戏准备界面 ................................................................................................................... 65 5.6游戏界面 ........................................................................................................................... 69 第6章 总结与展望 ...................................................................................................................... 98 致谢 ................................................................................................................................................ 98

2

第1章 绪论

1.1目的

网络小游戏制作的目的是满足了人们休闲的需要,在紧张工作之余休闲类的小游戏能够给人带来最大程度的放松,也可以增进人们之间的交流,沟通,通过游戏还可以认识更多的朋友,也可以到达跨省、跨市,甚至跨国间人们互相娱乐的目的。

另外也通过本程序将两年来所学的专业知识和其他方面的知识融入到实际应用中。

1.2意义

通过此次课题的设计,掌握如何制作一个游戏软件,以及制作游戏软件的整个流程,制作游戏软件的步骤,为以后的就业工作打下基础。

1.3主要问题

开始制作游戏时,主要要解决的问题有以下几个方面:如何设置整个游戏的界面;如何控制连连看游戏中随机图片的生成且每种图片必须为偶数个;游戏开始后,判断鼠标两次点击的图片能否消去,即图片是否相同且图片之间路径的判断;如何连接网络上的两台计算机实现网络对战,互发消息,如何判断游戏是否结束以及输赢问题等。

1.4技术要求

网络中任意计算机当运行该游戏软件是,要有一台当服务器,如果要当服务器,则等待客户机的连接请求;如果要当客户机,则要主动去连接服务器。游戏中能正确判断鼠标两次点下的图片是否可以消去、能正确判断游戏是否已经结束和哪一方玩家胜出。还可顺利发消息给对方和接收对方发来的消息。

1.5发展概况

网络游戏正处于加速发展周期中,中国网络游戏市场迅速扩大,近三年的年均增长率超过100%。网络游戏的告诉发展,逐渐引起了我国政府的高度重视,信息产业部、文化部、新闻出版总属等相关部门都在积极推动各项市场监管和鼓

3

励网络游戏产业发展的政策措施的出台,2003年网络游戏首次被正式纳入国家863计划,标志着我国网络游戏产业已经的到政府的充分重视。除外,在网络游戏产业发展的同时,有力带动了相关行业的发展,如软件、计算机、通信、电信运营、互联网等,根据统计,网络游戏能够带动10倍于自身产值的相关行业的发展。预计未来三年,中国游戏时常规模仍将保持60%以上的告诉增长,至2006年市场规模将接近100亿元,而多样的资本运作模式将成为网络游戏产业发展的重要推动力。同时,手机游戏、家用游戏机、游戏传媒、电子竞技等游戏周边行业也将快速发展起来。

1.6指导思想

按照软件开发的总过程进行设计,经历定义和计划、需求分析、软件设计、软件编码、软件测试等过程。

4

第2章 系统解决方案的选择

2.1 C/S结构

C/S (Client/Server)结构,即大家熟知的客户机和服务器结构。它是软件系统体系结构,通过它可以充分利用两端硬件环境的优势,将任务合理分配到Client端和Server端来实现,降低了系统的通讯开销。目前大多数应用软件系统都是Client/Server形式的两层结构,由于现在的软件应用系统正在向分布式的Web应用发展,Web和Client/Server 应用都可以进行同样的业务处理,应用不同的模块共享逻辑组件;因此,内部的和外部的用户都可以访问新的和现有的应用系统,通过现有应用系统中的逻辑可以扩展出新的应用系统。这也就是目前应用系统的发展方向。

C/S结构的优点是能充分发挥客户端PC的处理能力,很多工作可以在客户端处理后再提交给服务器。对应的优点就是客户端响应速度快。

C/S架构软件的优势与劣势:

(1)应用服务器运行数据负荷较轻。最简单的C/S体系结构的数据库应用由两部分组成,即客户应用程序和数据库服务器程序。二者可分别称为前台程序与后台程序。运行数据库服务器程序的机器,也称为应用服务器。一旦服务器程序被启动,就随时等待响应客户程序发来的请求;客户应用程序运行在用户自己的电脑上,对应于数据库服务器,可称为客户电脑,当需要对数据库中的数据进行任何操作时,客户程序就自动地寻找服务器程序,并向其发出请求,服务器程序根据预定的规则作出应答,送回结果,应用服务器运行数据负荷较轻。 (2)数据的储存管理功能较为透明。在数据库应用中,数据的储存管理功能,是由服务器程序和客户应用程序分别独立进行的,前台应用可以违反的规则,并且通常把那些不同的(不管是已知还是未知的)运行数据,在服务器程序中不集中实现,例如访问者的权限,编号可以重复、必须有客户才能建立定单这样的规则。所有这些,对于工作在前台程序上的最终用户,是“透明”的,他们无须过问(通常也无法干涉)背后的过程,就可以完成自己的一切工作。在客户服务器架构的应用中,前台程序不是非常“瘦小”,麻烦的事情都交给了服务器和网络。在C/S体系的下,数据库不能真正成为公共、专业化的仓库,它受到独立的专门管理。

5

(3)C/S架构的劣势是高昂的维护成本且投资大。首先,采用C/S架构,要选择适当的数据库平台来实现数据库数据的真正“统一”,使分布于两地的数据同步完全交由数据库系统去管理,但逻辑上两地的操作者要直接访问同一个数据库才能有效实现,有这样一些问题,如果需要建立“实时”的数据同步,就必须在两地间建立实时的通讯连接,保持两地的数据库服务器在线运行,网络管理工作人员既要对服务器维护管理,又要对客户端维护和管理,这需要高昂的投资和复杂的技术支持,维护成本很高,维护任务量大。

2.2 三层架构

2.2.1什么是“三层架构”

三层架构(3-tier application) 通常意义上的三层架构就是将整个业务应用划分为:表现层(UI)、业务逻辑层(BLL)、数据访问层(DAL)。区分层次的目的即为了“高内聚,低耦合”的思想。所谓三层体系结构,是在客户端与数据库之间加入了一个“中间层”,也叫组件层。这里所说的三层体系,不是指物理上的三层,不是简单地放置三台机器就是三层体系结构,也不仅仅有B/S应用才是三层体系结构,三层是指逻辑上的三层,即使这三个层放置到一台机器上。三层体系的应用程序将业务规则、数据访问、合法性校验等工作放到了中间层进行处理。通常情况下,客户端不直接与数据库进行交互,而是通过COM/DCOM通讯与中间层建立连接,再经由中间层与数据库进行交互。

2.2.2三层架构的优缺点

优点:

(1)开发人员可以只关注整个结构中的其中某一层; (2)可以很容易的用新的实现来替换原有层次的实现; (3)可以降低层与层之间的依赖; (4)有利于标准化; (5)利于各层逻辑的复用。 缺点:

(1)降低了系统的性能。这是不言而喻的。如果不采用分层式结构,很多业务可以直接造访数据库,以此获取相应的数据,如今却必须通过中间层来完成。

6

(2)有时会导致级联的修改。这种修改尤其体现在自上而下的方向。如果在表示层中需要增加一个功能,为保证其设计符合分层式结构,可能需要在相应的业务逻辑层和数据访问层中都增加相应的代码。

第3章 需求分析

3.1产品描述

本产品是一款网络游戏。系统由服务端与客户端两个程序构成。采用C/S构架方式实现。服务端主要业务:提供客户端请求的服务、中转游戏数据等。而客户端提供友好的人机交互方式,供用户游戏平台,主要实现了最多6人一起游戏,按照以下顺序实现:进入游戏大厅、准备开始游戏,如果有3个以上的客户端预备开始游戏,而限定时间内又没有新的客户端准备开始,服务端就要求客户端开始游戏的倒计时,倒计时完成后,各玩家开始游戏。在游戏过程中,各玩家可以看到其它玩家的游戏进度的缩略图,但不允许增加新玩家,其它没有游戏的玩家只可以旁观游戏

3.2产品功能

模块 服务端 功能 玩家信息管理 积分管理 在线用户管理 游戏桌子管理 游戏棋盘管理 信息中转管理 客户端 注册新玩家 登陆功能 大厅浏览功能 准备与自动搜寻游戏功能 游戏旁观功能 各玩家地图缩略图

说明 7

积分排行 连连看游戏规则

3.3具体功能需求

3.3.1服务器端: 玩家信息管理

引言:该功能实现玩家基础数据管理,包括玩家的游戏ID、姓名、密码、昵称、性别、生日、联系电话。这些数据是由客户端输入,玩家提交信息后,通过网络传输到服务端,服务端验证合法性后,自动生成一个新的游戏ID,告诉客户端,并将该玩家的一系列信息存入对应数据库表中。

输入 1. 2. 3. 4. 5. 6. 7. 游戏ID 姓名 昵称 密码 性别 生日 联系电话 处理 1、 游戏ID是服务端自动生成给玩家的游戏编号,玩家登陆时用该编号登陆(编号位数不限,可以为1位也可以为任意位数值) 2、 姓名与昵称长度都不能超过8位,可以为字母 空格 汉字。 3、 密码长度5位,必需给出确认密码的输入 (不限定字符,可为任意字符) 4、 性别:男、女 5、 生日形如:**年**月**日 6、 联系电话:7位或8位或11位或12位(12位时第一个数字必需是0) 输出 1、 所有输入不按规则输入,均给出相应错误提示,提示要有针对性 2、 如果两次密码输入不一致,给用户一个友好提示,要求改正 3、 密码用‘*’输出 3.3.2 服务端:积分管理功能

引言:服务端必需在每次游戏结束后,按各玩家游戏的进度情况,评出6个等级出来,分别加分6、3、1、0、-1、-2,并在玩家积分表加入对应的积分值,并在客户端能查看出积分排行情况,列出前10名的玩家信息。积分表包含:游戏

8

ID(连连看游戏ID值暂定为1000)、玩家ID、积分

输入 1、 各玩家游戏的进度 处理 1、服务端要求统计出各玩家所得分值 输出 1、服务端应将该次游戏的各玩家得到累计到对应积分表中 2、 客户端能查看积分在前10名的玩家排行榜 3.3.3服务端:在线用户管理

引言: 服务端必需在列表视图里显示当前在线玩家,某玩家上线或下线必需实时更新列表。该列表内容包括玩家ID、昵称、玩家状态(空闲、旁观、正在游戏)

输入 处理 输出 实时更新在线用户列表,及相应玩家状态 3.3.4服务器端:游戏桌子管理功能

引言:游戏桌子数量暂定为1张,共6个位置,至少要3个人坐不同位置才可以开始游戏。服务端当监控到该桌子数量玩家数有3个以上,并在10秒内没有新玩家坐下,即可通知各坐下的客户端开始倒计时,开始倒计时后不允许新玩家再坐下空位置。如果各玩家主动都提出开始游戏,则可不用倒计时直接开始游戏。

3.3.5服务器端:游戏棋盘管理

引言: 开始游戏提交后,服务端随机生成本次游戏的棋盘布局数据,大小为12*8,发送给各玩家。(注:共有12*8=96项数据,数据取值暂定16种,每种数据出现6次)

输入 无 处理 随机生成大小为12*8的棋盘布局数据 输出 将棋盘数据发送给各玩家 3.3.6服务器端:信息中转管理功能

引言: 对各玩家的互相通讯的信息,都要经过服务器中转。包含游戏中通讯的数据、私聊、群聊等信息

9

3.3.7客户端:注册新玩家

引言:该功能在客户端输入新玩家信息,包括玩家的姓名、密码、昵称、性别、生日、联系电话。玩家提交信息后,通过网络传输到服务端,服务端能过后,通知客户端生成一个新的玩家ID,并在界面里提示出

输入 1. 2. 3. 4. 5. 6. 姓名 昵称 密码 性别 生日 联系电话 处理 输出 1、 姓名与昵称长度都不能超过8位 1、 所有输入不按规则输入,2、 密码长度5位,必需给出确认密码的输入 3、 性别:男、女 4、 生日形如:**年**月**日 5、 联系电话:7位或8位或11位或12位(12位时第一个数字必需是0) 均给出相应错误提示,提示要有针对性 2、 如果两次密码输入不一致,给用户一个友好提示,要求改正 3、 密码用‘*’输出 4、 注册成功与否要提示客户,如果成功则要给出新玩家的ID号 3.3.8客户端:登陆功能

引言:客户端启动程序后,要求客户输入玩家ID与密码,通过服务器验证后,如果存在该玩家且密码正确,则允许登陆,进入系统后,在界面上能直观看出当前玩家昵称。否则登陆失败提示登陆出错信息,不允许进入系统

输入 1、 玩家ID 2、 密码 处理 1、 对输入的数据进行合法验证(数据格式验证) 输出 1、登陆结果要给出提示,提示内容要人性化,合理 3.3.9客户端:大厅浏览功能

引言: 客户端进入系统后,可以浏览到当前游戏的大厅,及桌子数。目前只有一个桌子,因此在客户端能看到当前一张桌子,及桌子6个座位的入座情况即可。

3.3.10客户端:准备与自动搜寻位置功能

引言:客户端各玩家根据当前桌子的入座情况,选择一个空位置即可进入游戏状

10

态,准备开始游戏。在入座过程中,有一玩家比你先坐下,则要提示已有玩家入坐该位置。

自动搜寻位置:该功能实现自动的搜索出一空位置,提示玩家是否入座该位置。

3.3.11客户端:游戏旁观功能

引言:该功能实现游戏桌子已经开始游戏后,其它非游戏中的玩家,可以进入旁观游戏状态,浏览到各玩家游戏进度情况。但不能任何方式干扰正在游戏玩家

3.3.12客户端:各玩家地图缩略图

引言:在游戏过程中,当前玩家可以看到其它玩家的游戏进度,用地图缩略图的方式清楚看到对方游戏状态。

3.3.13客户端:积分排行

引言:任何玩家都可以由主界面的功能链接,查看到当前全服积分提在前10名玩家信息,显示玩家信息只要主要信息即可

3.3.14连连看游戏规则与约定

引言:哪个玩家最快连完全图,则得分最高,只要一玩家连完全图,则游戏结束。此时服务端根据各玩家连接图片数量,排出该次游戏名次出来,并提示各玩家得分情况

重列功能:客户端提供连连看图片重列功能:重新放置剩下图片,可随机改变剩下图片位置与顺序,重列次数暂定为最多重列5次

连击次数统计:当连接图片一次与上一次连接时间相差在1秒内认为是连击,并要累计连接最大数,并显示在界面上。当断连击后,下次连击要显示出上次连击的最大数,如本次连击了两个,上次最大数为12次,则显示:2/12

3.3.15连连看游戏特效

引言: 连接线特效:两张相像的图被消时,要在这两张图之间爆破连线(模仿QQ连连看效果)

3.4协议设计

3.4.1控制消息UDP数据包格式

名称

内容 描述 长度

11

VERSION CMD_TYPE KEYWORD COMMAND SEQNUM UIN PARAMETERS

01 00 Xx Xx Xx xx Xx xx

协议版本 命令类型(00,01) 加密字段 命令代码 数据包序号

2 1 1 2 2 4 可变

Xx xx xx xx 发送方标识 可变

可选参数

CMD_TYPE取值范围 值 00 01

含义 C->S S->C

3.4.2客户端到服务器端(C->S)UDP数据包

名称

CMD_KEEPALIVE CMD_REG CMD_LOGIN

CMD_SEND_LOG_DATE CMD_FANGJIAN_DATE CMD_CLOSE_DATE

CMD_KEEPALIVE 名称 HOST MAC

内容 可变

描述 主机名称

长度 可变 6

代码 0x01 0x02 0x03 0x04 0x05 0x06

描述 学生在线保持 用户注册 用户登录

向服务器请求在线列表 进入游戏房间 关闭游戏

Xx xx xx xx xx MAC地址 xx

12

3.4.3服务器端到客户端 (S->C)UDP数据包

名称

SRV_LOGIN_OK SRV_REG_OK

代码 0x01 0x02

描述 登录成功 注册成功 群聊信息 游戏结束 离开桌子 游戏开始 重置图片

SRV_QUNLIAO_DATE 0x03 SRV_GAME_OVER SRV_EXIT_TUPIAN

0x04 0x05

SRV_YOUXI_KAISHI 0x06 SRV_ CHONGZHI

0x07

3.4.4数据库设计

根据系统流程图对数据库进行设计(详细见第4章)。

3.4.5详细设计

进行了系统详细设计,并进行编码设计,完成了对多人对战平台(连连看)系统大部分功能模块的开发。(详细见第5章)。

13

第4章 总体设计

4.1开发环境

开发工具:Microsoft Visual C++ 6.0 数据库 :Microsoft Access 数据库

4.2相关表设计图

服务器类图

14

客户端类图

15

16

数据库表设计图:

用户明细表:

用户积分表

17

玩家在线状态表

在线状态明细表

18

数据库关系图

系统用例图

19

注册功能流程图

20

21

登录功能流程图

22

请求实时在线列表流程图

坐下位置流程图

23

准备开始游戏流程图

24

开始游戏流程图

25

重置图片流程图

26

小地图功能流程图

27

聊天流程图

28

29

实时更新图片流程图

30

第5章 详细设计

由于是客户机/服务器模式,因此下列的功能都将是服务器和客户端对应的功能一起讲解

5.1用户注册功能

1、注册如图5.1.1

图5.1.1注册

首先,我们先来查看如何获得用户输入的数据 为了保存用户的数据,我们需要定义变量进行接收: CString m_username; CString m_nicheng; CString m_pass; CString m_two_pass; CString

m_tel;

CTime m_date;

31

int m_men;

接下来是处理和打包数据:

先是判断用户是否有输入数据:

BOOL MyReg::CheckNull() {

UpdateData();

if (m_username.IsEmpty()) { MessageBox(\用户名不能为空!\

m_pEdit = (CEdit*) this->GetDlgItem(IDC_YONGHU); m_pEdit->SetFocus(); return FALSE;

}

if (m_nicheng.IsEmpty()) { MessageBox(\昵称不能为空!\

m_pEdit = (CEdit*) this->GetDlgItem(IDC_NICHENG); m_pEdit->SetFocus(); return FALSE;

}

if (m_pass.IsEmpty()) { MessageBox(\密码不能为空!\

m_pEdit = (CEdit*) this->GetDlgItem(IDC_MIMA); m_pEdit->SetFocus(); return FALSE;

}

if (m_two_pass.IsEmpty()) {

32

MessageBox(\确认的密码不能为空!\

m_pEdit = (CEdit*) this->GetDlgItem(IDC_QUERENMIMA); m_pEdit->SetFocus(); return FALSE;

}

if (m_tel.IsEmpty()) { MessageBox(\电话不能为空!\

m_pEdit = (CEdit*) this->GetDlgItem(IDC_DIANHUA); m_pEdit->SetFocus(); return FALSE;

}

if (m_men == -1) { MessageBox(\性别不能为空!\

m_pEdit = (CEdit*) this->GetDlgItem(IDC_RADIO1); m_pEdit->SetFocus();

return FALSE;

}

return TRUE;

}

如果有输入空的数据,则返回假,正确返回真。

之后是判断数据是否输入正确:

BOOL MyReg::CheckFull()

{ if (!CheckNull())

{ 33

}

return FALSE;

if (m_pass.GetLength() != 5 || m_two_pass.GetLength() != 5) { MessageBox(\密码长度不正确!\

m_pEdit = (CEdit*) this->GetDlgItem(IDC_MIMA); m_pEdit->SetFocus(); m_pass.Empty(); m_two_pass.Empty(); UpdateData(FALSE); return FALSE;

}

if (m_pass != m_two_pass) { MessageBox(\两次输入的密码不正确!\

m_pEdit = (CEdit*) this->GetDlgItem(IDC_MIMA); m_pEdit->SetFocus(); m_pass.Empty(); m_two_pass.Empty(); UpdateData(FALSE); return FALSE;

}

if (m_tel.GetLength() == 7 || m_tel.GetLength() m_tel.GetLength() == 11) { return TRUE;

}

else if (m_tel.GetLength() == 12)

== 8 ||

34

{ if (m_tel.Left(1) != \{ MessageBox(\你输入的电话的第一位不正确,请重新输入!!\ m_pEdit = (CEdit*) this->GetDlgItem(IDC_DIANHUA); m_pEdit->SetFocus(); m_tel.Empty(); UpdateData(FALSE); return FALSE;

}

return TRUE;

} else { MessageBox(\你输入的电话的位数不正确,请重新输入!!\ m_pEdit = (CEdit*) this->GetDlgItem(IDC_DIANHUA); m_pEdit->SetFocus(); m_tel.Empty(); UpdateData(FALSE); return FALSE;

}

return TRUE;

}

当数据都验证成功之后,将调用下面函数发送至服务器端

void MyReg::OnOK() { // TODO: Add extra validation here if (!CheckFull())

{

35

}

return;

REG_DATE m_reg;

memset(&m_reg,0,sizeof(REG_DATE));

strcpy(m_reg.birthday,m_date.Format(\strcpy(m_reg.nicheng,m_nicheng); strcpy(m_reg.password,m_pass); strcpy(m_reg.tel,m_tel);

strcpy(m_reg.user_name,m_username); m_reg.sex = m_men;

char buf[sizeof(REG_DATE) + sizeof(int) + 1]; memset(buf,0,sizeof(buf)); sprintf(buf,\char *p = buf; p += 4;

memcpy(p,&m_reg,sizeof(REG_DATE));

sendto(MySocket::m_socket,buf,sizeof(REG_DATE) + sizeof(int) +

1,0,(sockaddr*)&MySocket::udp_addr,sizeof(sockaddr_in));//这里将数据发送到服务器 }

服务器端:服务器在接受到客户端的信息之后,将调用下面的函数进行处理:

void CMyDlg::Reg_date(LPPER_IO_DATA pData) {

REG_DATE reg = *((REG_DATE*)(m_buf)); CString c_sql; int n;

36

c_sql.Format(\用户名,昵称,密码,性别,生日,电话) values('%s','%s','%s',%d,'%s','%s')\

reg.user_name,reg.nicheng,reg.password,reg.sex,reg.birthday,reg.t

el);

LONG text = m_ado.JExecuteWithoutRecordset(c_sql); //这里调用ADO连接数据库

switch (text) { case 1:

{

RECORDSET rs = m_ado.JExecuteWithRecordset(\MAX(用

if (rs != NULL)

户ID) as id from account\

{ }

CString c_sql;

while (!rs->rsEOF) { ??? }

c_sql.Format(\into account_jifen(用户ID)

values(%d)\

m_ado.JExecuteWithoutRecordset(c_sql); REG_DATE send_reg;

memset(&send_reg,0,sizeof(REG_DATE)); send_reg.id = n; send_reg.flag = EXEC_OK;

char buf[sizeof(int) + sizeof(REG_DATE) + 1] = {0};

37

char* s = buf;

sprintf(buf,\s += 4;

memcpy(s,&send_reg,sizeof(REG_DATE));

sendto(m_sock.GetSock(),buf,sizeof(int)

+

sizeof(REG_DATE) + 1,0,(sockaddr*)&pData->addr,sizeof(sockaddr_in));

} break;

default:

{

REG_DATE send_reg;

send_reg.flag = OTHER_ERROR;

char buf[sizeof(int) + sizeof(REG_DATE) + 1] = {0}; char* s = buf;

sprintf(buf,\s += 4;

memcpy(s,&send_reg,sizeof(REG_DATE));

sendto(m_sock.GetSock(),buf,sizeof(int)

+

sizeof(REG_DATE) + 1,0,(sockaddr*)&pData->addr,sizeof(sockaddr_in)); //这里将注册成功或失败的信息返回给客户端

} }

} break;

38

客户端: 接收到服务器端发送回来的信息之后将成功或失败的信息显示出来,如果失败,将需要用户继续输入,如果成功,将提示成功信息,并返回到登陆界面。

LRESULT MyReg::OnUserReg(WPARAM wParam,LPARAM lParam) {

?????.. { CString str;

str.Format(\注册成功\\r\\n登陆ID为:%d\ MessageBox(str);

} else { MessageBox(\注册失败\ m_username = _T(\ m_nicheng = _T(\ m_pass = _T(\ m_two_pass = _T(\ m_tel = _T(\

m_date = CTime::GetCurrentTime(); m_men = -1; UpdateData(FALSE);

m_pEdit = (CEdit*) this->GetDlgItem(IDC_YONGHU); m_pEdit->SetFocus(); return 1; }

MyGlobalVariable*

m_glb

MyGlobalVariable::GetMyGlobalVariable();

=

39

::SendMessage(m_glb->GetLoginHwnd(),USER_MSG,(unsigned int)&m_reg.id,NULL);

CDialog::OnOK(); return 0; }

注册成功的界面

5. 2登录页面

40

1、登录页面如图5.1.2

图5.1.2登录截图

首先定义2个变量接受用户输入的账号和密码的信息,定义如下: CString m_id; CString m_mima;

当用户点击了登陆界面之后,将调用以下函数进行处理: void MyLogin::OnOK()

{ // TODO: Add extra validation here UpdateData(); LOGIN_DATE m_log;

memset(&m_log,0,sizeof(LOGIN_DATE)); m_log.user_name = atoi(m_id); strcpy(m_log.password,m_mima);

char buf[sizeof(LOGIN_DATE) + sizeof(int) + 1]; memset(buf,0,sizeof(buf));

sprintf(buf,\ 41

char *p = buf; p += 4;

memcpy(p,&m_log,sizeof(LOGIN_DATE));

sendto(MySocket::m_socket,buf,sizeof(LOGIN_DATE) + sizeof(int) +

1,0,(sockaddr*)&MySocket::udp_addr,sizeof(sockaddr_in)); //这里将用户输入的数据发送到服务器端 }

服务器端:当服务器收到用户提交的登录请求之后,将调用以下函数查询数据库并返回成功或失败的信息

void CMyDlg::Lonin_date(LPPER_IO_DATA pData) {

LOGIN_DATE m_log;

memset(&m_log,0,sizeof(LOGIN_DATE)); m_log = *((LOGIN_DATE*)m_buf); CString str;

str.Format(\个数 FROM account where 用户ID

= %d and 密码 = '%s'\

RECORDSET flag = m_ado.JExecuteWithRecordset(str); int n = 0; if (flag != NULL) { }

if (n == 1)

//账号和密码正确

while (!flag->rsEOF) { }

n = GIF(flag,\个数\flag->MoveNext();

42

{

int a = 0;

str.Format(\count(*) as 个数 from account_zaixian

where 用户ID = %d\

sendto(m_sock.GetSock(),buf,10,0,(sockaddr*)&pData->addr,sizeo

RECORDSET rs = m_ado.JExecuteWithRecordset(str); if (rs != NULL) { }

if (a == 1) {

char buf[10] = {0};

sprintf(buf,\while (!rs->rsEOF) { }

a = GIF(rs,\个数\rs->MoveNext();

f(sockaddr_in));

}

str.Format(\用户ID as ID,a.昵称 as 昵称,b.积分 as

return ;

积分 from account as a, account_jifen as b where a.用户ID = %d and a.用户ID = b.用户ID\

rs = m_ado.JExecuteWithRecordset(str); XINXI m_xinxi = GetXinxi(rs);

char buf[sizeof(int) + sizeof(XINXI) + 1] = {0};

43

sprintf(buf,\char *p = buf; p += 4;

memcpy(p,&m_xinxi,sizeof(XINXI));

sendto(m_sock.GetSock(),buf,sizeof(int) + sizeof(XINXI) +

//客户端保存

1,0,(sockaddr*)&pData->addr,sizeof(sockaddr_in)); 相应的数据;

char arr[10] = {0};

sprintf(arr,\

sendto(m_sock.GetSock(),arr,10,0,(sockaddr*)&pData->addr,sizeo

f(sockaddr_in));

char buf1[sizeof(int) + sizeof(XINXI) + 1] = {0}; sprintf(buf1,\p = buf1; p += 4;

memcpy(p,&m_xinxi,sizeof(XINXI));

for (ADDRIT it = m_addr.begin(); it != m_addr.end(); ++it) {

sendto(m_sock.GetSock(),buf1,sizeof(int) + sizeof(XINXI)

+ 1,0,(sockaddr*)&(*it),sizeof(sockaddr_in));

/******************更新list控件*****************/ rs = NULL;

}

m_addr.push_back(pData->addr);

44

str.Format(\用户ID as ID, a.昵称 as 昵称,a.积分 as

积分,b.在线状态 as 状态 from account_zaixian as a, account_zhuangtai as b where a.用户ID = %d and a.在线ID = b.在线ID\

rs = m_ado.JExecuteWithRecordset(str); UpdateList(rs);

CTime t = CTime::GetCurrentTime(); CString str,m_xianshi_xinxi,str1; str = t.Format(\str1.Format(\

d

线

!!

\\r\\n\

sendto(m_sock.GetSock(),buf,10,0,(sockaddr*)&pData->addr,sizeo } else {

char buf[10] = {0};

sprintf(buf,\m_xinxi_xianshi.ReplaceSel(str1); m_xinxi_xianshi.SetSel(-1,-1);

f(sockaddr_in)); }

客户端:当收到服务器端处理完毕的数据之后,将调用下面函数进行处理。成功之后将显示游戏大厅界面。 {

int log = atoi((char*)wParam);

LRESULT MyLogin::OnUserLog(WPARAM wParam,LPARAM lparm)

}

45

delete [] (char*)wParam;

if (log == EXEC_OK) //账号密码验证成功 { MySysCfg::Set_old_user(m_id);

MySysCfg::write_to_old_file();

// memcpy(m_id,m_id,m_id.GetLength());

MyGlobalVariable*

m_glb

MyGlobalVariable::GetMyGlobalVariable(); m_glb->SetLoginHwnd(NULL); CDialog::OnOK(); return 0;

}

if (log == LOGIN_ERROR) { MessageBox(\您输入的用户名或密码不正确,请您重新输入!\ m_id = \ m_mima = \ UpdateData(FALSE);

CEdit* pEdit = (CEdit*) this->GetDlgItem(IDC_YONGHU); pEdit->SetFocus(); return 0;

}

if (log == REPEAT_LOGIN) { MessageBox(\您输入的用户名已经登录,请您重新输入!\ m_id = \ m_mima = \

UpdateData(FALSE);

=

46

}

CEdit* pEdit = (CEdit*) this->GetDlgItem(IDC_YONGHU); pEdit->SetFocus(); return 0;

return 0; }

47

5.3游戏大厅

客户端的大厅界面如图5.2.1

图5.2.1大厅界面

界面左边是选择游戏大厅的界面,这个功能不需要连接服务器,相关的显示函数如下:

void CMyDlg::InitTreeText() //初始化控件信息 { }

m_tree.DeleteAllItems(); HTREEITEM root; HTREEITEM root1;

root = m_tree.InsertItem(\连连看\m_tree.SetItemData(root,0);

root1 = m_tree.InsertItem(\连连看一区\m_tree.SetItemData(root1,1);

48

void CMyDlg::OnDblclkTree1(NMHDR* pNMHDR, LRESULT* pResult) //选择

房间

{ // TODO: Add your control notification handler code here POINT point;

GetCursorPos(&point); UINT uFlags;

m_tree.ScreenToClient(&point);

HTREEITEM hItem = m_tree.HitTest(point, &uFlags);

if ((hItem != NULL) && (TVHT_ONITEM & uFlags)) { int i = m_tree.GetItemData(hItem); if (i == 1) { if (m_bool == FALSE) { CString str;

str = m_tree.GetItemText(hItem); m_tab.InsertItem(1, str, 0); m_tab.SetCurSel(1);

m_fangjian = new MyFangjian();

m_fangjian->Create(IDD_FANGJIAN,&m_tab); m_sum++; m_bool = TRUE; DoTab(m_sum);

}

else

49

}

}

{

MessageBox(\你已经开启房间了\

}

}

*pResult = 0;

界面中间的窗体显示的是游戏中积分排名前10名的玩家的信息,相关的函数如下:

char buf[sizeof(int) + 1];

memset(buf,0,sizeof(buf)); sprintf(buf,\sendto(MySocket::m_socket,buf,sizeof(int)

+ // 向

1,0,(sockaddr*)&MySocket::udp_addr,sizeof(sockaddr_in)); 服务器请求列表数据

服务器端:服务器在接受到客户端的请求之后,调用函数查询数据库并返回结果集:

void CMyDlg::Request_date(LPPER_IO_DATA pData) {

char buf[DATA_SIZE] = {0}; int x = 0;

RECORDSET rs = m_ado.JExecuteWithRecordset(\昵称 as 昵

称,a.积分 as 积分,b.在线状态 as 状态 from account_zaixian as a, account_zhuangtai as b where a.在线ID = b.在线ID\

x = Pack_date(rs,buf);

50

char arr[DATA_SIZE] = {0};

sprintf(arr,\char *p = arr; p += 8;

memcpy(p,buf,sizeof(XINXI) * x);

sendto(m_sock.GetSock(),arr,sizeof(XINXI)

*

x

+

8,0,(sockaddr*)&pData->addr,sizeof(sockaddr_in));// 将信息发送回客户端 }

int CMyDlg::Pack_date(RECORDSET rs,char *buf) //检索信息 {

int n = 0;

CString m_nicheng,m_zhuangtai; int m_jifen; XINXI m_xinxi; char *p = buf; if (rs != NULL) {

while (!rs->rsEOF) {

memset(&m_xinxi,0,sizeof(XINXI)); m_jifen = GIF(rs,\积分\m_nicheng = GTF(rs,\昵称\m_zhuangtai = GTF(rs,\状态\strcpy(m_xinxi.nicheng,m_nicheng); strcpy(m_xinxi.zhuangtai,m_zhuangtai); m_xinxi.jifne = m_jifen;

51

}

}

}

memcpy(p,&m_xinxi,sizeof(XINXI)); p += sizeof(XINXI); n++;

rs->MoveNext();

return n;

客户端:客户端在接受到服务器发送回来的玩家信息的数据之后,调用下面的函数进行处理:

LRESULT MyDating::OnUserUpdateList(WPARAM wParam,LPARAM lparm) {

m_list.DeleteAllItems(); UPDATELIST m_updatelist;

memset(&m_updatelist,0,sizeof(m_updatelist)); int x = 0;

char arr[10] = {0}; char *p = (char*)wParam; memcpy(arr,p,4); p += 4; x = atoi(arr);

for (int i = 0; i < x; ++i) {

memcpy((char*)&m_updatelist,p,sizeof(UPDATELIST)); p += sizeof(UPDATELIST); m_list.InsertItem(i,\

m_list.SetItemText(i,0,m_updatelist.m_id);

//显示信息

52

}

}

m_list.SetItemText(i,1,m_updatelist.m_nicheng); m_list.SetItemText(i,2,m_updatelist.m_jifen);

m_list.Invalidate(); return 0;

界面右边的是当前在线的玩家以及聊天的信息,首先我们演示的是在线列表,代码如下:

服务器端:首先客户端登录成功之后服务器端向其他客户端下发有人登陆的指令以及数据,

char buf1[sizeof(int) + sizeof(XINXI) + 1] = {0};

sprintf(buf1,\p = buf1; p += 4;

memcpy(p,&m_xinxi,sizeof(XINXI));

for (ADDRIT it = m_addr.begin(); it != m_addr.end(); ++it) {

sendto(m_sock.GetSock(),buf1,sizeof(int) + sizeof(XINXI)

+ 1,0,(sockaddr*)&(*it),sizeof(sockaddr_in));

}

客户端收到服务器发送的信息之后显示在线列表:

LRESULT CMyDlg::OnUserDating(WPARAM wParam,LPARAM lparm) list控件信息 {

m_list.DeleteAllItems(); m_flag = 0; char buf[10] = {0};

char arr1[sizeof(XINXI) + 1] = {0};

//更新

53

char *p = (char*)wParam; XINXI m_xinxi; memcpy(buf,p,4); p += 4;

memset(&m_xinxi,0,sizeof(XINXI)); CString a;

for (int i = 0;i < atoi(buf);i++) { memcpy(arr1,p,sizeof(XINXI)); p += sizeof(XINXI); m_xinxi = *((XINXI*)arr1); m_list.InsertItem(i, \ a.Format(\

m_list.SetItemText(i, 0, m_xinxi.nicheng); m_list.SetItemText(i, 1, a);

m_list.SetItemText(i, 2, m_xinxi.zhuangtai);

}

m_flag = i;

m_list.Invalidate(); delete [] (char*)wParam; return 0;

}

接下来我们显示的是聊天的实现:

客户端:首先玩家先将一条信息发送到服务器端: void CMyDlg::OnButton1() {

// TODO: Add your control notification handler code here

54

MyGlobalVariable *m_glb =

MyGlobalVariable::GetMyGlobalVariable();

UpdateData(); char buf[1024] = {0}; sprintf(buf,\

说: %s\

m_fasong = \UpdateData(FALSE);

sendto(MySocket::m_socket,buf,strlen(buf),0,(sockaddr*)&MySock

et::udp_addr,sizeof(sockaddr_in)); }

服务器端在收到客户端的信息之后,将这条信息群发到连接到服务器上的所有客户端:

void CMyDlg::Qunliao_date(LPPER_IO_DATA pData) {

char *buf = new char[15 + strlen(m_buf)]; memset(buf,0,sizeof(buf)); sprintf(buf,\

+

CEdit* pEdit = (CEdit*) this->GetDlgItem(IDC_FASONG); pEdit->SetFocus();

strlen(m_buf),QUNLIAO_DATE,m_buf); }

客户端在接收到服务器的聊天信息之后,将信息显示到聊天窗口中: LRESULT CMyDlg::OnUserQunliao(WPARAM wParam,LPARAM lparm) {

UpdateData();

m_xianshi.ReplaceSel((char*)wParam); m_pushdeque.push_back(buf);

55

}

m_xianshi.ReplaceSel(\m_xianshi.SetSel(-1,-1); delete [](char*)wParam; //UpdateData(FALSE); return 0;

56

5.4游戏房间

1、客户端的游戏房间界面如图5.2.2

图5.2.2游戏房间

我们先来查看自动寻位的功能:

当玩家点击自动寻位的功能之后,系统会自动选择一个空闲的位置并让玩家坐下,同时向服务器发送位置已经坐下的信息: void MyFangjian::OnButton7() {

// TODO: Add your control notification handler code here if (m_zhuozi == 1) { }

if (m_user1 == 0) {

57

return;

OnButton1(); return;

}

if (m_user2 == 0) { OnButton2(); return;

}

if (m_user3 == 0) { OnButton3(); return; }

if (m_user4 == 0) { OnButton4(); return; }

if (m_user5 == 0) { OnButton5(); return; }

if (m_user6 == 0) { OnButton6(); return; }

58

}

void MyFangjian::OnButton6() {

// TODO: Add your control notification handler code here if (m_zhuozi == 1) { }

if (m_user6 == 1) { }

m_flag = 6; char buf[10];

memset(buf,0,sizeof(buf));

sprintf(buf,\

sendto(MySocket::m_socket,buf,10,0,(sockaddr*)&MySocket::udp_a

MessageBox(\该位置已经有人坐了,请不要重复坐下!\return;

MessageBox(\游戏已经开始,不能坐下!\return;

ddr,sizeof(sockaddr_in));

char arr1[sizeof(int) + sizeof(int)] = {0}; sprintf(arr1,\MyYouxi::GetWeizhi(m_flag); MyYouxi m_youxi; m_youxi.DoModal();

59

sendto(MySocket::m_socket,arr1,sizeof(int) +

sizeof(int),0,(sockaddr*)&MySocket::udp_addr,sizeof(sockaddr_in)); }

void MyFangjian::OnButton1() {

// TODO: Add your control notification handler code here if (m_zhuozi == 1) { }

if (m_user1 == 1) { }

m_flag = 1; char buf[10];

memset(buf,0,sizeof(buf));

sprintf(buf,\

sendto(MySocket::m_socket,buf,10,0,(sockaddr*)&MySocket::udp_a

MessageBox(\该位置已经有人坐了,请不要重复坐下!\return;

MessageBox(\游戏已经开始,不能坐下!\return; m_flag = 0;

ddr,sizeof(sockaddr_in));

MyYouxi::GetWeizhi(m_flag); MyYouxi m_youxi;

60

m_youxi.DoModal();

char arr1[sizeof(int) + sizeof(int)] = {0}; sprintf(arr1,\sendto(MySocket::m_socket,arr1,sizeof(int)

+

sizeof(int),0,(sockaddr*)&MySocket::udp_addr,sizeof(sockaddr_in)); m_flag = 0;

}

void MyFangjian::OnButton2() { // TODO: Add your control notification handler code here if (m_zhuozi == 1) { MessageBox(\游戏已经开始,不能坐下!\ return; }

if (m_user2 == 1) { MessageBox(\该位置已经有人坐了,请不要重复坐下!\ return;

}

???????????..

MyYouxi::GetWeizhi(m_flag); MyYouxi m_youxi; m_youxi.DoModal();

char arr1[sizeof(int) + sizeof(int)] = {0};

61

sprintf(arr1,\sendto(MySocket::m_socket,arr1,sizeof(int)

+

sizeof(int),0,(sockaddr*)&MySocket::udp_addr,sizeof(sockaddr_in)); }

void MyFangjian::OnButton3() {

// TODO: Add your control notification handler code here if (m_zhuozi == 1) { }

if (m_user3 == 1) { }

m_flag = 3; char buf[10];

memset(buf,0,sizeof(buf));

sprintf(buf,\

sendto(MySocket::m_socket,buf,10,0,(sockaddr*)&MySocket::udp_a

MessageBox(\该位置已经有人坐了,请不要重复坐下!\return;

MessageBox(\游戏已经开始,不能坐下!\return; m_flag = 0;

ddr,sizeof(sockaddr_in));

MyYouxi::GetWeizhi(m_flag); MyYouxi m_youxi;

62

m_youxi.DoModal();

char arr1[sizeof(int) + sizeof(int)] = {0}; sprintf(arr1,\sendto(MySocket::m_socket,arr1,sizeof(int)

+

sizeof(int),0,(sockaddr*)&MySocket::udp_addr,sizeof(sockaddr_in)); m_flag = 0;

}

void MyFangjian::OnButton4() { // TODO: Add your control notification handler code here if (m_zhuozi == 1) { MessageBox(\游戏已经开始,不能坐下!\ return; }

if (m_user4 == 1) { MessageBox(\该位置已经有人坐了,请不要重复坐下!\ return;

}

m_flag = 4; char buf[10];

memset(buf,0,sizeof(buf));

sprintf(buf,\

63

sendto(MySocket::m_socket,buf,10,0,(sockaddr*)&MySocket::udp_a

ddr,sizeof(sockaddr_in));

char arr1[sizeof(int) + sizeof(int)] = {0}; sprintf(arr1,\sendto(MySocket::m_socket,arr1,sizeof(int)

+

MyYouxi::GetWeizhi(m_flag); MyYouxi m_youxi; m_youxi.DoModal();

sizeof(int),0,(sockaddr*)&MySocket::udp_addr,sizeof(sockaddr_in)); }

void MyFangjian::OnButton5() {

// TODO: Add your control notification handler code here if (m_zhuozi == 1) { }

if (m_user5 == 1) { }

m_flag = 5; char buf[10];

MessageBox(\该位置已经有人坐了,请不要重复坐下!\return;

MessageBox(\游戏已经开始,不能坐下!\return; m_flag = 0;

64

memset(buf,0,sizeof(buf));

sprintf(buf,\

sendto(MySocket::m_socket,buf,10,0,(sockaddr*)&MySocket::udp_a

ddr,sizeof(sockaddr_in));

char arr1[sizeof(int) + sizeof(int)] = {0}; sprintf(arr1,\sendto(MySocket::m_socket,arr1,sizeof(int)

+

MyYouxi::GetWeizhi(m_flag); MyYouxi m_youxi; m_youxi.DoModal();

sizeof(int),0,(sockaddr*)&MySocket::udp_addr,sizeof(sockaddr_in)); }

m_flag = 0;

5.5游戏准备界面

1、客户端的游戏准备界面如图5.2.3

65

图5.2.3游戏准备界面

2、我们来查看开始按钮的功能实现,首先当用户点击开始的按钮之后,系统向服务器发送游戏准备的指令,当服务器接受到指令之后,将判断是否是2个及2个以上的玩家点击了准备的按钮,如果是的话,服务器将向准备的客户端发送游戏开始的命令。 void MyYouxi::OnBtnStart() {

// TODO: Add your control notification handler code here char buf[10] = {0};

sprintf(buf,\

sendto(MySocket::m_socket,buf,10,0,(sockaddr*)&MySocket::udp_a

ddr,sizeof(sockaddr_in));

m_kaishiButton.EnableWindow(FALSE);

m_kaishiButton.LoadBitmaps(IDB_KAISHI_WUXIAO);

66

m_kaishiButton.Invalidate(); m_kaishiButton.SizeToContent();

m_lianxiButton.EnableWindow(FALSE);

m_lianxiButton.LoadBitmaps(IDB_LIANXI_WUXIAO); m_lianxiButton.Invalidate(); m_lianxiButton.SizeToContent();

}

服务器端代码实现:

void CMyDlg::Zhunbei_date(LPPER_IO_DATA pData) { int n = atoi(m_buf); char *buf = new char[15]; memset(buf,0,sizeof(buf));

sprintf(buf,\ switch (n) { case 1: m_fangjian.m_user1_jushou = 1; m_zhunbei++;

break;

case 2: m_fangjian.m_user2_jushou = 1; m_zhunbei++;

break;

case 3:

m_fangjian.m_user3_jushou = 1;

67

m_zhunbei++;

break;

case 4: m_fangjian.m_user4_jushou = 1; m_zhunbei++;

break;

case 5: m_fangjian.m_user5_jushou = 1; m_zhunbei++;

break;

case 6: m_fangjian.m_user6_jushou = 1; m_zhunbei++; break;

}

m_pushdeque.push_back(buf);

if ((m_youxi > 1) && (m_youxi == m_zhunbei)) { m_zhunbei = 0; RandomMap();

char *buf1 = new char[450]; memset(buf1,0,sizeof(buf1));

sprintf(buf1,\ char *p = buf1; p += 8;

memcpy(p,&m_map,sizeof(int) * 96);

m_pushdeque.push_back(buf1);

68

char *buf2 = new char[sizeof(XIAOTUWEIZHI) + 20] ; memset(buf2,0,sizeof(buf2));

sprintf(buf2,\

+

20,XIAOTU_KAISHI);

sprintf(buf6,\

m_fangjian.m_user1_jushou = 0; //位置1是否举手 m_fangjian.m_user2_jushou = 0; m_fangjian.m_user3_jushou = 0; m_fangjian.m_user4_jushou = 0; m_fangjian.m_user5_jushou = 0; m_fangjian.m_user6_jushou = 0;

m_fangjian.m_zhuozi = 1; char *buf6 = new char[50]; memset(buf6,0,sizeof(buf6));

char *p1 = buf2; p1 += 8;

memcpy(p1,&m_zuoxiaweizhi,sizeof(XIAOTUWEIZHI)); m_pushdeque.push_back(buf2);

zi);

m_pushdeque.push_back(buf6);}

5.6游戏界面

1、客户端的游戏开始界面如图5.2.4

69

图5.2.4游戏开始界面

2、首先我们来看显示图片的功能实现,客户端的代码如下: void MyYouxi::InitBitmap() //初始化游戏图片数组 {

CDC *pdc = GetDC(); CDC mdc; CDC dctext;

CBitmap m_bitmap1,m_bittext; mdc.CreateCompatibleDC(pdc); dctext.CreateCompatibleDC(pdc);

m_bittext.CreateCompatibleBitmap(pdc,33,38);

m_bitmap1.m_hObject = (HBITMAP)::LoadImage(NULL,\游戏

\\\\tuxing.bmp\

mdc.SelectObject(m_bitmap1);

70

}

dctext.SelectObject(m_bittext); POINT m_pt = {0};

for (int i = 0;i < 48;i++) { }

int s = 0;

for (i = 0;i< 3;i++) { }

for (int j = 0;j < 16;j++) { }

m_pt.y = 0; m_pt.x += 33;

dctext.SelectObject(m_ver[s]);

dctext.BitBlt(0,0,33,38,&mdc,m_pt.x,m_pt.y,SRCCOPY); s++;

m_pt.y += 38;

m_ver[i].CreateCompatibleBitmap(pdc,33,38);

LRESULT MyYouxi::OnUserYouxiKaishi(WPARAM wParam,LPARAM lparm) //游戏图片贴图 {

memcpy((char*)m_map,(char*)wParam,sizeof(int) * 96); delete [](char*)wParam;

71

);

m_chongzhiButton.EnableWindow(TRUE);

m_chongzhiButton.LoadBitmaps(IDB_CHONGZHI_UP,IDB_CHONGZHI_DOWN

m_chongzhiButton.Invalidate(); m_chongzhiButton.SizeToContent();

m_buttonFlag = 0;

memset(m_sum,-1,sizeof(m_sum)); m_sumVer.clear();

CDC *pdc = GetDC(); size_x = 0; CDC mdc;

mdc.CreateCompatibleDC(pdc); CBitmap m_bit;

m_bit.m_hObject=(HBITMAP)::LoadImage(NULL,\

GE_BITMAP,800,600,LR_LOADFROMFILE);

if (m_mdc.m_hDC == NULL) { }

m_mdc.SelectObject(m_bit);

//m_sdc.BitBlt(0,0,612,562,&m_mdc,0,29,SRCCOPY); //SetTimer(2,1,NULL);

WaitForSingleObject(hmutex,INFINITE);

m_dcmem.BitBlt(0,29,612,562,&m_mdc,0,29,SRCCOPY); ReleaseMutex(hmutex);

m_mdc.CreateCompatibleDC(pdc);

72

InvalidateRect(CRect(0,29,612,562 + 29),FALSE);

if (m_xiaotuDC.m_hDC == NULL) { m_xiaotuDC.CreateCompatibleDC(pdc);

m_xiaotubitmap.CreateCompatibleBitmap(pdc,8,8); m_xiaotuDC.SelectObject(m_xiaotubitmap);

}

m_xiaotuDC.BitBlt(0,0,8,8,&m_dcmem,48,58,SRCCOPY); OnKaishi1();

return 0;

}

void MyYouxi::RandomMap() //图片排列

{ CDC *pdc = GetDC(); CDC mdc,dc1;

mdc.CreateCompatibleDC(pdc); dc1.CreateCompatibleDC(pdc); CBitmap bit;

bit.CreateCompatibleBitmap(pdc,396,304); dc1.SelectObject(bit);

int i,j; POINT pt; pt.x = 0; pt.y = 0;

int max = 0;

73

int n = 0;

int num = 0;//随机产生的单个地图的编号

/******************随机生成地图*********************/ for (i = 1;i < 9;i++) { }

m_dcmem.BitBlt(96,221,396,304,&dc1,0,0,SRCCOPY);

InvalidateRect(CRect(m_pt.x,m_pt.y,m_pt.x + (j - 1) * 33,m_pt.y

for (j = 1;j < 13;j++) { }

pt.x = 0; pt.y += 38;

num = m_map[max];

mdc.SelectObject(m_ver[num]);

dc1.BitBlt(pt.x,pt.y,33,38,&mdc,0,0,SRCCOPY); pt.x += 33; m_sum[i][j] = num; max++;

+ (i - 1) * 38),FALSE); }

之后我们来查看小地图的功能实现,我们在游戏中能够实时的查看到其他玩家的游戏进度,这个功能是由以下几个函数配合来实现的: 首先是当玩家消除了2个图形之后,需要向服务器发送数据 char buf4[1024] = {0};

POINT m_fasongOld,m_fasongNew; m_fasongOld.x = m_old.x - 1;

74

m_fasongOld.y = m_old.y - 1; m_fasongNew.x = m_new.x -1; m_fasongNew.y = m_new.y - 1;

sprintf(buf4,\char *p1 = buf4; p1 += 8;

memcpy(p1,&m_fasongOld,sizeof(POINT)); p1 += sizeof(POINT);

memcpy(p1,&m_fasongNew,sizeof(POINT));

sendto(MySocket::m_socket,buf4,sizeof(buf4),0,(sockaddr*)&MySo

cket::udp_addr,sizeof(sockaddr_in));

之后服务器接收到客户端的数据之后,将数据群发到其他正在游戏的客户端:

void CMyDlg::Xiaotu_date(LPPER_IO_DATA pData) { }

当其他的客户端接收到信息之后,将更新小地图的显示,代码如下: LRESULT MyYouxi::OnUserXiaotu(WPARAM wParam,LPARAM lparm) {

char *p = (char *)wParam;

char *buf = new char[100 + sizeof(POINT) * 2]; memset(buf,0,sizeof(buf));

sprintf(buf,\char *p = buf; p += 8;

memcpy(p,m_buf,sizeof(POINT) * 2 + 5); m_pushdeque.push_back(buf);

75

char buf[5] = {0};

memcpy(buf,(char *)wParam,4); int x = atoi(buf); p += 4;

POINT m_jieshouOld,m_jieshouNew;

memcpy((char*)&m_jieshouOld,p,sizeof(POINT)); p += sizeof(POINT);

memcpy((char*)&m_jieshouNew,p,sizeof(POINT)); delete [](char*)wParam; if (x == m_weizhi) { }

x = BIJIAO(x,m_weizhi); switch (x) { case 1:

{

WaitForSingleObject(hmutex,INFINITE);

m_dcmem.BitBlt(m_p1.x + m_jieshouOld.x * 8,m_p1.y + return 0;

m_jieshouOld.y * 8,8,8,&m_xiaotuDC,0,0,SRCCOPY);

ReleaseMutex(hmutex);

InvalidateRect(CRect(m_p1.x + m_jieshouOld.x * 8,m_p1.y +

m_jieshouOld.y * 8,m_p1.x + m_jieshouOld.x * 8 + 8,m_p1.y + m_jieshouOld.y * 8 + 8),FALSE);

WaitForSingleObject(hmutex,INFINITE);

m_dcmem.BitBlt(m_p1.x + m_jieshouNew.x * 8,m_p1.y +

m_jieshouNew.y * 8,8,8,&m_xiaotuDC,0,0,SRCCOPY);

76

ReleaseMutex(hmutex);

InvalidateRect(CRect(m_p1.x + m_jieshouNew.x * 8,m_p1.y +

m_jieshouNew.y * 8,m_p1.x + m_jieshouNew.x * 8 + 8,m_p1.y + m_jieshouNew.y * 8 + 8),FALSE);

} break;

case 2:

{

WaitForSingleObject(hmutex,INFINITE);

m_dcmem.BitBlt(m_p2.x + m_jieshouOld.x * 8,m_p2.y +

m_jieshouOld.y * 8,8,8,&m_xiaotuDC,0,0,SRCCOPY);

ReleaseMutex(hmutex);

InvalidateRect(CRect(m_p2.x + m_jieshouOld.x * 8,m_p2.y +

m_jieshouOld.y * 8,m_p2.x + m_jieshouOld.x * 8 + 8,m_p2.y + m_jieshouOld.y * 8 + 8),FALSE);

WaitForSingleObject(hmutex,INFINITE);

m_dcmem.BitBlt(m_p2.x + m_jieshouNew.x * 8,m_p2.y +

m_jieshouNew.y * 8,8,8,&m_xiaotuDC,0,0,SRCCOPY);

ReleaseMutex(hmutex);

InvalidateRect(CRect(m_p2.x + m_jieshouNew.x * 8,m_p2.y +

m_jieshouNew.y * 8,m_p2.x + m_jieshouNew.x * 8 + 8,m_p2.y + m_jieshouNew.y * 8 + 8),FALSE);

} break;

case 3:

{

WaitForSingleObject(hmutex,INFINITE);

m_dcmem.BitBlt(m_p3.x + m_jieshouOld.x * 8,m_p3.y +

m_jieshouOld.y * 8,8,8,&m_xiaotuDC,0,0,SRCCOPY);

77

ReleaseMutex(hmutex);

InvalidateRect(CRect(m_p3.x + m_jieshouOld.x * 8,m_p3.y +

m_jieshouOld.y * 8,m_p3.x + m_jieshouOld.x * 8 + 8,m_p3.y + m_jieshouOld.y * 8 + 8),FALSE);

WaitForSingleObject(hmutex,INFINITE);

m_dcmem.BitBlt(m_p3.x + m_jieshouNew.x * 8,m_p3.y +

m_jieshouNew.y * 8,8,8,&m_xiaotuDC,0,0,SRCCOPY);

ReleaseMutex(hmutex);

InvalidateRect(CRect(m_p3.x + m_jieshouNew.x * 8,m_p3.y +

m_jieshouNew.y * 8,m_p3.x + m_jieshouNew.x * 8 + 8,m_p3.y + m_jieshouNew.y * 8 + 8),FALSE);

} break;

case 4:

{

WaitForSingleObject(hmutex,INFINITE);

m_dcmem.BitBlt(m_p4.x + m_jieshouOld.x * 8,m_p4.y +

m_jieshouOld.y * 8,8,8,&m_xiaotuDC,0,0,SRCCOPY);

ReleaseMutex(hmutex);

InvalidateRect(CRect(m_p4.x + m_jieshouOld.x * 8,m_p4.y +

m_jieshouOld.y * 8,m_p4.x + m_jieshouOld.x * 8 + 8,m_p4.y + m_jieshouOld.y * 8 + 8),FALSE);

WaitForSingleObject(hmutex,INFINITE);

m_dcmem.BitBlt(m_p4.x + m_jieshouNew.x * 8,m_p4.y +

m_jieshouNew.y * 8,8,8,&m_xiaotuDC,0,0,SRCCOPY);

ReleaseMutex(hmutex);

InvalidateRect(CRect(m_p4.x + m_jieshouNew.x * 8,m_p4.y +

m_jieshouNew.y * 8,m_p4.x + m_jieshouNew.x * 8 + 8,m_p4.y + m_jieshouNew.y * 8 + 8),FALSE);

78

} break;

case 5:

{

WaitForSingleObject(hmutex,INFINITE);

m_dcmem.BitBlt(m_p5.x + m_jieshouOld.x * 8,m_p5.y +

m_jieshouOld.y * 8,8,8,&m_xiaotuDC,0,0,SRCCOPY);

ReleaseMutex(hmutex);

InvalidateRect(CRect(m_p5.x + m_jieshouOld.x * 8,m_p5.y +

m_jieshouOld.y * 8,m_p5.x + m_jieshouOld.x * 8 + 8,m_p5.y + m_jieshouOld.y * 8 + 8),FALSE); }

在游戏编写与调试的过程中,我在遇到了了几个问题。

首先是游戏同时开始的问题,因为一个客户端是不能进行游戏的,需要2个及2个以上的玩家才能开始游戏,这里就存在一个游戏同步的问题,这里我是采用在服务器端进行判断,当服务器端判断可以开始游戏之后,将由服务器下达游戏开始的命令,这样就可以解决游戏同步的问题。相关代码如下: if ((m_youxi > 1) && (m_youxi == m_zhunbei))

{

m_zhunbei = 0; RandomMap();

char *buf1 = new char[450]; memset(buf1,0,sizeof(buf1)); }

return 0;

????????.. } break;

79

sprintf(buf1,\ char *p = buf1; p += 8;

memcpy(p,&m_map,sizeof(int) * 96);

m_pushdeque.push_back(buf1);

char *buf2 = new char[sizeof(XIAOTUWEIZHI) + 20] ; memset(buf2,0,sizeof(buf2));

sprintf(buf2,\

20,XIAOTU_KAISHI); char *p1 = buf2; p1 += 8;

memcpy(p1,&m_zuoxiaweizhi,sizeof(XIAOTUWEIZHI));

m_pushdeque.push_back(buf2);

m_fangjian.m_user1_jushou = 0; //位置1是否举手 m_fangjian.m_user2_jushou = 0; m_fangjian.m_user3_jushou = 0; m_fangjian.m_user4_jushou = 0; m_fangjian.m_user5_jushou = 0; m_fangjian.m_user6_jushou = 0;

m_fangjian.m_zhuozi = 1; char *buf6 = new char[50];

memset(buf6,0,sizeof(buf6)); +

80

sprintf(buf6,\

zi); }

DWORD WINAPI ThreadProc2(LPVOID lpParameter) {

for (ADDRIT it = m_addr.begin(); it != m_addr.end(); ++it) {

CMyDlg *p = (CMyDlg *)lpParameter; while (1) {

char buf1[5] = {0}; memcpy(buf1,buf,4); char *q = buf; q += 4;

if (m_pushdeque.size() == 0) { }

char *buf = m_pushdeque.front();//取出头部第一个元素, m_pushdeque.pop_front();//删除头部第一个元素,

Sleep(10); continue;

}

m_pushdeque.push_back(buf6);

81

int ret =

sendto(p->m_sock.GetSock(),q,atoi(buf1),0,(sockaddr*)&(*it),sizeof(sockaddr_in)); }

其次是游戏图片同步的问题,因为是多人游戏,那么就必须让每一个玩家的图片都必须一样,这里,我还是采用在服务器端进行处理,由服务器端统一出一个图片显示的数组,之后分发给其他的客户端,功能实现如下: void CMyDlg::RandomMap() {

vector ver; int i,j,num;

for (i = 0;i < 6;i++) { }

srand(time(NULL));

for (j = 0;j < 16;j++) { }

ver.push_back(j);

}

return 0;

delete []buf; }

if (ret == SOCKET_ERROR)

TRACE(\

TRACE(\

82

}

int road,road1;

for(i = 0; i < 96; ++i) { }

road = rand(); road1 = rand();

num = (road * road1) % ver.size(); m_map[i] = ver[num]; ver.erase(ver.begin()+num);

最后是游戏结束的问题,当有玩家已经将图片给消除完毕之后,其他玩家需要知道这局游戏已经结束了,这就需要先结束的客户端将信息发送到服务器,由服务器来通知游戏结束的信息。 首先是客户端发送结束命令,代码如下: if (p->m_lianjishu == 0)

sendto(MySocket::m_socket,buf1,10,0,(sockaddr*)&MySocket::udp_{

char buf1[10] = {0};

sprintf(buf1,\

addr,sizeof(sockaddr_in));

服务器接受到这个命令之后将向其他的客户端发送游戏已经结束的命令: void CMyDlg::YouxiWin_date(LPPER_IO_DATA pData) {

char *buf = new char[20]; memset(buf,0,sizeof(buf)); }

83

sprintf(buf,\m_pushdeque.push_back(buf); m_fangjian.m_zhuozi = 0; char *buf6 = new char[50]; memset(buf6,0,sizeof(buf6));

sprintf(buf6,\

zi); }

客户端在收到这个游戏结束的命令之后,将调用下面的函数结束游戏: LRESULT MyYouxi::OnUserYouxiKill(WPARAM wParam,LPARAM lparm) {

KillMap(); m_youxiKaishi = 0; KillTimer(1);

memset(m_sum,-1,sizeof(m_sum)); memset(&m_map,-1,sizeof(m_map)); char buf[10] = {0};

sprintf(buf,\

sendto(MySocket::m_socket,buf,10,0,(sockaddr*)&MySocket::udp_am_pushdeque.push_back(buf6);

ddr,sizeof(sockaddr_in)); }

void MyYouxi::KillMap()

return 0;

84

{ int i,j; int k = 0;

CDC *pdc = GetDC();

CDC mdc,dc1,mdc1;

mdc.CreateCompatibleDC(pdc); dc1.CreateCompatibleDC(pdc); CBitmap bit;

bit.CreateCompatibleBitmap(pdc,396,304); dc1.SelectObject(bit);

POINT pt; pt.x = 0; pt.y = 0; int num;

for (i = 1;i<9;i++) { for (j = 1;j < 13;j++) { num = m_sum[i][j]; if (num == -1) {

dc1.BitBlt(pt.x,pt.y,33,38,&m_mdc,96 33,221 + (i - 1) * 38,SRCCOPY); pt.x += 33; m_sum[i][j] = num;

continue;

+ (j - *

85

1)

}

}

}

mdc.SelectObject(m_ver[num + 32]);

dc1.BitBlt(pt.x,pt.y,33,38,&mdc,0,0,SRCCOPY); pt.x += 33;

pt.x = 0; pt.y += 38;

WaitForSingleObject(hmutex,INFINITE);

m_dcmem.BitBlt(96,221,396,304,&dc1,0,0,SRCCOPY); ReleaseMutex(hmutex);

InvalidateRect(CRect(m_pt.x,m_pt.y,m_pt.x + (j - 1) * 33,m_pt.y

+ (i - 1) * 38),FALSE); }

memset(m_sum,-1,sizeof(m_sum));

5.7连连看算法

连连看的算法我是通过以下思路进行解决的:首先先查看两个图片是否能够直接连通,如果可以,那么就消去图片,如果不可以,那么就判断在有一个转折点的情况下是否可以连通,如果可以,那么就消去图片,如果不可以,如果还是不行,那么就判断在有2个转折点的情况下是否可以连通,如果可以,那么就消去图片,如果不可以,那么就判断无法消去图片,代码如下: BOOL MyYouxi::CheckBitmap() {

m_sumVer.clear(); if (m_oldNum == m_newNum)

86

{ if (DirectBend(m_old,m_new)) { m_i = 1; return TRUE;

}

else if (FirstBend(m_old,m_new)) { m_i = 2; return TRUE; }

else if (FirstBend(m_new,m_old)) { m_i = 2; return TRUE; }

else if (SecondBend(m_old, m_new)) { m_i = 3; return TRUE; }

else if (SecondBend(m_new,m_old)) { m_i = 3; return TRUE; }

}

87

}

return FALSE;

BOOL MyYouxi::DirectBend(POINT oldpt, POINT newpt) { POINT pt; int tmp = 0;

if (oldpt.x == newpt.x) { if ((oldpt.y + 1 == newpt.y) || (oldpt.y - 1 == newpt.y)) { return TRUE;

}

}

else if (oldpt.y == newpt.y) { if ((oldpt.x + 1 == newpt.x) || (oldpt.x - 1 == newpt.x)) {

return TRUE;

}

}

if (oldpt.x == newpt.x) { if (oldpt.y > newpt.y) { tmp = oldpt.y; oldpt.y = newpt.y; newpt.y = tmp;

}

88

for (int i = oldpt.y + 1;i < newpt.y; i++) { if (m_sum[i][oldpt.x] != -1) { m_sumVer.clear(); return FALSE;

}

pt.x = oldpt.x; pt.y = i;

m_sumVer.push_back(pt);

}

return TRUE;

}

if (oldpt.y == newpt.y) { if (oldpt.x > newpt.x) { tmp = oldpt.x; oldpt.x = newpt.x; newpt.x = tmp;

}

for (int i = oldpt.x + 1;i < newpt.x; i++) { if (m_sum[oldpt.y][i] != -1) { m_sumVer.clear(); return FALSE;

}

89

pt.x = i; pt.y = oldpt.y;

m_sumVer.push_back(pt);

}

return TRUE;

}

return FALSE;

}

BOOL MyYouxi::FirstBend(POINT oldpt, POINT newpt) {

POINT textpt;

?????????????????. }

}

m_sumVer.clear(); return FALSE;

}

BOOL MyYouxi::SecondBend(POINT oldpt, POINT newpt) { m_sumVer.clear(); POINT pt; int j; int x,y;

if (newpt.x-oldpt.x >= 0) {

x = 1; 90

}

else x = -1;

if (newpt.y-oldpt.y>=0) { y = 1;

}

else y = -1; CPoint tmpPoint; BOOL result1,result2; for (j=oldpt.y+1;j<=9;j++) { m_sumVer.clear();

for (int s = oldpt.y+1; s <= j;s++) { pt.x = oldpt.x; pt.y = s;

m_sumVer.push_back(pt); }

if (m_sum[j][oldpt.x] != -1) { break;

}

if (m_sum[j][oldpt.x + x] == -1) { tmpPoint.y=j; tmpPoint.x=oldpt.x;

m_sumVer.push_back(tmpPoint);

result1=FirstBend(tmpPoint,newpt); 91

if (result1 == TRUE) { m_temppt = tmpPoint; return TRUE;

} else { m_sumVer.empty();

for (int s = oldpt.y+1; s <= j;s++) { pt.x = oldpt.x; pt.y = s;

m_sumVer.push_back(pt); }

m_sumVer.push_back(tmpPoint); result2=FirstBend(newpt,tmpPoint); if (result2==TRUE) { m_temppt = tmpPoint; return TRUE; }

}

}

}

m_sumVer.clear(); j = 0;

for (j=oldpt.y-1;j>=0;j--) {

92

m_sumVer.clear();

for (int s = oldpt.y-1; s >= j;s--) { pt.x = oldpt.x; pt.y = s;

m_sumVer.push_back(pt);

}

if (m_sum[j][oldpt.x] != -1) { break;

}

if (m_sum[j][oldpt.x + x] == -1) { tmpPoint.y=j; tmpPoint.x=oldpt.x;

m_sumVer.push_back(tmpPoint); result1=FirstBend(tmpPoint,newpt); if (result1 == TRUE) { m_temppt = tmpPoint; return TRUE; } else { m_sumVer.clear();

for (int s = oldpt.y-1; s >= j;s--) { pt.x = oldpt.x;

pt.y = s; 93

}

m_sumVer.push_back(pt);

m_sumVer.push_back(tmpPoint); result2=FirstBend(newpt,tmpPoint); if (result2==TRUE) { m_temppt = tmpPoint; return TRUE;

}

}

}

}

m_sumVer.clear(); j=0;

for (j=oldpt.x-1;j>=0;j--) { m_sumVer.clear();

for (int s = oldpt.x-1; s >= j;s--) { pt.x = s; pt.y = oldpt.y;

m_sumVer.push_back(pt);

}

if (m_sum[oldpt.y][j] != -1) { break; }

if (m_sum[oldpt.y+y][j] == -1)

{

94

tmpPoint.x=j; tmpPoint.y=oldpt.y;

m_sumVer.push_back(tmpPoint); result1=FirstBend(tmpPoint,newpt); if (result1 == TRUE) { m_temppt = tmpPoint; return TRUE;

} else { m_sumVer.clear();

for (int s = oldpt.x-1; s >= j;s--) { pt.x = s; pt.y = oldpt.y; m_sumVer.push_back(pt); }

m_sumVer.push_back(tmpPoint); result2=FirstBend(newpt,tmpPoint); if (result2==TRUE) { m_temppt = tmpPoint; return TRUE; }

}

}

}

95

m_sumVer.clear(); j=0;

for (j=oldpt.x+1;j<=13;j++) { m_sumVer.clear();

for (int s = oldpt.x+1; s <= j;s++) { pt.x = s; pt.y = oldpt.y;

m_sumVer.push_back(pt);

}

if (m_sum[oldpt.y][j] != -1) { break; }

if (m_sum[oldpt.y+y][j] == -1) { tmpPoint.x=j; tmpPoint.y=oldpt.y;

m_sumVer.push_back(tmpPoint); result1=FirstBend(tmpPoint,newpt); if (result1 == TRUE) { m_temppt = tmpPoint; return TRUE; } else

{

96

m_sumVer.clear();

for (int s = oldpt.x+1; s <= j;s++) { pt.x = s; pt.y = oldpt.y; m_sumVer.push_back(pt);

}

m_sumVer.push_back(tmpPoint); result2=FirstBend(newpt,tmpPoint); if (result2==TRUE) { m_temppt = tmpPoint; return TRUE; }

}

}

}

m_sumVer.clear(); return FALSE;

}

97

第六章 总结与展望

这个游戏分2个部分,其中客户端部分的内容都是非常分散,常常要考虑到模块之间的协作,而且每个模块内部又有很多小模块,互相之间也有非常密切的联系,很多变量之间数据的传递都要考虑好。而第二个部分(即服务器部分)相对比较集中,几乎就只有一个函数,但是代码内容非常长,工作量也是很大的,且几乎全部是在代码中编写,没有添加什么界面上的控件操作。

另外这个游戏有用到数据库,但使用的功能也不是很多,但是由于考虑到要按固有的游戏规则来编写,因此要写较多时间考虑游戏怎么玩,怎么通过代码判断用户每个鼠标点击的坐标以及当前坐标位置代表的图片内容等各方面的判断考虑得就较多了。

致谢

经过数月的资料查阅、整理和准备,今天我的论文终于顺利地完成了。通过这次论文的写作,我学到了很多东西:培养了我的自学能力和动手能力,学会了如何将学到的知识转化为自己的东西,学会了怎样来更好地处理知识和实践相结合的问题。同时,我还学到了做任何事情所要有的态度和心态。首先,做学问要一丝不苟,对于发展过程中出现的任何问题和偏差都不要轻视,要通过正确的途

98

径去解决;在做事情的过程中要有耐心和毅力,要有坚持不懈、迎难而上的精神,只有坚持才会找到解决问题的思路。回顾起这个艰辛却充满挑战、让人感到充实和回味的过程,期间有太多的人需要感谢。

首先,要特别感谢我的论文指导老师,在老师的悉心指导下,我的毕业设计选题、构思、设计和论文资料的收集、论文框架的确定、开题报告的准备及论文初稿、定稿的完成才得以顺利进行。在这个过程中,老师倾注了大量的心血,他循循善诱,精心指导,给予我无尽的启迪。他对我论文的初稿进行了逐字逐句的批阅,指正谬误,这种严谨的治学态度和一丝不苟的作风,将会成为我学习和效仿的榜样。在此,对老师做出的全部努力和付出,所给予的一切帮助,我深深地表示感谢!

同时我还要借此机会向在这二年里给予了我帮助和指导的班主任与各位任课老师认真负责表示感谢,在他们的悉心帮助和支持下,我能够很好的掌握和运用专业知识,并在设计中得以体现,顺利完成毕业论文。

最后,感谢参加论文评审和答辩的各位老师和同学。由于本人学识水平和能力的限制,文中见解谬误不当之处难免,恳请同行、领导、专家批评指正。

99