游戏简介:
在欧美英语国家,Knock Knock Jokes是一个非常流行的语言类游戏,是训练孩童、小学生语言表达能力和想象能力的有趣途径,因此这个游戏常见于家庭或朋友之间的娱乐场合。这个游戏有两个玩家,一个扮演敲门人,一个扮演开门人。我们这里分别称之为“outdoor”和“indoor”。
Knock!Knock!
Who’s there?
Eye
Eye Who?
Ice cream
Buster 捣蛋鬼
Buster Cherry 大樱桃
制作过程:
1、 新建项目 KKServer和KKClient
2、 先做客户端,在客户端的包里,新建JFrame界面,命名为ClientUI;再做服务器端,命名为ServerUI
客户机:
服务器:
3、 运行一下所做的界面
服务器端:
1、 双击启动服务器按钮
2、 往前找,窗体里先进行变量初始化(该import的import)
3、 回到启动服务器按钮的事件,添加事件
4、 从文本框里,获取主机相应的IP地址和端口号,存到对应的变量当中(还是在启动服务器按钮的事件中)
5、 构建套接字地址,存数据(IP地址和端口号)(先不抛异常)
6、 创建ServerSocket对象,绑定套接字==开启端口(也是先不抛异常)
7、 定义线程池大小(先获取当前可使用处理器个数)
8、 根据处理器个数来确定线程池的大小(一般一个CPU跑两个线程)(这个可以import)
9、 获取线程的编号(线程编号是自动命名的,我们只需要获取,存到currentId里)
10、 连接上之后,服务端加上一个反映,告诉我们有人连上了。开启端口之后显示的内容
11、 抛异常,再改成IO异常,删掉捕获之后的内容(整体截个图)
12、 运行试试
客户端:
1、 双击 连接服务器 按钮
2、 转到最上面先变量初始化(import)
3、 回到按钮事件,先获取要连接的服务器ID和端口号
4、 构建套接字对象(import)
5、 创建Socket对象,去连接远程地址(套接字)先不抛
6、 输入输出流监听(import但不抛异常)
7、 接收并显示获取信息(服务器输入的)先不抛
8、 处理异常,第一个,语句块,直接就是IO异常,然后修改catch之后的内容(import)
9、 没有返回,证明连接成功,将按钮设置不可用
10、 保存运行,先开服务端,再开客户端(没报错就代表正常,可以修改端口号,再连接,会报错,也是正常)
11、 改个东西
通信协议设计:
语法语意同步(怎样讲、讲什么、谁先讲)
游戏过程:(定义为4步,编号为0,1,2,3)
定义协议编码(回到KKServer服务端):
1、 新建一个Java类
2、 变量初始化
前四个变量标识着游戏进行到第几步,这些变量都是隶属于这个协议类的,不能重写、修改
定义游戏的总局数为8
当前会话进行到哪一步,要统计一个会话状态,默认是waiting,服务器开启端口等待连接状态
最后一个变量是计数,当前游戏一共八个词,我玩到第几个了
KKServer服务端:(在Protocol里面)
1、 线索词库
2、 答案词库(太长了,我给分行了)
3、 在这个类里定义一个方法(需要返回值,这里的返回值先是null,后面会改)
4、 下面开始实现流程,用选择语句实现,先看选择语句(多分支选择语句),里面内容放到下一步实现
5、 下面往switch括号里添加东西
a) 第一个选择分支(WATTING状态)
b) 第二个选择分支(SENTKNOCKKNOCK状态)
如果问who’s there,那我找出当前的第一个线索词作为回复,回复回去
如果不是who’s there,给个提示,你应该问who’s there,然后重新开始敲门
c) 第三个选择分支(SENTCLUE状态)
如果问对了,就给出当前库里的第一个回答,返回回去
状态跳转到已发送答案的状态(SENTANSWER)
如果没问对,给提示,然后重新敲门
d) 第四个选择分支(SENTANSWER状态)
如果把答案发出去了,问是否继续,y/n(是或者不是),如果是 是 ,重新开始敲门,如果总局数等于7,则证明是最后一局,那么当前线索词回到第一个(0号就是第一个),算第一局开始;如果不是最后一局(第7局),那么线索词序号+1,不论怎样,接下来都会到敲门的那一步,然后开始循环
如果不继续,那就发送 Game Over! Goodbye! ,然后回到WAITING状态
6、 修改返回值,从null改为answer
协议类到此为止就完成了
7、 在服务器端新建客户端的线程类(ClientThread)
8、 首先,此客户端线程类继承Thread类
9、 做变量初始化的工作,该import的import(toClientSocket未定义,所以会有个错误)
10、 构造函数(构造函数写完,上一步的toClientSocket错误也没了)
11、 重写run函数(在构造函数的外面哦)
12、 输入输出(在run函数里)(先import,不try catch)(txtArea是txtArea1)
13、 创建协议对象
14、 使用协议对象开始聊天了
15、 服务器显示一段内容(我在做窗体的时候,起的名是Area1,正常应该只是Area)
16、 反复和客户机进行对话(这里用的while循环)先不try catch
17、 关闭,先不try catch
18、 抛异常,最上面那个异常,选择块,然后删掉IO异常后面的捕获内容,捕获之后并不需要什么操作
ServerUI:
双击 启动服务器 按钮(前几节课已经编辑过了,接着以前的编辑)
1、 一客户一线程
2、 加循环,加到刚才写的run里面
3、 判断连接
4、 在当前窗体的文本框里添加一句话(我的窗体是txtArea1,正常应该是txtArea)
5、 抛异常,语句块。这里修改一下抛的异常。将try{剪切到while前,将catch{},后面的},剪切到catch前面
6、 以上,启动服务器按钮就完成了,下面进行窗体关闭的事件。回到设计界面,选中整个窗体,选中Windowclosing事件
7、 在事件里添加的内容(最上面的异常 import一下,其他的就没异常了)
如果关闭的时候还有和客户端连接,那就把它关掉
如果还有连接,关掉
如果还有线程为空(服务器上的),就直接关闭了;如果还有没关闭的线程,等待60秒,再关闭,如果这时候还不为空(就是关不调),就强制关闭。强制关闭要是没关掉的话,再等一分钟,关了就返回,没关再等一分钟,再关闭。然后抛异常。
服务器端工作彻底完成
游戏模式图:
客户端:
1、 客户端 设计页面 选中“此处输入会话内容……”字段 让它不显示 右边的事件 添加focusgained事件 在事件中添加一段
2、 再添加一个回车就能发送,对命令按钮就是点击,对文本框来说就是回车
3、 下面在ActionPerformed事件里添加程序
a) 存储两个变量,判断连接是否为空,如果连上是肯定有信息系的,如果没有的话,提示错误信息
b) 获取在文本框里输入的信息,并判断文本框是否为空
判断好链接之后,将文本框的值存到一个变量里,如果这个值不为空,把文本框输入的内容发出去,发给服务器,发出去之后,还要将这句话添加到客户端的文本区域内,显示出来以后,就把刚才的文本框清空了,准备下一次输入,否则,如果输入的内容为空的话,就弹出提示信息
c) 不知道在干啥(先不抛异常)
d) 抛异常,改catch
4、 回到客户端设计界面,选中整个窗体,找到窗体的关闭事件,添加事件
5、 在窗体关闭事件里添加内容
6、 到目前为止,整个设计就算全部完成
7、 测试
a) 一台客户机 一台服务器
b) 两台客户机 一台服务器