文章目录
- 一、项目背景
- (一)用户管理
- (二)匹配对战
- (三)聊天功能
- 二、开发环境
- 三、核心技术
- 四、项目大流程
- 五、项目模块介绍
- (一)实用工具类模块
- 1.意义
- 2.设计
- (二)数据管理模块
- 1.意义
- 2.数据库管理
- (1)功能
- (2)user_table类设计
- (三)在线用户管理模块
- 1.意义
- 2.功能
- 3.设计
- (四)游戏房间管理模块
- 1.意义
- 2.功能
- 3.设计
- (1)游戏房间类设计
- (2)游戏房间管理设计
- (五)玩家匹配管理模块
- 1.意义
- 2.功能
- 3.设计
- (1)match_queue-匹配队列
- (2)matcher-匹配管理
- (六)session管理模块
- 1.意义
- 2.功能
- 3.设计
- (1)session类设计
- (2)session_manager管理类设计
- (七)前端界面模块
- 六、项目呈现
一、项目背景
本项目主要实现一个网页版的五子棋对战游戏,其主要支持以下核心功能:
(一)用户管理
实现用户注册,用户登录、获取用户信息、用户天梯分数记录、用户比赛场次记录等。
(二)匹配对战
实现两个玩家在网页端根据天梯分数匹配游戏对手,并进行五子棋游戏对战的功能。
(三)聊天功能
实现两个玩家在下棋的同时可以进行实时聊天的功能。
二、开发环境
- Linux (Centos-7.6)
- VSCode/Vim
- g++/gdb
- Makefile
三、核心技术
- HTTP/WebSocket
- Websocket++
- JsonCpp
- Mysql
- C++11
- BlockQueue
- HTML/CSS/JS/AJAX
四、项目大流程
- 环境搭建(在Linux环境下安装需要用到的的工具以及第三方库)
- 框架设计
- 前置知识的了解
- 模块开发
五、项目模块介绍
(一)实用工具类模块
1.意义
实用工具类模块主要是负责提前实现一些项目中会用到的边缘功能代码,提前实现好了就可以在项目中用到的时候直接使用了。
2.设计
- 日志宏
实现程序日志打印 - mysql_util
数据库的连接和初始化,句柄的销毁,语句的执行 - Jsoncpp-API
封装实现json的序列化和反序列化 - file_util
主要封装了文件数据的读取功能(对于html 文件数据进行读取) - string_util
主要是封装实现字符串分割功能
(二)数据管理模块
1.意义
数据管理模块主要负责对于数据库中数据进行统一的增删改查管理,其他模块要对数据操作都必须通过数据管理模块完成。
2.数据库管理
(1)功能
- 用户信息, 用来实现登录、注册、游戏对战数据管理等功能。
- 积分信息, 用来实现匹配功能。
(2)user_table类设计
- 成员
MYSQL *_mysql; //mysql操作句柄
std::mutex _mutex;//互斥锁保护数据库的访问操作
- 函数
user_table() {};
~user_table() {};
注册时新增用户:bool insert(Json::Value &user);
登录验证,并返回详细的用户信息:bool login(Json::Value &user);
通过用户名获取用户信息:bool select_by_name(const std::string &name, Json::Value &user);
通过用户名获取用户信息:bool select_by_id(uint64_t id, Json::Value &user);
胜利时天梯分数增加30分,战斗场次增加1,胜利场次增加1 :bool win(uint64_t id);
失败时天梯分数减少30,战斗场次增加1,其他不变:bool lose(uint64_t id);
(三)在线用户管理模块
1.意义
在线用户管理,是对于当前游戏大厅和游戏房间中的用户进行管理,主要是建立起用户与Socket连接的映射关系。
2.功能
- 能够让程序中根据用户信息,进而找到能够与用户客户端进行通信的Socket连接,进而实现与用户端的通信。
- 判断⼀个用户是否在线,或者判断判断⼀用户是否在线,或者判断用户是否已经掉线。
3.设计
当一个用户发送了消息(实时聊天消息/下棋消息),我们可以找到房间中的其它用户,在在线用户管理模块中,找到这个用户对应的websocket连接,然后将消息发给指定用户。
- 通过用户id找到用户连接,进而实现向指定用户的客户端推送消息,websocket连接失败时,会自动在在线用户管理模具爱中删除自己的信息!
- 可以判断一个用户是否还在用户管理模块中来确认用户是否在线。
#ifndef __M_ONLINE_H__
#define __M_ONLINE_H__
#include "util.hpp"
#include <mutex>
#include <unordered_map>
class online_manager{
private:
std::mutex _mutex;
//用于建立游戏大厅用户的用户ID与通信连接的关系
std::unordered_map<uint64_t, wsserver_t::connection_ptr> _hall_user;
//用于建立游戏房间用户的用户ID与通信连接的关系
std::unordered_map<uint64_t, wsserver_t::connection_ptr> _room_user;
public:
//websocket连接建立的时候才会加入游戏大厅&游戏房间在线用户管理
void enter_game_hall(uint64_t uid, wsserver_t::connection_ptr &conn) {
std::unique_lock<std::mutex> lock(_mutex);
_hall_user.insert(std::make_pair(uid, conn));
}
void enter_game_room(uint64_t uid, wsserver_t::connection_ptr &conn) {
std::unique_lock<std::mutex> lock(_mutex);
_room_user.insert(std::make_pair(uid, conn));
}
//websocket连接断开的时候,才会移除游戏大厅&游戏房间在线用户管理
void exit_game_hall(uint64_t uid) {
std::unique_lock<std::mutex> lock(_mutex);
_hall_user.erase(uid);
}
void exit_game_room(uint64_t uid) {
std::unique_lock<std::mutex> lock(_mutex);
_room_user.erase(uid);
}
//判断当前指定用户是否在游戏大厅/游戏房间
bool is_in_game_hall(uint64_t uid) {
std::unique_lock<std::mutex> lock(_mutex);
auto it = _hall_user.find(uid);
if (it == _hall_user.end()) {
return false;
}
return true;
}
bool is_in_game_room(uint64_t uid) {
std::unique_lock<std::mutex> lock(_mutex);
auto it = _room_user.find(uid);
if (it == _room_user.end()) {
return false;
}
return true;
}
//通过用户ID在游戏大厅/游戏房间用户管理中获取对应的通信连接
wsserver_t::connection_ptr get_conn_from_hall(uint64_t uid) {
std::unique_lock<std::mutex> lock(_mutex);
auto it = _hall_user.find(uid);
if (it == _hall_user.end()) {
return wsserver_t::connection_ptr();
}
return it->second;
}
wsserver_t::connection_ptr get_conn_from_room(uint64_t uid) {
std::unique_lock<std::mutex> lock(_mutex);
auto it = _room_user.find(uid);
if (it == _room_user.end()) {
return wsserver_t::connection_ptr();
}
return it->second;
}
};
(四)游戏房间管理模块
1.意义
对匹配成功的玩家创建房间,建立起一个小范围的玩家之间的关联关系!房间里一个玩家产生的动作将会广播给房间里的其他用户。
2.功能
将这些房间管理起来,以便于进行房间生命周期的控制!
3.设计
(1)游戏房间类设计
管理的数据,处理房间中产生的动作,两个动作,下棋和聊天。
- 房间的ID
- 房间的状态(决定了一个玩家退出房间时所作的动作)
- 房间中玩家的数量(决定了玩家什么时候销毁)
- 白棋玩家id
- 黑棋玩家id
- 用户信息表的句柄(当玩家胜利/失败的时候更新用户数据)
- 棋盘信息(二维数组)
(2)游戏房间管理设计
- 创建房间 (两个玩家对战匹配完成了,为他们创造一个房间,需要传入两个玩家的用户id)
- 查找房间 (通过房间id查找房间信息,通过用户id查找房间所在信息)
- 销毁房间 (根据房间id销毁房间,房间中所有用户退出了,销毁房间)
需要管理的数据:
- 数据管理模块句柄
- 在线用户管理模块句柄
- 房间id分配计数器
- 互斥锁
- using room_ptr = std::shared_ptr; 房间信息的空间使用shared_ptr进行管理,释放了我们还操作,访问错误!
- unordered_map<room_id,room_ptr> 房间信息管理(建立起房间id与房间信息的映射关系)
- unordered_map<room_id,user_id> 房间id与用户id的关联关系管理! 通过用户id找到所在房间id,再去查找房间信息!
- 房间中所有用户退出了,销毁房间。
(五)玩家匹配管理模块
1.意义
所有玩家,根据得分,分为三个档次!
// 1. 将所有玩家,根据得分,分为三个档次!
// 2. 为三个不同档次创建三个不同的匹配队列!
// 3. 如果有玩家想要进行对战匹配,根据玩家分数,将玩家的id,加到指定的队列中!
// 4. 当一个队列中元素数量 >= 2,则表示有两个玩家要进行匹配,匹配成功
// 5. 出对队列中的前两个元素,为这两个玩家创建房间!
// 6. 给匹配成功的玩家,发送匹配响应,对战匹配成功!
2.功能
进行玩家匹配对战管理。
3.设计
(1)match_queue-匹配队列
- 目的
目的是为了实现玩家匹配队列 - 功能
- 入队数据
- 出队数据
- 移除指定的数据
- 线程安全
- 获取队列元素个数
- 阻塞接口
- 判断队列是否为空
(2)matcher-匹配管理
- 目的
- 三个不同档次的队列
- 三个线程分别对三个队列中的玩家进行匹配
- 房间管理模块的句柄
- 在线用户管理模块的句柄
- 数据管理模块——用户表的句柄
- 功能
- 添加用户到匹配队列
- 线程入口函数
判断指定队列是否热人数大于2
出对队列中的前两个元素
创建房间,将两个用户信息添加到房间中
向两个玩家发送对战匹配成功的消息! - 从匹配队列移除用户
(六)session管理模块
1.意义
⼀个浏览器独占⼀个session对象(默认情况下)。因此,在需要保护用户数据时,服务器程序可以把用户数据写到用户浏览器独占的session中,当用户使用浏览器访问其它程序时,其它程序可以从用户的session中取出该用户的数据,识别该连接对应的用户,并为用户提供服务。
2.功能
保存客户端的用户状态信息。
3.设计
(1)session类设计
- 有自己的表示:ssid
- 用户的状态信息
(2)session_manager管理类设计
- 创建session
- 为session设置过期时间
- 获取session
- 销毁session(过期被自动销毁)
(七)前端界面模块
1.game_hall.html :大厅界面
2.game_room.html:游戏房间界面
3.login:登陆界面
4.register:注册界面
六、项目呈现
新用户注册:
登录:
匹配:
对战:
2023.10.26
又一程
善始善终