毕业设计(论文)-基于JAVA的“五子棋”网络游戏开发
PAGE
第一章 系统概述
课题意义
本程序旨在用JAVA实现一个基本于C/S模式的五子棋网络对战游戏。玩家作为客户端通过服务器端与其它玩家进行对战,聊天等功能。通过实现本程序加深对计算机网络编程的了解。
国内外有关研究动态
???电脑游戏行业经过二十年的发展,已经成为与影视、音乐等并驾齐驱的全球最重要的娱乐产业之一,其年销售额超过好莱坞的全年收入。互联网的出现为电脑游戏行业发展注入了新的活力,凭借信息双向交流、速度快、不受空间限制等优势,让真人参与游戏,提高了游戏的互动性、仿真性和竞技性,使玩家在虚拟世界里可以发挥现实世界无法展现的潜能,改变了单机版游戏固定、呆板、与机器对话的状况。网络游戏的这些优势不仅使其在电脑游戏行业中异军突起并在某种程度上取代了单机版游戏,而且成为网络业三大(网上金融、网上教育和网络游戏)赢利且利润优厚的领域之一[1]。
网络作为一种新兴的传播方式,主要包括三大内容:娱乐、资讯、通讯。提到网络娱乐,过去主要指的是单机版游戏,没有引入网络的概念[2]但随着科技的发展,游戏娱乐产业也在成长[3]目前,国内的游戏娱乐产业正处于起步阶段,特点表现为:第一,它是一种文化的传播。娱乐产业可以潜移默化地改变人的观念,当前,很多多媒体的播放已被电脑网络所取代[4]。第二,网络游戏加强了人与人的沟通。第三,网络游戏具有一定的教育意义[5]。网络游戏所具有的角色扮演的功能,使得玩家能通过互助更好地完成游戏中的各项任务。网络无国界,游戏在网络文化产业世界的发展中地位会越来越高[6]。
目前在国外,休闲游戏如棋类等,玩家的年龄跨度非常大,这和我国目前网游市场以青少年为主要消费人群的状况截然不同[7]。其实,网络可以解决空间的问题,网络和生活越来越息息相关,因此,开辟适合各个年龄层的游戏产品迫在眉睫。同时,这也涉及到一个企业开发的能力。娱乐产业发展到一定程度,通过不断锻炼和经验的积累,完全可以通过融入娱乐的成分把教条的东西深入浅出地展现给消费者[8] 。
就国内的发展来看,最近這两三年内国内的游戏公司如雨后春笋般的成立,所開發或代理的网络游戏更是不胜枚举。以全球游戏业界的发展来看,這几年韩国的表现最为突出,特別是在网络游戏的技术研发兴游戏制作,其所发行的网络游戏更成为全球游戏产业重要的指标之一。去年在美国洛杉矶所举行的 E3(Electronic Entertainment Exposition)展中,已经有几家的韩国厂商挤入世界第一线的游戏开发厂商之列[9]。
??? 近几年来,由于 3D 硬体绘图技术的突破,使得即时描绘的书面越来越精致,而且3D遊戏性更多元化更逼近真实世界,因此在遊戏产业中,3D 游戏已经逐渐取代2D游戏为游戏市场的主流,即使是网络游戏,也慢慢趋向3D化。然而游戏3D化将会带来的游戏开发上的困难等问题,这些问题以后都需要逐步解决[10]。
课题主要内容及创新之处
五子棋是一种受大众广泛喜爱的游戏,其规则简单,变化多端,非常富有趣味性和消遣性。本程序是用JAVA实现的一个基本于C/S模式的五子棋网络对战游戏。JAVA是一种简单的,面向对象的,分布式的,解释的,健壮的,安全的,结构中立的,可移植的,性能很优异的多线程的,动态的语言。因此用Java开发的网络应用系统可以在各种平台上运行,实现了设备无关性,一次开发处处运行,大大增加了开发效率,减少了重复劳动。玩家作为客户端通过服务器端与其它玩家进行对战,聊天等功能[11]。本程序作为一种网络游戏,其乐趣是人与人之间的对抗,而不仅仅是人与事先设置的各种程序的对抗,所以比普通的人机对战游戏更具有生命力,更具有趣味性[12]。而且通过实现本程序可以加深对计算机网络编程的了解。
五子棋简介
五子棋起源、历史、简介
五子棋起源于中国古代的传统黑白棋[13]。现代五子棋日文称之为連珠,英译为Renju,英文称之为Gobang或FIR(Five in a Row的缩写),亦有连五子、五子连、串珠、五目、五目碰、五格等多种称谓。
五子棋不仅能增强思维能力,提高智力,而且富含哲理,有助于修身养性。五子棋既有现代休闲的明显特征短、平、快,又有古典哲学的高深学问阴阳易理;它既有简单易学的特性,为人民群众所喜闻乐见,又有深奥的技巧和高水平的国际性比赛;它的棋文化源渊流长,具有东方的神秘和西方的直观;既有场的概念,亦有点的连接。它是中西文化的交流点,是古今哲理的结晶。
五子棋规则说明
棋盘
棋盘正中一点为天元。棋盘两端的横线称端线。棋盘左右最外边的两条纵线称边线。从两条端线和两条边线向正中发展而纵横交叉在第四条线形成的四个点称为星。天元和星应在棋盘上用直径约为0.5厘米的实心小圆点标出。 以持黑方为准,棋盘上的纵轴线从左到右用英文字母A~O标记。横行线从近到远用阿拉伯数字1~15标记。纵横轴上的横纵线交叉点分别用横纵线标记的名称合写成。如天元H8,四个星分别为D4、D12、L12、L4等。见图2.1
图 2.1 棋盘
基本规则
黑白双方依次落子,任一方先在棋盘上形成横向、竖向、斜向的连续的相同颜色的五个(含五个以上)棋子的一方为胜。
阳线和阴线
阳线:棋盘上可见的横纵直线。
阴线:棋盘上无实线连接的隐形斜线。
连
在棋盘某一阳线或阴线上形成5个以上的同色棋子不间隔地相连。
五连:在棋盘上形成的5个同色棋子的连。
长连:在棋盘上形成的6个或6个以上同色棋子的连。
四包括活四和冲四
图 2.2 活四说明
活四:在棋盘某一条阳线或阴线上有同色4子不间隔地紧紧相连,且在此4子两端延长线上各有一个无子的交叉点与此4子紧密相连。见图2.2
冲四:除活四外的,再下一着棋便可形成五连,并且存在五连的可能性的局面。见图2.3
图 2.3 冲四说明
白棋再下一着可形成长连的局面也视为四。见图2.4
图 2.4 白棋长连形成的四
三指活三,包括连三和跳三
活三:在棋盘某一条阳线或阴线上有同色3子不间隔地紧紧相连,且在此3子两端延长线上各有一个无子的交叉点与此3子紧密相连。
连三:在棋盘某一条阳线或阴线上有同色三子相连,且在此三子两端延长线上有一端至少有一个,另一端至少有两个无子的交叉点与此三子紧密相连。
跳三:中间仅间隔一个无子交叉点的连三,但两端延长线均至少有一个无子的交叉点与此三子相连。
三手可交换
是指黑棋下盘面第3着棋后,白方在应白4着棋之前,如感觉黑方棋形不利于己方,可提出交换,即执白棋一方变为执黑棋一方,而黑方不可以不换。
五手两打
是指黑棋在下盘面上关键的第5手棋时,必须下两步棋,让白棋在这两步棋中任选一步,然后再继续对弈。一般说来,白棋肯定拿掉对白方不利的一点,而保留对黑方较为不利的那点让黑方行棋。
禁手规则
无禁手: 是指采用最简单古老的规则。黑白双方依次落子,任一方先在棋盘上形成横向、竖向、斜向的连续的相同颜色的五个(含五个以上)棋子的一方为胜。这种规则非常简单容易理解。适合初学的业余五子棋爱好者。但是在这种规则下黑棋胜算较大。甚至已经有人证明在黑白双方都不出现错误的情况下,黑棋可以必胜。所以一般要求连续玩两盘以上,既任一方执黑,执白各一次。
有禁手:鉴于无禁手规则黑棋必胜,人们不断采用一些方法限制黑棋先行的优势,以平衡黑白双方的形式。于是针对黑棋的各种禁手逐渐形成。禁手最简单地说就是一手棋形成长连(连成五个以上连续相同的棋子),或两个以上的活三,或者两个以上的四,并且这些四、活三和长连都要包括这一手棋。
并且规定,当禁与连五同时出现时为黑方取胜禁手不成立,禁手是针对黑棋而言的,白棋没有任何禁手。例如:黑棋长连是禁手,白棋长连算赢棋。 国际比赛规则规定:对局中如黑方出现禁手,白方应立即指出禁手点,黑方即负。如白方在黑方出现禁手后,又落一步白子,黑棋禁手则不成立了。 所以 在有禁手的房间里,如果黑方出现禁手,白方应立即按下禁手按钮 。程序会判黑方负。如果这时白方又在棋盘上落一子,黑棋禁手则不成立了。
第三章 方案设计及开发工具的选取
选用Java进行开发的原因
Java是一种简单的,面向对象的,分布式的,解释的,健壮的安全的,结构的中立的,可移植的,性能很优异的多线程的,动态的语言[14] 。因此用Java开发的网络应用系统可以在各种平台上运行,大大增加了开发效率,减少重复劳动。而且,Java集成的网络功能分有利于开发网络应用系统[15] 。
Java具有许多的优点:
简单
Java最初是为对家用电器进行集成控制而设计的一种语言,因此它必须简单明了。Java语言的简单性主要体现在以下三个方面:1.Java的风格类似于C++,因而C++程序员是非常熟悉的。从某种意义上讲,Java语言是C及C++语言的一个变种,因此,C++程序员可以很快就掌握Java编程技术。2.Java摒弃了C++中容易引发程序错误的地方,如指针和内存管理。3.Java提供了丰富的类库。
面向对象
面向对象可以说是Java最重要的特性。Java语言的设计完全是面向对象的,它不支持类似C语言那样的面向过程的程序设计技术。Java支持静态和动态风格的代码继承及重用。单从面向对象的特性来看,Java类似于SmallTalk,但其它特性、尤其是适用于分布式计算环境的特性远远超越了SmallTalk。
分布式
Java包括一个支持HTTP和FTP等基于TCP/IP协议的子库。因此,Java应用程序可凭借URL打开并访问网络上的对象,其访问方式与访问本地文件系统几乎完全相同。为分布环境尤其是Internet提供动态内容无疑是一项非常宏伟的任务,但Java的语法特性却使我们很容易地实现这项目标。
健壮
Java致力于检查程序在编译和运行时的错误。类型检查帮助检查出许多开发早期出现的错误。Java自己操纵内存减少了内存出错的可能性。Java还实现了真数组,避免了覆盖数据的可能。这项功能特征大大缩短了开发Java应用程序的周期。Java提供Null指针检测数组边界检测异常出口字节代码校验
结构中立
另外,为了建立Java作为网络的一个整体,Java将它的程序编译成一种结构中立的中间文件格式。只要有Java运行系统的机器都能执行这种中间代码。现在,Java运行系统有Solaris2.4(SPARC),Win32系统(Windows95和WindowsNT)等.Java源程序被编译成一种高层次的与机器无关的byte-code格式语言,这种语言被设计在虚拟机上运行,由机器相关的运行调试器实现执行。
安全
Java的安全性可从两个方面得到保证。一方面,在Java语言里,像指针和释放内存等C++功能被删除,避免了非法内存操作。另一方面,当Java用来创建浏览器时,语言功能和一些浏览器本身提供的功能结合起来,使它更安全。Java语言在你的机器上执行前,要经过很多次的测试。它经过代码校验,检查代码段的格式,检测指针操作,对象操作是否过分以及试图改变一个对象的类型。
可移植的
同体系结构无关的特性使得Java应用程序可以在配备了Java解释器和运行环境的任何计算机系统上运行,这成为Java应用软件便于移植的良好基础。但仅仅如此还不够。如果基本数据类型设计依赖于具体实现,也将为程序的移植带来很大不便。例如在Windows3.1中整数(Integer)为16bits,在Windows95中整数为32bits,在DECAlpha中整数为64bits,在Intel486中为32bits。通过定义独立于平台的基本数据类型及其运算,Java数据得以在任何硬件平台上保持一致。Java语言的基本数据类型及其表示方式如下:byte8-bit二进制补码short16-bit二进制补码int32-bit二进制补码long64-bit二进制补码float32-bitIEEE754浮点数double32-bitIEEE754浮点数char16-bitUnicode字符。在任何Java解释器中,数据类型都是依据以上标准具体实现的。因为几乎目前使用的所有CPU都能支持以上数据类型、8~64位整数格式的补码运算和单/双精度浮点运算。Java编译器本身就是用Java语言编写的。Java运算系统的编制依据POSIX方便移植的限制,用ANSIC语言写成。Java语言规范中也没有任何同具体实现相关的内容。
多线程
Java的多线程功能使得在一个程序里可同时执行多个小任务。线程有时也称小进程,是一个大进程里分出来的小的独立的进程。因为Java实现的多线程技术,所以比C和C++更健壮。多线程带来的更大的好处是更好的交互性能和实时控制性能。当然实时控制性能还取决于系统本身(UNIX,Windows,Macintosh等),在开发难易程度和性能上都比单线程要好。任何用过当前浏览器的人,都感觉为调一副图片而等待是一件很烦恼的事情。在Java里,你可用一个单线程来调一幅图片,而你可以访问HTML里的其它信息而不必等它。
与C和C++语言的异同
Java提供了一个功能强大语言的所有功能,但几乎没有一点含混特征。C++安全性不好,但C和C++还是被大家所接受,所以Java设计成C++形式,让大家很容易学习。Java去掉了C++语言的许多功能,让Java的语言功能很精炼,并增加了一些很有用的功能,Java去掉了以下几个C和C++功能和特征:指针运算结构typedefs#define需要释放内存全局变量的定义这个功能都是很容易引起错误的地方。
客户端服务器模式
C/S模式简介
客户 机 /服务器(Client/Server)模式是指两个逻辑(往往是物理的)系统(客户机/服务器)及其应用程序逻辑组件之间复杂关系的协同[16]。一般而言,C/S应用系统从物理上都可划分为客户机与服务器两大部分,而逻辑上又可分解为三部分:表达逻辑、业务处理逻辑和数据管理逻辑。C/S应用系统的格局和性能主要取决于这些逻辑成份在客户机上或在服务器上的组织与分配。C/S模式将一个应用分为两个部分:前端(客户端)、后端(服务器)。客户机指提供客户机服务的逻辑系统,服务器指向服务器请求提供服务的逻辑系统。一般来说,客户机向服务器发出请求为其完成一部分工作服务器则处理客户机的请求并返回结果。
C/S 两层模式主要有以下特点:分布的处理与集中的数据操作管理有机地结合;开放式的系统;用与操作系统、网络协议无关的方式存取数据,支持多平台和跨平台;服务器对用户是透明的;交互性强;相对B/S模式,C/S模式速度快,更利于处理大量数据。
C/S两层模式中,客户机并不是毫无运算能力的输入、输出设备,而是具有了一定的数据处理和数据存储能力,通过把应用软件的计算和数据合理地分配在客户机和服务器两端,可以有效地降低网络通信量和服务器运算量。由于服务器连接个数和数据通信量的限制,这种结构的软件适于在用户数目不多的局域网内使用。国内目前的大部分ERP(财务)软件产品即属于此类结构。C/S模式(Client-Server Architecture)可能是应用软件开发所使用的最成功的一种模式。它首先是出现在主机系统中,在局域网环境下,其性能显的格外的突出。而现在,C/S模式已经成为一种基本的开发设计模式。虽然C/S应用软件包含了Client和Server部件并且在网络中相互交互。但这并不代表说所有的C/S应用软件均需要按照这样来设计(即网络不是必须的),它是允许在单机上运行的。
虽然 两 层 系统有以上的优点,但在多用户、多数据库、且非安全的网络环境下(例如Internet),两层的应用就有明显的局限性。服务器端的数据库必须同每一个活动的客户保持连接,这些连接消耗了大量的运算资源,其结果是随着客户数目的增加,性能不断下降.由于应用逻辑全部驻留在客户端,当应用环境发生变化需要改变事务逻辑时,每个客户机上的程序都需要更新,给系统的维护和管理造成了一定的困难。随着应用系统越来越复杂,客户端应用程序变得越来越庞大,对客户机的处理能力要求越来越高,成为所谓的“胖客户机”
在C/S模式中,工作原理可以简单的理解为:Client向Server提交一个请求,Server则使用一些方法处理这个请求,并将效果返回给Client. 见图3.1
图 3.1 C/S模式原理图
在处理Client的请求时,Server本身可以成为另一个C/S模式中的Client.
见图3.2
图 3.2 server与client关系图
大部份的人认为在Client-Server应用软件中,Server做了几乎所有的工作。但实际上并不是这样。在实际应用中,Client执行了大部份的软件逻辑并完成了大部份的工作。Server当然也做了些工作。但它主要的工作是接受client的请求并返回结果。
有许多人说C/S结构是分布式结构中最常用的一个例子。的确,它确实是一个常用的架构模式,而且它也确是通过网络进行Client和Server之间的交互,但是,严格来说,C/S模式有可能不是真正意义上的分布式结构。为什么这么说呢?我们首先应该从分布式结构的定义及特性去考虑。分布式系统简单来说是指通过网络,进行多于一台电脑之间的数据交互。而它最大的特性在于二点,性能(performance)和可量测性(Scalability). 而C/S模式由于含有一系列的限制,以至于很难达到这二点分布式系统的特性。另一方面,一个单独的应用软件的透明度通常也是一个分布式结构的特性,但C/S模式并没有提供这方向的特性。举个例子,一个网页浏览器,可以看成是一个Client.而用户必须输入网站的网址去连接包含所要求网页的Server,在这里,它就缺乏了透明性。因此我也可以将这个网页浏览器和服务器看成是在这个系统中的二个独立的组件。在C/S模式下,应用程序直接存取数据库服务器上的数据,数据库服务器挂在网络服务器上,客户机通过协议(如TCP/IP)和服务器连接。网络服务器一般运行Unix或Windows NT等操作系统,客户机一般运行Windows95/98。在C/S模式下,大量的开发任务在客户机端。目前各种流行的开发环境一般都有开发数据库的工具,并且支持C/S模式开发。如Visual C++/Basic、Delphi/C++ Builder、Power Builder等。
C/S模式的限制与应用
C/S模式也含有一系列的限制。那这些限制都是什么呢?其实C/S模式最基本的问题在于其缺乏可量测性,主要原因是由于Server逐渐的变成了性能的瓶颈。在前面介绍了可量测性和性能是分布式结构的二大特点。二者相辅相成,缺乏了可量测性也成为了C/S模式不是一种完全的分布式结构的一个原因。在C/S模式中,服务端通常需要通过获取和使用一些资源来处理Client的请求,比如说,连接数据库,获取数据信息等。对于一个软件的开发设计,任何一个需要访问共享资源的设计系统均应该在最短的时间内获取到所需资源,这样其它的用户就可以有机会去访问资源。试想一下,如果同一时间,大量的Client同时对Server发出请求,会出现什么的样的情况?可能会是Server的崩溃,也可能会是网络的停滞,但不管是什么,这一点将会让Server变成一个性能的瓶颈,这也是为什么我说C/S模式对于一个应用软件的可量测性来说含有一定的限制。(有关可量测性,在下面讨论)。C/S模式不适合大型的网络系统,但对于局域网系统来说是个很好的选择,换句话说,C/S模式适合10到100用户的局域网的系统开发,而对于Internet用户的系统来说,这种模式就不适合了。如果说C/S模式不是一种完全的分布式系统,那么它与传统的分布式系统又有什么差别呢?C/S模式的大部处理是在Client 中执行,而传统的分布式系统是在另一远程机器中进行处理。二者的边界有点模糊,针对不同的系统要进行正确的选择,这样才能设计出高性能的系统。
可量测性(Scalability)的讨论
什么是可量测性呢?对于一个含有可量测性的系统来说,当其在物理资源(小陆所说的硬件资源)的数量或者用户的数量增加的前提下,仍应尽可能的保持着效率。当然,在实际的操作中,这是不可能的,多多少少性能都会受到影响。拿本程序来当例子,当玩家多的时候,大家都需要排队,才能进入到游戏,而当玩家少的时候,大家就可以直接连接,进入到游戏中[17]。
界面开发工具的选择
对一个优秀的应用程序来说,良好的图形用户接口是必不可少的。缺少良好的图形用户接口,将会给用户理解和使用应用程序带来很多不便。很难想象用户为了学会使用一个应用程序,去记一大堆命令。Java提Awt和swing包了生成一个良好的图形用户接口所需要的;基本元件:面板(Panelcopy;、按钮(Buttoncopy;、标copy;(Labelcopy;、画板(Canvasescopy;、滚动条(Scrollbarcopy;、列表框(Listcopy;、文本域(TextFieldcopy;、文本区(TextAreacopy)。由于本系统是一个休闲娱乐游戏,本身的界面元素也不是很复杂,所以用Java AWT来做界出处理已经足够了。用JAVA AWT做界面也有利于和JAVA内部程序的衔接。
JAVA Socket编程
Java是一种可用于进行网络编程的语言,它提供了两种功能强大的网络支持机制:URL访问网络资源的类和用Socket通讯的类,来满足不同的要求[18]。一是URL用于访问Internet网上资源的应用;另一种是针对client/server(客户端/服务器)模式的应用以及实现某些特殊的协议的应用,它的通讯过程是基于TCP/IP协议中传输层接口socket实现的。
客户基于服务器之间使用的大部分通讯组件都是基于socket接口来实现的[19]。Socket是两个程序之间进行双向数据传输的网络通讯端点,有一个地址和一个端口号来标识。每个服务程序在提供服务时都要在一个端口进行,而想使用该服务的客户机也必须连接该端口。Socket因为是基于传输层,所以它是比较原始的通讯协议机制。通过Socket的数据表现形式为字节流信息,因此通讯双方要想完成某项具体的应用则必须按双方约定的方式进行数据的格式化和解释,它具有更强的灵活性和更广泛的使用领域。
客户机/服务器Socket通讯工作模式见图3.3
图 3.3 客户机/服务器Socket通讯工作模式
第四章 五子棋详细设计
根据上一章介绍的系统实现方案,可以将系统简要的看为分为三个大的功能模块,即界面元素的设计,客户端程序设计和服务器端程序设计。下面就这三个部分的主要功能实现依次进行介绍:
4.1需求规定
棋盘采用 15×15 棋盘。
游戏采用人与人对弈模式,可以选择玩家进行游戏。
游戏中设有禁守规则和其他走子限制。
只有当五个相同颜色的棋子成线以后才判为获胜,长连也算获胜。
棋盘颜色与棋子颜色要对比分明,便于其他程序识别。
游戏中可以显示游戏状态的信息,但是不能有弹出对话框之类的窗口挡住棋盘。
运行环境
硬件配置(推荐):
CPU:P4—1GHZ或更高
内存:128M或更多
显示器分辨率:800x600或更高
软件配置:
Jbuilder 9或安装了JDK 1.4,windowsXP操作系统
运行本软件的系统平台:
由于本程序是采用JAVA开发的,实现了与平台的无关性,具有很强的可移性,一次开发处处运行,所以可以在所有平台运行。
开发工具:
Jbuilder 9
五子棋客户端设计
建立15X15棋盘
图 4.1 五子棋棋盘
界面元素的设计
游戏菜单,玩家列表,聊天窗口以及其它一些状态信息。整个程序界面见图4.2
图 4.2 系统界面
游戏菜单:可以单击和人对战,设定禁手规则,退出,以及作者信息。
玩家列表:玩家可以双击列表中的一个玩家请求游戏,当对方接受请求双方即可以开始游戏。
聊天窗口:一对正在游戏的玩家可以互相聊天。
建立与使用获胜表
int board [10][10];//玩家的每一颗棋子是否在各个获胜表中
图 4.3 获胜表
board [15][15]中的元素都初始化为0;board [15][15]中记录了两个玩家的所有落子信息,一方玩家为白子在数组中用0表示,一方为黑子在数组中用1表示,所以在整个数组都是1,0的数据,根据正向,反向,斜向上1,0形成的个数学来判断白子和黑子的是获胜的组合数
客户端程序主要变量说明
表1 客户端程序主要变量列表
变量
类 型
功 能
board
int[][]
用来记录玩家各自的下子信息,由此表判断胜负。
pColor
Int
用来记录玩家所选的棋的颜色。
socket
Socket
定义一个套接字。
PORT
Int
定义服务器端需要监听的端口,客户端一连接到此端口,服务器端就可以监听到,从而和客户端建立起通信。
in
ObjectInputStream
表示客户端套接字的输入流,用来接收其它客户端和服务器端传来的数据。
out
ObjectOutputStream
表示客户端套接字的输出流,用来向其它客户端和服务器端输出数据。
serverAddress
String
记录主机即服务器端的IP地址信息,客户端通过些IP地址连接到服务器的PORT端口。
name
String
记录了当前玩家的名字。
send
Char[]
当玩家离开时服务器时会向另一玩家发离开消息,此变量记录的便是这个消息字符串。
message
Message
beginFlag
Boolean
记录游戏开始/结束的标志,也是游戏开始的标志
bpanel
BoardPanel
记录了棋盘信息。包括棋盘的创建以及棋盘响应的事件。
xp
Int
记录了玩家按下的点的横向的像素位置
yp
Int
记录了玩家按下的点的竖向的像素位置
setting
Boolean
是否设置禁手。
coordinateX
Int
客户端向服务器发送消息时记发的当前玩家下棋的横向位置。
coordinateY
Int
客户端向服务器发送消息时记发的当前玩家下棋的纵向位置。
msg
char[]
记录了玩家与玩家之间聊天信息。
客户端主要方法说明
表2 客户端程序主要方法列表
方 法 名 称
类 型
功 能
acceptToPlay(Message msg)
void
接受一个玩家的游戏请求
arrayToString(char [] arr)
String
将字节流转换为字符串
drawChess(int x,int y){
void
在指定位置画一颗棋字
getDeny(Message msg)
void
拒绝一个玩家的游戏请求
getDisconnection(Message msg)
void
正在游戏时,另一玩家退出,收到服务器发来的玩家离开消息。
getFailed(Message msg)
void
当玩家输掉游戏时显示失败信息。
getVictory(Message msg)
void
当玩家输掉游戏时显示胜利信息。
newGame()
void
重新开始新游戏,程序回到初始状态。
paint(GraphiC/S g)
void
重画棋盘。
putChessman(Message msg)
void
玩家下了一个棋子后,通过传送消息提交到服务器。
requestAnother(Message msg)
void
请求与另外的玩家进行游戏。
sendDisconnect()
void
向服务器发送断开连接请求,退出程序,断开与服务的连接
clearBoard()
void
将棋盘清零,回到初始状态。
updateBoard(int x,int y){
void
更新棋盘。
judge(int x,int y,int clr)
boolean
判断棋盘,是否有同颜色的棋子构成五个以上,由些判断胜负。
五子棋服务器端设计
服务器端的程序是整个程序的核心,用来处理来自客户端的请求,传送消息,服务器程序的设计主要包括:监听端口接收来自客户端的连接请求,将相互对战的客户端编组,向对战的客户传送聊天信息,处理来自客户端的消息以及向客户端发送消息,胜负的判断,一些功能转换函数,处理来自客户端的连接及断开连接请求。
服务器端程序主要变量说明
表3 服务器端主要变量说明
变 量 名
类 型
功 能
player
String
记录了每个玩家的基本信息。
in
ObjectInputStream
服务器端的输入流,用来接收来自客户端的消息。
out
ObjectOutputStream
服务器端的输出流,用来发送消息到客户端。
socket
Socket
定义一个套接字,用来与客户端的连接。
gg
Group
对战玩家组的基本信息。
playerList
ArrayList
玩家列表。
groupList
ArrayList
对战的玩家列表。
PORT
Int
定义服务器端需要监听的端口,客户端一连接到此端口,服务器端就可以监听到,从而和客户端建立起通信。
s
ServerSocket
服务器端的套接字。
服务器端程序主要方法说明
表4 服务器端主要方法说明
方 法 名 称
类 型
功 能 说 明
addPlayer(Message player)
void
添加一个玩家到玩家列表。
acceptRequest(Messagemsg)
void
A玩家接受另B玩家的游戏请求,服务器向B玩家发送接受游戏请求消息。
denyRequest(Messagemsg)
void
A玩家拒绝B玩家的游戏请求,服务器向B玩家发送拒绝游戏请求消息。
doMessage(Message msg)
int
处理来自客户端的消息。
getdisconnect(Message msg)
void
处理正在游戏的两个玩家中的断开连接请求。
getSocket()
Socket
获得一个套接字。
playerRefresh(Messageplayer)
void
刷新玩家列表。
putChessman(Message msg)
void
处理玩家的下子信息。
requestAnother(Message msg)
void
处理一个玩家请求向另外的玩家游戏请求的消息。
updateClient()
void
更新玩家列表。
setting(Message msg, boolean flag)
void
向对战的两家发送消息设置是否禁手。
chatmessage(Message msg)
void
处理对战的两玩家的聊天信息。
judge(Group gg, int x, int y)
boolean
判断胜负。
服务器端主体流程图(见图4.4)
客户端消息doMessage(),处理来自客户端的消息,判断消息类型23==3=2
客户端消息
doMessage(),处理来自客户端的消息,判断消息类型
2
3==3=2
4
5
7
12
19
21
13
6
putChessman(msg)
denyRequest(msg)
acceptRequest(msg)
checkVictory(msg)
setting(msg, flag)
playerRefresh(msg)
chatmessage(msg)
setting(msg, flag)
checkVictory(msg)
requestAnother(msg
输出消息到各客户端
图 4.4 服务器端主体流程图
程序模块功能说明
表5程序模块功能说明
类 名
功 能 说 明
BoardPanel
画出棋盘,处理棋盘事件
ChessWZQ
客户端主程序,处理客户端与服务器端的消息传送
Group
定义一个对战玩家组
Player
初始化一个玩家信息
Server
初始化服务器端的监听程序
Message
客户端与服务器端传送的消息对象
ServerOneClient
服务器端的主体程序,处理与客户端的交互,转发请求
InetAddressTest
用于初始化服务器端的IP地址址信息。
程序主体流程图(见图4.5)
图 4.5程序主体流程图
第五章 系统测试与性能分析
系统功能测试
设定JDK1.4的ClassPath和Path后进入到程序所在的目录,在Dos界面运行server.bat启动服务器端程序,按照上面步聚再启动一个Dos 界面运行client1.bat启动一个客户端程序,按照上面步聚再启动一个Dos 界面运行client2.bat启动一个客户端程序,至此系统完整界面启动,见图5.1
图 5.1 系统界面
1.由图6.1可知各界面元素符合需求分析中规定的要求,游戏界面测试成功。
2.玩家选择白色棋子,对方则自动选择黑色棋子,棋子选色测试成功。
3.在玩家列表中双击一个玩家请求游戏,双方建立了连接,游戏正常开始,游戏连接测试成功。
4.在聊天窗口中输入信息,对方玩家可以收到自己发的信息,自己也可以收到对方玩家输入的信息,聊天窗口测试成功。
5.在棋盘上点击鼠标,程序可以依照程序要求在上面下子,并且可以正常处理判断胜负,下子过程测试成功。
6.点击Create中的play with people 则系统提示在玩家列表中选择玩家进行游戏,Create菜单测试成功。
7.点击Quit按钮,游戏可以正常退出并可以正确判断胜负,退出功能测试成功。
5.2 系统性能分析
1.测试服务器的响应时间
运行客户端程序client1.bat,玩家名字可以立即出现在服务器端的玩家列表中,由此可知客户端与服务器的连接速度良好。
2.测试下子过程及胜负的处理响应时间
在棋盘上下一个棋子,服务器端可以接收到下子信息并把信息发到另外的客户端,如果此时有任一方的棋子可以五个成一线则可以正确判断胜负,由些可知系统对下子过程的处理响应时间良好。
由些可以测定系统对各方面的性能响应要求良好,符合需求分析的要求。
结束语
网络游戏正在形成一个成熟而巨大的产业。在日本和韩国,电子游戏已经相继超过以汽车制造为代表的传统制造业而成为国民经济主导产业之一。在美国,游戏业已经超越拥有百年历史的好莱坞电影业而成为整个电子娱乐产业的龙头。根据市场预测,从2001年到2005年,美国的网络游戏收入将会以每年50%的速度递增,由2.3亿美元增加到18亿美元。2003年, 中国网络游戏人数将超过1500万人。国内网站方面,网易、新浪、搜狐、21CN、腾讯、TOM等纷纷进军网络游戏。2002年,国内网络游戏从50多款迅速发展到了130多款。2003年将继续成倍增加。可见网络游戏的开发还存在着巨大的潜力,如何开发出更好的网络游戏将是我们继续努力的目标。通过本程序的开发我掌握了很多JAVA应用方面的知识,加深了对计算机网络编程的了解。
参考文献
[1] 王晓春.PC游戏编程(人机博弈)[M].北京:清华大学出版社,2001
[2] 黎德玲.中国象棋的机器下棋[M].北京:清华大学出版社,2001
[3] 李琳.JAVA核心技术[M].北京:清华大学出版社,2001
[4] 杜诚.JAVA基础与提高[M].北京:人民邮电出版社,2001
[5] HYPERLINK /itbook/booklist.asp?zuoz=%A3%A8%C3%C0%A3%A9Nils+J%2ENilsson \t _blank Nils J.Nilsson.人工智能[M].美: HYPERLINK /itbook/publisher_jx.asp \t _blank 机械工业出版社,2000
[6] HYPERLINK /search/search.asp?Author=林尧瑞 \t _blank 林尧瑞. HYPERLINK /usercenter/addfavbook.asp?id=2922 人工智能导论[M] .北京: HYPERLINK /search/search.asp?publisher=清华大学出版社 \t _blank 清华大学出版社 ,2001
[7] 尼尔松.人工智能[M].北京: HYPERLINK /search/search.asp?publisher=机械工业出版社 \t _blank 机械工业出版社, 2001
[8] 那威,张照元.连珠五子棋提高捷径入段升级必读[M]. 北京:北京体育大学出版社,1998
[9] Erich Gamma, Richard Helm, Ralph Johnson, John Vlissides.可复用面向对象软件的基础[M].北京:机械工业出版社,2000
[10] Donald E. Knuth. The Art of Computer Programming[M]. Addison-Wesley,1998
[11] 雷超阳,徐正权,张治元.基于C/S模式中影响数据库系统性能的研究[J].电脑信息技术.2005,
24(1):4~7
[12] 赵子义,李明.Java Socket 编程详解[J].计算机科学.2003,20(2):11~12
[13] 曾亚纯,彭远威.数据库设计与编程实例详解[J].信息与电脑.2001,15(5):15~17
[14] 杨世清.基于网络环境的游戏开发技术[J].武汉科技报.2004,18(10):10~13
[15] 李达.现代游戏开发技术[J].计算机学报.2003,14(3):33~40
[16] 萨师煊,王珊.计算机网络概论[J].电脑信息报.2001,19(1):30~39
[17] 蔡自兴.人工智能技术[J].计算机学报.2002,20(2):5~9
[18] Wiki Discussiion,Cost of Design carry./cgi/Wiki?cost of Design Carry,1999
[19] 许正熙,信息管理论文.论文急救中心.,2001
致谢
最后,我要感谢在这段时间内对我的工作进行指导的孙建平老师。在程序的实现过程中,她的指导使我对网络游戏和计算机网络编程的认识更加深刻,对人工智能的讲解对我来说是全新的,非常有吸引力的。在程序的设计过程中遇到困难的时候,她及时的给了我建议与支持,使得毕业设计能够顺利进行,并在规定的时间内完成各项任务。
感谢系里领导为我们学生毕业设计过程中提供的各种方便、理解与支持。有了他们的支持我的毕业设计才能如期完成。
感谢JAVA中文论坛中开展的讨论,我在那里学到了许多关于JAVA网络编程方面的知识,在写论文的过程中和程序实现上遇到疑问的时候,从那里也得到了很多启发。
我还要感谢同组的同学,在设计和调试遇到困难的时候,很多都是依赖与他们的交流。是他们的鼓励和热心帮助让我顺利的完成了设计任务。
附录
Message类
//Message 类是客户端与服务器端传送的消息对象
import java.io.Serializable;
/**
* message list
* type = 1 // request of connected,msg = connectors name
* type = 2 // put chessman
* type = 3 // request play with another
* type = 4 // deny a request for play
* type = 5 // agree with request
* type = 6 // send victory message
* type = 7 // send disconnection
* type = 8 // save game but not to disk,it will be lost when next start
* type = 9 // add new player to all clients player list
* type = 10// response for message type ==1
* type = 11// play with a player,msg save players name ,game set by
* // the one who create game
* type = 12// setting information
* type = 13// setting player color
* type = 14// msg for acceptor B to setting color and setings
* type = 15// server update message
* type = 16// send messages of control or errors
* type = 17// failed in the game
* type = 18// server socket close
* type = 19// player end a game and refresh
* tyep = 20// computer win / people win
*/
public class Message implements Serializable{
byte type; // message type ,eg.1=request of connection
boolean setting; // 是否设置禁手
int color; // chessman color ,1 = black ,2 = white
boolean forYourTurn; // judge whether it is for receivers turn
int coordinateX; // record the coordinate X from 0~14 ,save black or white
int coordinateY; // record the coordinate Y from 0~14 ,save black or white
char[] msg;
public Message(){
setting=true;
msg = new char[50];
}
}
Player类
Player类用于初始化一个玩家信息
import .Socket;
public class Player {
String self=null;
ServeOneClient selfSocket=null;
boolean setting = false;
int color = 1;
public Player(){}
}
Group类
//Grout类用于定义一个对战玩家组,每两个玩家接受对战时,系统会将他们编为一组并从玩家列 //表消失
public class Group {
String self=null;
ServeOneClient selfSocket=null;
String player = null;
ServeOneClient playerSocket =null;
int selfColor = 0;
int playerColor = 0;
boolean Setting = false;
int board[][];
public Group(){
board = new int[15][15];
}
}
Server类
//Server类用于初始化服务器端的监听程序
import java.io.*;
import .*;
import java.util.ArrayList;
public class Server {
public static final int PORT = 8180;
public static ArrayList playerList = new ArrayList();
public static ArrayList groupList = new ArrayList();
public static void main(String[] args)throws IOException {
ServerSocket s = new ServerSocket(PORT);
System.out.println(Welcome using ChessWZQ1.0 server (alpha test)...\nAuthor:张良周\nCopyright:scitel \nMail:skywolf_2002@163.com);
System.out.println(Server Started at port +PORT+...);
System.out.println(This is on the server!);
try {
while(true) {
// Blocks until a connection occurs:
Socket socket = s.accept();
try {
System.out.println(create a socket frome server);
ServeOneClient server = new ServeOneClient(socket);
Player client = new Player();
client.selfSocket = server;
playerList.add(client);
System.out.println(playerList.size():+playerList.size() );
//System.out.println(Client);
} catch(IOException e) {
// If it fails, close the socket,
// otherwise the thread will close it:
socket.close();
}
}
} finally {
s.close();
}
}
}
InetAddressTest类
InetAddressTest类用于初始化服务器端的IP地址址信息。
import .*;
public class InetAddressTest {
public InetAddressTest() {
}
public static void main(String []args) throws UnknownHostException {
InetAddress Address=InetAddress.getLocalHost();
System.out.println(The Address:+Address);
Address=InetAddress.getByName(ANDY);
System.out.println(The Address:+Address);
InetAddress sw[]=InetAddress.getAllByName(ANDY);
for(int i=0;isw.length;i++)
System.out.println(The Address:+sw[i]);
}
}
BoardPanel类
//BoardPanel类主要用于画出棋盘,处理棋盘事件
import java.awt.*;
import java.awt.event.*;
import java.util.Arrays;
import javax.swing.*;
import java.io.*;
public class BoardPanel extends JPanel{
private static Image white = null;
private static Image black = null;
private static int xp; // position of x to put chessman
private static int yp; // position of y to put chessman
private Cursor handCursor;
private Cursor defaultCursor;
protected static int board[][]; // record of each position black or white
private int color=1; // record players chess color 1=black 2=white
int STEPCOUNTER=0;
int BASE=5;
int DEEPTH=3;
int MINDEEPTH=3;
int MAX1=5;
long INVALID=9000000;
int chessBoard[][];
// draw the line number with x/y direction
String line = a b c d e f g h i j k l m n o;
char [] rowNum1 = {1,2,3,4,5,6,7,8,9};
char [] rowNum2={1,0,1,1,1,2,1,3,1,4,1,5};
public BoardPanel(){
try {
handCursor=new Cursor(12);
defaultCursor = new Cursor(0);
board = new int[15][15];
jbInit();
}
catch(Exception e) {
e.printStackTrace();
}
}
public void paint(GraphiC/S gc){
super.paint(gc);//question
gc.setColor(Color.blue);
gc.drawString(line,25,15);
for(int i=0;i9;i++){
gc.drawChars(rowNum1,i,1,10,35+i*30);
}
for(int i=9,j=0;i15;i++,j+=2){
gc.drawChars(rowNum2,j,2,10,35+i*30);
}
for (int i = 0; i 15; i++) {
gc.drawLine(30, 30 + i * 30, 450, 30 + i * 30); //draw raw
gc.drawLine(30 + i * 30, 30, 30 + i * 30, 450); //draw column
}
gc.drawLine(25, 25, 455, 25);
gc.drawLine(25, 25, 25, 455);
gc.drawLine(25, 455, 455, 455);
gc.drawLine(455, 25, 455, 455);
//when window repaint to replay the original status of board
for(int i=0;i15;i++){
for (int j = 0; j 15; j++) {
xp=16+i*30;
yp=16+j*30;
if (board[i][j] == 1){
gc.setColor(Color.black);
gc.fillOval(xp,yp,28,28);
//gc.drawImage(black, 16 + i * 30, 16 + j * 30, this);
}
if (board[i][j] == 2){
gc.setColor(Color.white);
gc.fillOval(xp,yp,28,28);
//gc.drawImage(white, 16 + i * 30, 16 + j * 30, this);
}
}
}
}
private void jbInit() throws Exception {
this.addMouseMotionListener(new ChessWZQ_this_mouseMotionAdapter(this));
this.addMouseListener(new ChessWZQ_this_mouseAdapter(this));
}
public int getColor(){
return color;
}
public void setColor(int cr){
color=cr;
}
/**
* clear board when updated
*/
public void clearBoard2(){
for(int i=0;i1;i++){
for(int j=0;j17;j++)
board[i][j]=0;
}
repaint();
}
public void clearBoard(){
for(int i=0;i15;i++){
for(int j=0;j15;j++)
board[i][j]=0;
}
repaint();
}
void this_mouseClicked(MouseEvent e) {
int x=0,y=0;
if(color==0){
return;
}
x=e.getX();
y=e.getY();
System.out.println(In BoardPanel getX() and getY(): (+x+,+y+)) ;
//System.out.println(In BoardPanel getX()+y) ;
if(x20x460y20y460(x%3010||x%3020)(y%3010||y%3020)){
if(ChessWZQ.beginFlag==false){
ChessWZQ.label6.setText(You may not do that);
return;
}
xp = x / 30 * 30 - 14;//question
yp = y / 30 * 30 - 14;
if (x % 30 20) {
xp += 30;
}
if (y % 30 20) {
yp += 30;
}
x=xp/30;y=yp/30;
if(board[x][y]!=0){
return;
}
// client s board
board[xp / 30][yp / 30] = color;
GraphiC/S g=this.getGraphiC/S();
if(color==1){//black
g.setColor(Color.black);
}
if(color==2){//white
g.setColor(Color.white);
}
g.fillOval(xp, yp, 28, 28);
ChessWZQ.beginFlag=false;
if(ChessWZQ.ptocFlag==false){
Message msg = new Message();
msg.color = color;
msg.coordinateX = x;
msg.coordinateY = y;
msg.type = 2; //press chessman
try {
ChessWZQ.out.writeObject(msg);
}
catch (IOException ee) {
ee.printStackTrace();
}
}
char cc = (char)(x+65);
ChessWZQ.label6.setText(put on ( +cc+ , +(y+1)+ ));
}
}
public void strToCharArray(String str,char [] arr){
int i;
for(i=0;istr.length()i49;i++){
arr[i] = str.charAt(i);
}
arr[i]=\0;
}
protected int getXP(){
return xp/30;
}
protected int getYP(){
return yp/30;
}
/**
* put a chessman and display it (x,y) position on the panel
* draw chessman on (x,y)
* @param x
* @param y
*/
public void drawChess(int x,int y){
GraphiC/S g=this.getGraphiC/S();
char cc = (char)(x+65);
int temp = y+1;
x=x*30+16;
y=y*30+16;
if(color==1)
g.setColor(Color.white);
else
g.setColor(Color.black);
g.fillOval(x, y, 28, 28);
ChessWZQ.label6.setText(Player put on ( +cc+ , +temp+ ));
}
/**
* update board status when B put a chessman
* @param x Bs chessmans X coordinate 0=x15
* @param y Bs chessmans Y coordinate 0=y15
*/
public void updateBoard(int x,int y){
int tcolor=0;
if(color==1) tcolor=2;
else tcolor=1;
board[x][y]=tcolor;
}
public char intToChar(int x){
char temp=\0;
if(x=0x=9)
temp=(char)(48+x);
else if(x=10 x=15){
temp=(char)(55+x);
}
return temp;
}
/**
* mouseMoved Event
* @param e
*/
void this_mouseMoved(MouseEvent e) {
int x=0,y=0;
x=e.getX();
y=e.getY();
if(x20x460y20y460(x%3010||x%3020)(y%3010||y%3020)){
this.setCursor(handCursor); //HAND_CURSOR
}
else{
this.setCursor(defaultCursor);
}
}
/**
* judge if a man win the game
* @param x the newest kids x coordinate
* @param y the newest kids y coordinate
* @return
*/
protected boolean judge(int x,int y,int clr){
int i=0,j=0,count=0;
boolean flag=true;//judge is life or dead.
String strX;
// x direction
for(i=0,count=0;x-i=0i5;i++){
if (clr==board[x-i][y]){
count++;
}else{
if(board[x-i][y]!=0){
flag=false;
}
break;
}
// System.out.println(( +x+ , +y+ )+count = +count);
if(count==5)
return true;
}
for(i=1;x+i15i5;i++){
if(clr==board[x+i][y]){
count++;
}else{
if(board[x+i][y]!=0){
flag=false;
}
break;
}
strX=judgeChess(count,flag);
if(count==5)
return true;
// if (board[x-i][])
}
// y direction
for(i=0,count=0;y-i=0i5;i++){
if (clr==board[x][y-i]){
count++;
}else{
break;
}
// System.out.println(( +x+ , +y+ )+count = +count);
if(count==5)
return true;
}
for(i=1;y+i15i5;i++){
if(clr==board[x][y+i]){
count++;
}else{
break;
}
// System.out.println(( +x+ , +y+ )+count = +count);
if(count==5)
return true;
}
// \ direction
for(i=0,count=0;x-i=0y-i=0i5;i++){
if(clr==board[x-i][y-i]){
count++;
}else{
break;
}
// System.out.println(( +x+ , +y+ )+count = +count);
if(count==5)
return true;
}
for(i=1;x+i15y+i15i5;i++){
if(clr==board[x+i][y+i]){
count++;
}else{
break;
}
// System.out.println(( +x+ , +y+ )+count = +count);
if(count==5){
return true;
}
}
// / direction
for(i=0,count=0;x+i15 y-i=0 i5; i++){
if(clr==board[x+i][y-i]){
count++;
}else{
count=0;
}
// System.out.println(( +x+ , +y+ )+count = +count);
if(count==5)
return true;
}
for(i=1;x-i=0 y+i15 i5;i++){
if(clr==board[x-i][y+i]){
count++;
}else{
break;
}
// System.out.println(( +x+ , +y+ )+count = +count);
if(count==5){
return true;
}
}
return false;
}
class Queue{
int position;
long m
文档评论(0)