Skip to content

iDTer/wordwar

Folders and files

NameName
Last commit message
Last commit date

Latest commit

 

History

7 Commits
 
 
 
 
 
 
 
 
 
 
 
 
 
 

Repository files navigation

wordwar

一、目的与要求

题1:用JavaSocket编程开发英语六级词汇学习对战游戏

(1) 在网上自行下载英语六级词汇表。存到文件中,格式自定。

(2)该游戏支持两人通过网络对战,测试双方对英语六级词汇的熟悉程度。

(3)首先运行服务器。服务器运行之后,两个客户可以加入对战游戏中。

(4)运行客户端。用户能够输入昵称,确定,则连接到服务器。连接成功,即可出现游戏界面。

(5)客户端游戏界面如下:系统随机选择一个六级英文词汇,同时从两个客户端顶部落下,底部有四个中文释义,分别为选项A、B、C、D。其中有一个正确答案。

规则如下:

(1)每人初始生命值为20分。

(2)英文词汇从界面顶部落下时,用户按下键盘,选择A、B、C或者D。选项快速射向单词。如果选项正确,则自己加1分,对方减1分;如果错误,自己减1分,对方加1分。

(3)一旦有用户选择了选项,该单词下落过程结束。重新出现新的单词从顶部落下,选项更新。

(4)词汇掉到用户界面底部,如果两个用户都还没做出选择,两个用户减1分,重新出现新词汇,选项更新。

(5)某用户如果生命值率先变为0分,则判输,游戏退出。

(6)游戏退出后,每个用户保存3个文件,分别存储判断正确的单词表、判断错误的单词表、未判断的单词表。便于用户复习。

二、操作环境

硬件: Windows 10

软件: IntelliJ IDEA

三、内容

介绍代码文件结构,每个文件中有哪些类和函数,各起到什么作用

首先是游戏的客户端,其中包含的类和函数如下:

1、客户端的GamePanel主类

继承了Runnable,ActionListener,KeyListener接口。 其中的函数有:

初始化整型life = 20,

搭建好用于与服务器收发消息的Socket、BufferedReader、PrintStream,

新建一个Timer,传入的参数(300,this)。

(1)、writeFile函数:

调用时传入两个字符串参数,第一个字符串表示需要写入的文件名,第二个字符串表示将写入的字符串,在这里用于写入判断正确或判断错误的词汇,分两个文件存储写入就好。

(2)、init函数:

不需要传入参数,用于初始化掉落的单词JLabel:lbMoveChar,然后在其中调用readLineFile函数,并且传入两个参数,一个是“filename”,另一个是在词汇文档中用于随机按行读取词汇的整型数据il,接下来,再将四个选项JLabel;lbA,lbB,lbC,lbD,初始化一遍,设置好初始位置。并且lbMoveChar设置好标题,即将readLineFile函数中改写的存有掉落六级词汇的全局变量word,设为它的标题。最后,将lbMoveChar设置在掉落的初始位置。

(3)、checkFail函数

无参数,由于程序框架结构,它用于在每次客户端实现全局变量生命值的整型数life改变后,重新设置一遍lbLife(即显示生命值的一个控件),并且在此函数中实现,若用户如果生命值变为零,则判输,游戏退出,并提示“生命值耗尽,游戏失败!”。

(4)、actionPerformed函数

函数的作用就是实现若词汇掉到用户界面底部,如果两个用户都还没做出选择,两个用户减1分,即若if(lbMoveChar.getY() >= this.getHeight())判断为true,则既将这个掉到用户界面底部的词汇写入wrong.txt,然后调用checkFail(),并且向服务端发送“ASKRN#”;若判断为false,则lbMoveChar控价继续以一定的高度下掉。

(5)、readLineFile函数:

这个函数用synchronized同步锁锁定,因为在我进行编程的过程中,出现过:下落的词汇没有正确选项的情况,经过测试后发现,原来是因为多线程使用重复更新lbA,lbB,lbC,lbD,把四个选项A、B、C、D的值多次重复更新,然后就将本在后面调用的读取词汇中文的更新为此次的选项。

解决方法:直接把synchronized关键字直接加在函数的定义上,使得整个函数都同步,原理为:当某一线程运行同步代码段时,在“同步锁对象”上置一标记,运行完这段代码,标记消除。其他线程要想抢占CPU运行这段代码,必须在“同步锁对象”上先检查该标记,只有标记处于消除状态,才能抢占CPU。函数传入两个参数,一个为读取文件的路径,二个为整型的由服务器产生的随机数il,表示此次读取第几行的词汇。

接下来一个while循环的判断条件为(br.readLine() != null && il >= 0),即表示若文档中仍有下一行,且il大于等于0就继续执行,每一个il--,直到读取到指定行,就把此行存入一字符串中,String的split方法支持正则表达式;正则表达式\s表示匹配任何空白字符,+表示匹配一次或多次。把分离了的词汇与翻译存入一个String数组中,把strs[0]赋给全局字符变量word中。

然后产生一个随机范围为[0,4)的整数,若为0,则将正确选项存入A中,若为1,则将正确选项存入B中,若为2,则将正确选项存入C中,若为3,则存入D中。

(6)、keyPressed函数:

因为主类GamePanel主类继承了KeyListener,所以重写keyPressed函数。先把按的键的值赋给字符keyChar,再使用valueOf将其转换成字符串keyStr。判定keyStr是否和Opt(正确选项)相等,就调用writeFile,把strSave存入路径名为"D:\right.txt"的文档中,且life值自加2,并向服务器发送“LIFE#-1”。否则将其写入路径名为"D:\wrong.txt"的文档中,且life值自减2,并向服务器发送“LIFE#1”。

(7)、GamePanel的构造函数:

布置游戏界面,加入控件:lbLife,lbA,lbB,lbC,lbD,lbMoveChar,并调用init函数初始化,加入addKeyListener。

(8)、run函数:

​ 设置好canRun标识符,控制while循环,初设为true,直到运行时抛出异常,则设置canRun为false,结束循环,并且弹出提示为“游戏异常退出!”的窗口,点确定后退出。

​ while循环中,一直读取来自服务器端的消息br,并且存入字符串str中,将str用split将“#”分离开,存入strs字符串数组中。若(strs[0].equals("START"))判断为真,即传来的消息开头为“START”,则把消息中服务器随机产生的数赋值给读取文档用的il,否则若(strs[0].equals("LIFE"))判断为真,则此消息代表为生命值的增减,将strs[1]使用Integer.parseInt转换为整型,且存入score中。

​ 接下来将生命值的增减加入life中,再调用checkFail()函数,将这个界面面板更新。

​ 且若(strs[2].equals("START"))判断为真,即代表此时strs[]的格式为“LIFE#-1#START#srn",则将strs[3]存入il中,否则若(strs[0].equals("UWIN"))判断为真,则timer.stop(),弹出标题为“游戏结束,你赢了!”,且退出。

(9)、main函数:

​ 调用 GameFrame函数。

2、客户端的GameFrame类:

​ 设置好进入时的一个窗口:标题是输入名称,然后把输入的字符串设置为客户端的标题。

3、服务器端的Server主类

ps:服务器代码在MyGame文件夹下。

(1)Server的构造函数:

​ 设置“服务器端”为窗口标题,设置好界面,具体见源码。

(2)run函数:

​ 首先调用sendMessage向所有的客户端发送“START#”+wn(随机生成的属于(0,640)的整型数)。然后一个while死循环,条件canRun初始值为true,循环中一直执行读取来自客户端发来的消息,存入字符串str中,然后用split把“#”分离开存入strs数组中。

​ 若(strs[0].equals("LIFE"))判断为真,即表示此为生命值消息,将生命值转发给所有的客户端,并且产生一个随机数,调用sendMessage把“LIFE#”+strs[1]+“#”+srn发送给所有的客户端。

否则若(strs[0].equals("WIN"))为真,则说明有一方生命值已经归为0,服务器端将这个消息发送给所有的客户端,因为生命值先减为0的客户端,即发出此消息的客户端先已退出,所以此处不影响它的判断。

四、截图

png

png

png

png

About

Java网络编程英语单词对战平台

Resources

Stars

Watchers

Forks

Releases

No releases published

Packages

No packages published

Languages