[TOC]
Pokemon对战程序是一个模拟用户的精灵之间对战的程序. 主要实现的功能包括用户客户端, 系统服务端, 用户的登录注册以及用户的精灵与电脑和用户的精灵和用户的精灵之间的对战和奖惩系统.
- 操作系统是manjaro, 使用Qt Creator + qt5.11.
- 客户端使用qt进行UI设计和交互
- 服务端使用C/S模型,UDP与客户端进行通信
- 服务端数据存储使用MYSQL的一个扩展数据库mariadb
这个模块包括精灵的基类pokemon.h和派生类例如highattck.h和ashe.h, 用户类usr.h, 以及精灵属性配置信息pokemonsetting.h ,传输数据包格式定义global.h和伤害类定义damageinfo.h。因为此模块为服务端和客户端公用, 所以以动态链接库(dynamic-link library)的形式添加到服务端与客户端中,也方便日后对精灵种类和属性的更新.
此模块中的类图间的关系如下图所示.
精灵的组成分为三层
- 第一层为抽象基类
pokemon, 实现基本的精灵属性和功能. - 第二层为抽象派生类, 将精灵种类详细的分为高攻击, 高防御, 高血量和高敏捷四种, 不同种族的精灵的主属性不同,例如高攻击的主属性为攻击力, 而高敏捷的主属性为攻击速度和回避率.
- 第三层则是具体精灵的派生类,包括
ashe,anne等精灵种族.
对于每个生成的精灵都有一些接口函数用于控制精灵的属性和动作
每个精灵都有自己的稀有度, 稀有度在精灵产生的时候随机确定, 包括N, U, R, SR, SSR, UR6个等级, 在生成精灵或者升级的时候, 不同稀有度对于属性的增益也是不同的, 在头文件pokemonsetting.h中,coForMain和coForNormal分别定义了对于不同稀有度,不同属性的增益系数。公式基本为新的属性值 = 旧的属性值×(1+稀有度对应的增益系数)
根据需求, 精灵的攻击方式分为两种, 普通攻击(base attack)和终极技能攻击(ultimate attack). 精灵攻击时均会调用Damageinfo Attack()函数进行攻击操作, 不同种族的精灵具有不同的概率决定一次攻击是普通攻击还是终极技能攻击。
其中对于攻击方来说:
- 普通攻击的计算只跟攻击力以及是否暴击有关, 暴击将对攻击数值具有增益作用。
- 终极技能攻击根据精灵拥有的终极技能具有独特的伤害计算公式以及特殊攻击效果。
根据需求,精灵分为四种种类(race)分别是高攻击(highattck),高血量(highblood),高防御(highdefense)和高敏捷(highspeed)。不同种类具有不同的基础属性和属性增长系数。 例如对于高攻击类型的精灵来说, 主属性是攻击力, 那么攻击力的基础属性值和增长系数相较于其他类型的精灵来说要高。代码示例如下:
//高攻击力型精灵的的初始属性值
//攻击力相较于其他类型精灵更高
//攻击速度, 闪避率, 暴击率相较于其他精灵略低
static const unsigned int BASEATTACK = 200;
static const unsigned int DEFENSEPOWER = 80;
static const unsigned int MAXHP = 1000;
static const double WSP = 0.3;
static const double AVOID = 0.08;
static const double CRITICAL = 0.1;
//升级时主属性增长系数, 主属性为攻击力
static const double coLevelupMain = 0.05;
//升级时其他属性增长系数
static const double coLevelupNormal = 0.02;
而不同的类型派生出确定的不同种族的精灵, 例如高攻击来说的精灵the_frozen_archer_Ashe。目前实现了三个不同种族的精灵,the_frozen_archer_Ashe, the_dark_child_Anne和the_crimson_reaper_Vladimir。不同种族的精灵具有不同的终极技能,也具有不同的终极技能攻击函数ultimateSkillAttack()。
为了通信方便, 用户类存储了从服务端数据库获取的用户信息,以及客户端程序运行时的信息,具体包括如下
- 用户账户的信息包括
- uid, 账户名等标识单个用户的数据
- 胜负场,徽章获取情况等用户信息
- 所持有的精灵列表
- 客户端运行时的地址与端口信息
并且提供设置用户信息, 获取对应用户信息的端口。
开发者可以使用构造函数
Usr生成已知用户实例或者新的用户实例。然后使用addPokemon接口对精灵列表进行扩充。
此模块位于pokemomodule项目下面的global.h文件中,它规定了客户端与服务端之间通信时信号帧的格式。
DataType为数据帧的格式,规定了之后context里面的内容, context的内容根据需要可能分成多段, 整体使用QJsonDocument存储
客户端位于PokemonClient项目中, 客户端程序是面向用户的。 用户通过客户端可以进行
- 账户的注册和登录
- 查看在线用户以及其信息
- 进行PVE和PVP不同决斗模式的战斗
主程序模块位于mainwindow.h。 主程序模块在程序启动时创建一个主窗口,并新建一个QStackLayout用于存放和切换主页面,注册页面, 登录页面,以及战斗页面等。并且初始化socket用于客户端和服务端的通信。
开始页面模块位于startmenu.h。该模块完成用户的登录操作,对用户输入的账户密码发送到服务端进行确认,根据结果决定跳转页面还是提示相应的作为信息.
注册页面模块位于signuppage.h。该模块完成用户的注册操作。 用户在输入相应需要的信息之后, 将信息发送至服务端进行处理, 根据返回结果跳转页面和做出相应的信息提示
主页面模块位于mainpage.h。该模块提供用户查看当前在线用户的信息和进行战斗选择的功能
用户信息模块包括playerinfo.h和pokemonchoose.h。该模块存储用户的个人信息和精灵列表信息。在用户需要的时候进行显示和选择.
战斗页面模块位于fightpage.h。该模块提供战斗结果的可视化界面。提供包括
- 双方精灵和持有者的属性和名字
- 血量,攻击力的实时变化
- 双方精灵的攻击和被攻击的数值和类型信息
服务器端完成与客户端的信息的交互,由udpserver.h模块处理。以及战斗系统的执行, 由fightcore.h模块负责。
服务端在设计的时候充分考虑到多用户,多客户端,多个用户端同时战斗的情景。客户端消息的处理采用线程池的方式,提高并发处理的能力。 战斗系统则使用线程,实现多个客户端同时战斗的需要。
消息处理模块位于udpserver.h中,包括UdpServer和ProcessData两个类。
Udpserver将管理在线用户列表,数据库等全局信息。并且接受来自客户端的消息,并将消息分配给ProcessData类中处理。
ProcessData则在线程池中完成对于客户端传来的消息的处理处理工作。
战斗核心模块位于fightcore.h中,此模块完成精灵对战的功能。 根据构建的参数的不同,进行包括PVE,PVP,普通决斗,死斗等不同模式组合的决斗过程。 并在战斗结束后与客户端进行交互,进行精灵升级,损失或者获得精灵,账户信息回写到数据库等操作。
本系统服务端数据库使用的是MariaDB,MariaDB数据库管理系统是MySQL的一个分支,主要由开源社区在维护,采用GPL授权许可。MariaDB的目的是完全兼容MySQL,包括API和命令行,使之能轻松成为MySQL的代替品。在存储引擎方面,10.0.9版起使用XtraDB(名称代号为Aria)来代替MySQL的InnoDB。
- 表pokemoninfo 用于存储用户的宝可梦信息, uid为用户uid, pokemonname是精灵名字, 每个人持有的精灵中不存在重复名字, pokemoninfo为精灵详细信息.结构如下图:
- 表usrinfo 用于存储用户的详细信息,uid为用户uid, usrinfo为用户的详细信息,例如胜负场等,结构如下图:
- 表usrdata, 用于存储用户的账户密码,结构如下:
目前的设计方法是通过UDP进行通信, 因为UDP不需要建立通信, 更加灵活.而且UDP只发数据包不负责数据包的确认,所以延迟更低, 适合游戏这种低延时的要求.
服务器使用多线程. 在处理客户端消息请求的时候, 因为请求的处理时间短,所以服务器将请求放在线程池内进行处理,线程池会根据当前处理情况进行并发优化.对于战斗过程,因为持续时间长,多以淡出使用进程来完成多个战斗过程同时进行
可以的, 战斗系统核心fightcore设计之初就是按照人与人匹配战斗的需求进行的, 通过不同的构造参数,核心会自动判断是人与人还是人与机器的战斗,从而做出不同的处理.
本系统着重考虑服务端的稳定性, 多用户的并发,以及处理错误和突发情况.尤其是错误和突发情况的处理,包括但不限于
- 如果客户端崩溃关闭,没有通知服务端怎么办. 解决方法:在服务端为每一个用户设置定时器, 定时检查客户端发来的特定数据包, 超时则判定用户已经下线
- 如果在精灵选择的时候用户将客户端强行关闭,不选择精灵送出怎么办.解决方法:设置定时器,超时则默认送出用于战斗的精灵.
- 如果在精灵选择的时候客户端崩溃,还会继续匹配吗. 解决方法:设置定时器, 超时则结束匹配
精灵设计的时候将其分为三级, 这样未来无论是扩展精灵的种类, 合适新增精灵的种族, 更或是调整精灵的属性信息都更为方便,也就是低耦合性












