本作业参考博客java课程设计-多人聊天工具(socket+多线程)的聊天室,以此作为模板实现双人游戏的联机效果
项目框架:
——————————以下为大作业报告———————————
1.题目描述
本程序功能介绍如下
(1)服务端能看到所有在线玩家(最多两名)
服务端继承了JFrame,实现可视化,通过socket实现服务端与客户端的连接,服务端每接收一个连接,把传进来的用户名和对应的socket连接封装成一个User对象,把User对象存进一个ArrayList的用户列表并把User对象通过取用户名方法取得用户名存进一个ArrayList的用户名列表,添加一个JPanel组件,将ArrayList中的内容通过循环显示JPanel中并布局在窗体的右边,在每当有人上线或者下线,刷新JPanel组件。
(2)服务端能够强制玩家下线
创建一个布局在窗体的下方的JPanel,在此JPanel中分别添加JLabel用于显示提示文字,添加JTextField用于获取服务端想要强制用户下线的ID,添加JButton用于绑定强制用户下线的事件监听,事件监听中将获取的JTextField的内容与用户名列表进行逐一匹配,匹配上则创建JSON格式的键值对对象,通过用户列表循环广播告知其他用户,并在用户列表和用户名列表中分别删除该用户信息。
(3)客户端能够看到所有在线玩家
客户端继承了JFrame,实现可视化,添加了一个布局在窗口右边的JLable,把从服务端接收到的另一名玩家信息放进去。
(4)客户端能够同步游戏准备和游戏操作等信息
客户端点击选择角色或者在游戏中进行操作时,会向客户端发送信息,服务端接受,通过判断msg键对应值为选择角色或者游戏操作后,再发送给对应玩家的客户端,客户端接收信息后再调用相应的方法控制对应组件进行游戏
(5)运用JDBC实现持久化存储用户信息
数据库连接池运用了阿里巴巴的durid,定义一个JDBCUtils类,提供静态代码块加载配置文件,初始化连接池对象,通过Spring框架的JDBCTemplate对象进行sql语句的执行,在UserDao中提供了登录和注册、分数更新方法,登录方法运用queryForObject方法进行登录查询,如果查到返回一个User对象,查不到则返回空,注册方法直接插入新记录,此处建表语句中把用户名设置成了主键,保证了用户名的唯一性,注册失败有警告弹窗提示。游戏结算时会调用分数更新方法上传玩家分数到数据库。
(6)使用JSONObject对象封装数据
在数据的传输中运用了键值对的形式进行传输,客户端传输给服务端的数据包中,通过判断msg键对应的值是否包含contorl或者踢出来确认是否为同步游戏操作指令,通过username键告知服务端客户端的用户名,通过select键传输选择的游戏角色信息、通过up键传输游戏角色向上的运动信息等…服务端传输给客户端的数据包中,通过判断user_list键的值来确认在线用户及人数
2.程序设计
类图如下
2.1 User类
该类的作用是对一个玩家信息进行封装,包含以下变量和方法:
表1 User的变量
名字 | 类型 | 作用 |
---|---|---|
socket | Socket | 用户对应的Socket连接 |
password | String | 用户的密码 |
username | String | 用户的用户名 |
score | Int | 用户的累计分数 |
表2 User的方法
名字及类型 | 参数列表及用途 | 方法作用 |
---|---|---|
User() | 构造玩家对象 |
2.2 UserDao类
该类的作用是访问数据库,查询玩家信息和对游戏分数进行上传
表3 UserDao的方法
名字及类型 | 参数列表及用途 | 方法作用 |
---|---|---|
UserDao() | 构造访问数据库的对象 | |
int register(User) | User register_user 注册玩家对象 | 注册账号 |
User login(User) | User login_user 登录玩家对象 | 登录玩家账号 |
void updateScore(String,int) | String username 上传分数的用户名int score 上传的分数 | 上传游戏分数 |
2.3 Register类
该类的作用是打开注册用户界面,将输入的账户密码进行注册
表4 Register的方法
名字及类型 | 参数列表及用途 | 方法作用 |
---|---|---|
Register() | 构造注册用户窗口对象 |
2.4 Client类
该类的作用是启动客户端,让玩家登录自己的账号
表5 Client的方法
名字及类型 | 参数列表及用途 | 方法作用 |
---|---|---|
Client() | 构造客户端窗口,让玩家登录账号 | |
void main(String[]) | 主函数,用于打开客户端 |
2.5 Server类
该类的作用是启动服务端,接收客户端的消息,发送命令消息给客户端
表6 Server的方法
名字及类型 | 参数列表及用途 | 方法作用 |
---|---|---|
Server() | 构造服务端窗口,显示在线玩家信息 | |
void main(String[]) | 主函数,用于打开服务端 |
Server还有继承了Runnable的内置类ServerThread作为接收发送消息线程
表7 Read的方法
名字及类型 | 参数列表及用途 | 方法作用 |
---|---|---|
ServerThread(Socket) | Socket socket存放全局变量socket | 构造方法 |
void send_msg(String,int,String,int) | String username 发送者用户名int i 接收者的序号String msg 发送的消息int select 发送者选择的游戏角色序号 | 发送玩家的状态消息给另一名玩家 |
void run() | 持续接收客户端的消息 |
2.6 JDBCUtils类
JDBC工具类,操作数据库
表8 JDBCUtils的变量
名字 | 类型 | 作用 |
---|---|---|
dataSource | DataSource | 加载配置文件,初始化连接池对象 |
表9 JDBCUtils的方法
名字及类型 | 参数列表及用途 | 方法作用 |
---|---|---|
JDBCUtils() | 构造JDBC工具类 |
2.7 GameRoom类
该类的作用是玩家后登录进入游戏准备房间,显示在线联机的另一名的玩家信息和其选择的角色,双方都选择角色后倒计时开始游戏
表10 GameRoom的方法
名字及类型 | 参数列表及用途 | 方法作用 |
---|---|---|
GameRoom(String int) | String username 传用户名int score 传获取到的玩家累计分数 | 构造准备房间窗口,显示另一名玩家信息 |
void launch() | 启动窗口方法,用于添加窗口组件 |
GameRoom还有继承了Runnable的内置类Read持续接收服务端的消息
表11 Read的方法
名字及类型 | 参数列表及用途 | 方法作用 |
---|---|---|
Read() | 构造方法 | |
void run() | 持续接收服务端的消息,游戏开始后结束 | |
void time() | 准备好后进行倒计时,倒计时后启动游戏 |
2.8 Play类
该类的作用是让玩家进入游戏界面,同步双方的指令信息联机进行游戏
表12 Play的方法
名字及类型 | 参数列表及用途 | 方法作用 |
---|---|---|
Play(String,int,int,Socket) | String username 传用户名int select 传玩家选择的游戏角色序号int score 传获取到的玩家累计分数 | 构造游戏窗口,玩家操控自己选择的游戏角色,并与另一名玩家联机进行 |
void control(int,Boolean,Boolean,Boolean) | int select 传给服务端要控制的角色序号Boolean up 该角色的上方向参数Boolean left 该角色的左方向参数Boolean right 该角色的右方向参数 | 发送控制信息给服务端,服务端接收后再发送控制指令给两名玩家进行窗口上角色的控制 |
void setback() | 向游戏界面添加背景、场景物品等 |
Play还有继承了Runnable的内置类Read持续接收服务端的消息
表13 Read的方法
名字及类型 | 参数列表及用途 | 方法作用 |
---|---|---|
Read() | 构造方法 | |
void run() | 持续接收服务端的消息 |
Play还有继承了Thread的内置类TimeThread作为计时器线程
表14 TimeThread的方法
名字及类型 | 参数列表及用途 | 方法作用 |
---|---|---|
TimeThread() | 构造方法 | |
void run() | 持续进行游戏的倒计时,并进行游戏是否结束的判断 |
2.9 Mykey类
该类的作用是监听键盘事件,调用Play.control方法发送控制信息
表15 Mykey的方法
名字及类型 | 参数列表及用途 | 方法作用 |
---|---|---|
Mykey(Play,int) | Play play 传游戏主体对象int select 传操控的游戏角色序号 | 构造监听键盘类 |
void keyReleased(KeyEvent) | KeyEvent e 键盘的释放按键操作 | 停止游戏角色的运动 |
void keyPressed(KeyEvent) | KeyEvent e 键盘的按下按键操作 | 根据键盘的操作调用发送控制信息方法来控制对应游戏角色 |
2.10 FirePeople类
该类的作用是控制火人角色的各种行为,控制火人运动、结束游戏等
表16 FirePeople的方法
名字及类型 | 参数列表及用途 | 方法作用 |
---|---|---|
FirePeople(Play) | Play play 传游戏主体对象 | 构造火人角色类 |
void gain() | 获取火人通过吃钻石获得的分数 | |
void move(boolean,boolean,booleean) | boolean up 该角色的上方向参数boolean left 该角色的左方向参数boolean right 该角色的右方向参数 | 根据获得的方向信息来控制游戏角色 |
void verdict(int) | int i 游戏结束时火人的状态 | i为1时游戏胜利,i为2时游戏失败,最后调用updateSocre结算分数上传数据库 |
void run() | 控制角色上下移动的进程 |
2.11 IcePeople类
该类的作用是控制冰人角色的各种行为,控制冰人运动、结束游戏等
表17 IcePeople的方法
名字及类型 | 参数列表及用途 | 方法作用 |
---|---|---|
IcePeople(Play) | Play play 传游戏主体对象 | 构造冰人角色类 |
void gain() | 获取冰人通过吃钻石获得的分数 | |
void move(boolean,boolean,booleean) | boolean up 该角色的上方向参数boolean left 该角色的左方向参数boolean right 该角色的右方向参数 | 根据获得的方向信息来控制游戏角色 |
void verdict(int) | int i 游戏结束时冰人的状态 | i为1时游戏胜利,i为2时游戏失败,最后调用updateSocre结算分数上传数据库 |
void run() | 控制角色上下移动的进程 |
3.运行结果及测试
*3.1 启动服务端*
*3.2 启动客户端*
*3.3 登录进入游戏准备房间*
*只有一名玩家在线时会提示请等待另一名玩家*
*3.4两名玩家同步角色选择*
*两名玩家未选择角色,此时已更新另一名在线玩家*
*玩家选择角色后,另一名玩家同步显示被选择的角色*
*3.5准备好后游戏即将开始*
*两名玩家都选择角色后进行倒计时开始游戏*
*3.6进入游戏界面*
*进入游戏界面后,左上角显示玩家对应操控的角色*
*3.7联机同步进行游戏*
*两名玩家同时控制游戏角色进行游戏*
操作方式为方向键的上下左右操控
*3.8游戏胜利*
*两名玩家都到达终点,结算分数*
*3.9游戏失败*
*有任一玩家因时间结束或者触碰禁区游戏失败后,按各自吃的钻石数结算游戏分数*
*3.10服务端同步游戏信息*
*在服务端可以查看到在线玩家和玩家选择游戏角色、进入游戏等信息*