更新记录
1.0.0(2026-07-08)
PROJECT INTRODUCTION 斗地主King 科技国风在线斗地主 — 集英雄技能、实时对战、程序化音效与语音播报于一体的完整卡牌游戏项目
TypeScript NestJS 微信小游戏 WebSocket Canvas MySQL Docker Overview 项目概述 斗地主King 是一款科技国风风格的在线斗地主卡牌游戏,采用前后端分离架构。 项目包含独立游戏引擎、NestJS 服务端、微信小游戏客户端、 Web 客户端以及完整的容器化部署方案。 游戏支持 3 人实时对战、12 位英雄技能系统、AI 自动补位、自定义房间、 以及程序化生成的音效与中文语音播报。
5 子项目模块 12 英雄角色 14 数据库表 MIT 开源协议 游戏引擎 (game-engine) 独立的 TypeScript npm 包,提供牌型识别、出牌校验、AI 策略、牌组管理等核心游戏逻辑,可被任意客户端复用。
服务端 (server) NestJS 框架,双协议 WebSocket(Socket.IO + 原生 WS),MySQL 持久化,JWT 认证,完整的房间匹配与游戏流程管理。
小游戏客户端 (minigame) 微信小游戏,纯 Canvas 渲染,零 DOM 依赖,包含自适应双行手牌、程序化音效合成、共振峰语音播报系统。
Web 客户端 (client) 独立 Web 版本,Canvas + 原生 JS,可脱离后端运行本地 AI 对战,也支持在线连接。
Architecture 系统架构 项目采用经典的分层架构,游戏引擎作为独立中间层解耦核心逻辑,服务端和客户端分别对接。
平台兼容性
uni-app(3.7.13)
| Vue2 | Vue3 | Chrome | Safari | app-vue | app-nvue | Android | iOS | 鸿蒙 |
|---|---|---|---|---|---|---|---|---|
| - | - | - | - | - | - | - | - | - |
| 微信小程序 | 支付宝小程序 | 抖音小程序 | 百度小程序 | 快手小程序 | 京东小程序 | 鸿蒙元服务 | QQ小程序 | 飞书小程序 | 小红书小程序 | 快应用-华为 | 快应用-联盟 |
|---|---|---|---|---|---|---|---|---|---|---|---|
| √ | - | - | - | - | - | - | - | - | - | - | - |
斗地主King 使用说明
目录
项目简介
斗地主King 是一款科技国风风格的在线斗地主卡牌游戏,支持 3 人实时对战、12 位英雄技能系统、AI 自动补位、自定义房间等功能。
技术栈:TypeScript + NestJS + Canvas + WebSocket + MySQL + Redis
环境要求
本地开发
| 依赖 | 版本要求 | 说明 |
|---|---|---|
| Node.js | >= 18.x | 推荐 20.x LTS |
| npm | >= 9.x | 随 Node.js 安装 |
| MySQL | >= 8.0 | 用于数据持久化 |
| Redis | >= 7.0 | 用于缓存和排行榜 |
Docker 部署
| 依赖 | 版本要求 |
|---|---|
| Docker | >= 20.x |
| Docker Compose | >= 2.x |
项目结构
douzhu-king/
├── game-engine/ # 核心游戏引擎(独立 npm 包)
│ ├── src/ # TypeScript 源码
│ │ ├── types.ts # 类型定义
│ │ ├── deck.ts # 洗牌发牌
│ │ ├── card-analyzer.ts # 牌型识别
│ │ ├── card-comparator.ts # 大小比较
│ │ ├── play-validator.ts # 出牌校验
│ │ └── ai-player.ts # AI 出牌策略
│ └── package.json
├── server/ # NestJS 服务端
│ ├── src/
│ │ ├── main.ts # 启动入口
│ │ ├── ws-native.ts # 原生 WebSocket 游戏服务
│ │ ├── hero/ # 英雄模块
│ │ ├── game/ # Socket.IO Gateway
│ │ ├── user/ # 用户模块
│ │ ├── auth/ # JWT 认证模块
│ │ ├── config/ # 配置文件
│ │ └── common/ # 公共设施
│ └── package.json
├── client/ # Web 客户端(纯静态)
│ ├── index.html # 入口页面
│ ├── src/ # JS 源码
│ └── package.json
├── minigame/ # 微信小游戏客户端
│ ├── game.js # 入口文件
│ ├── js/ # 核心逻辑
│ │ ├── game-core.js # 游戏核心逻辑
│ │ ├── renderer.js # Canvas 渲染器
│ │ ├── online-mode.js # 在线模式控制器
│ │ ├── ws-client.js # WebSocket 客户端
│ │ ├── animator.js # 动画引擎
│ │ ├── audio.js # 程序化音效
│ │ └── speech.js # 语音播报
│ └── game.json # 小游戏配置
├── database/ # 数据库脚本
│ ├── schema.sql # MySQL 表结构(14 张表)
│ └── init-redis.lua # Redis 缓存初始化
└── deploy/ # 部署配置
├── docker/ # Docker 相关
│ ├── Dockerfile.server
│ ├── docker-compose.yml
│ └── nginx.conf
└── scripts/ # 部署脚本
├── deploy.sh
└── init-db.sh
快速开始
方式一:本地开发(推荐)
1. 克隆项目
git clone <仓库地址>
cd douzhu-king
2. 初始化数据库
# 创建数据库
mysql -u root -p -e "CREATE DATABASE IF NOT EXISTS douzhu_king DEFAULT CHARSET utf8mb4;"
# 导入表结构和初始数据
mysql -u root -p douzhu_king < database/schema.sql
或使用初始化脚本:
bash deploy/scripts/init-db.sh
脚本支持参数自定义:
bash deploy/scripts/init-db.sh <host> <port> <user> <password>
# 默认值:localhost 3306 root 123456
3. 启动 Redis
redis-server
4. 安装并启动游戏引擎
cd game-engine
npm install
npm run build
5. 安装并启动服务端
cd ../server
npm install
npm run build
npm run start:dev
启动成功后会看到:
🃏 斗地主之王 服务端已启动: http://localhost:3000
API前缀: http://localhost:3000/api/v1
原生WebSocket: ws://localhost:3000/game
服务端支持降级模式:即使 MySQL 不可用,HTTP 和 WebSocket 服务仍可启动(游戏房间在内存中运行)。
6. 启动 Web 客户端
cd ../client
npm install
npm run dev
浏览器访问 http://localhost:8080 即可进入游戏。
在连接面板中输入 WebSocket 地址 ws://localhost:3000/game,点击连接。
7.(可选)环境变量配置
在 server/ 目录下创建 .env 文件:
PORT=3000
DB_HOST=localhost
DB_PORT=3306
DB_USERNAME=root
DB_PASSWORD=123456
DB_DATABASE=douzhu_king
REDIS_HOST=localhost
REDIS_PORT=6379
# 跳过数据库连接(纯内存模式)
DB_SKIP=false
方式二:Docker 部署
一键启动
cd deploy/docker
docker compose up -d
这会启动 4 个服务:
| 服务 | 端口 | 说明 |
|---|---|---|
| Nginx | 80 | Web 客户端 + API 反代 |
| Server | 3000 | NestJS 服务端 |
| MySQL | 3306 | 数据库(密码:123456) |
| Redis | 6379 | 缓存 |
启动后浏览器访问 http://服务器IP 即可。
使用部署脚本
cd deploy/scripts
# 启动(自动构建、启动、健康检查)
bash deploy.sh start
# 停止
bash deploy.sh stop
# 重启
bash deploy.sh restart
# 查看状态
bash deploy.sh status
# 健康检查
bash deploy.sh health
# 仅构建镜像
bash deploy.sh build
# 数据库备份
bash deploy.sh backup
# 数据库回滚
bash deploy.sh rollback <备份文件路径>
各模块详细说明
游戏引擎 (game-engine)
独立的 TypeScript npm 包,提供斗地主核心逻辑,不依赖任何框架。
cd game-engine
npm install # 安装依赖
npm run build # 编译 TypeScript → dist/
npm run test # 运行测试(Jest + 覆盖率)
npm run dev # 监视模式编译
核心模块:
| 模块 | 功能 |
|---|---|
types.ts |
类型定义(Suit, Card, CardType, Player, Room 等) |
deck.ts |
创建牌组、洗牌、发牌、排序 |
card-analyzer.ts |
牌型识别(单张/对子/三条/顺子/连对/飞机/炸弹/火箭等) |
card-comparator.ts |
牌型大小比较、炸弹倍数计算 |
play-validator.ts |
出牌合法性校验 |
ai-player.ts |
AI 出牌策略(自由出牌/跟牌) |
服务端 (server)
基于 NestJS 框架,支持双协议 WebSocket。
cd server
npm install # 安装依赖
npm run build # 编译 TypeScript
npm run start:dev # 开发模式(热重载)
npm run start:prod # 生产模式
npm run lint # ESLint 检查
npm run test # 单元测试
端口配置:
| 服务 | 默认端口 | 配置方式 |
|---|---|---|
| HTTP API | 3000 | 环境变量 PORT |
| 原生 WebSocket | 3000 | 路径 /game |
| Socket.IO | 3000 | 路径 /game |
CORS 允许的来源:
localhost:3001localhost:8080localhost:5173127.0.0.1:8080
Web 客户端 (client)
纯静态 HTML + Canvas + 原生 JS,无需构建步骤。
cd client
npm install # 安装 http-server
npm run dev # 开发模式(禁用缓存,端口 8080)
npm run start # 生产模式(有缓存,端口 8080)
支持两种游戏模式:
- 本地对战:无需服务端,与 AI 单机对战
- 在线对战:连接 WebSocket 服务器,与真人实时对战
微信小游戏客户端 (minigame)
微信小游戏项目,纯 Canvas 渲染,零 DOM 依赖。
配置文件 game.json:
{
"deviceOrientation": "portrait", // 竖屏
"showStatusBar": false, // 隐藏状态栏
"networkTimeout": {
"request": 5000, // 请求超时 5 秒
"connectSocket": 5000, // WebSocket 连接超时 5 秒
"uploadFile": 5000,
"downloadFile": 5000
}
}
使用微信开发者工具导入 minigame/ 目录即可运行。需要在代码中配置 WebSocket 服务器地址(通过 WSClient.connect(url) 传入)。
核心文件说明:
| 文件 | 行数 | 功能 |
|---|---|---|
game-core.js |
~2260 | 游戏状态机、渲染调度、AI 逻辑、按钮/手牌交互 |
renderer.js |
~970 | Canvas 绘制(牌面/手牌/按钮/面板/特效) |
online-mode.js |
~1400 | WebSocket 消息处理、在线流程控制 |
ws-client.js |
~200 | WebSocket 客户端(心跳/重连/消息队列) |
animator.js |
~150 | Tween 动画引擎 |
audio.js |
~870 | 程序化音效合成(Web Audio API) |
speech.js |
~900 | 中文语音播报(共振峰合成) |
数据库配置
MySQL 表结构
共 14 张表,database/schema.sql 包含完整的建表语句和初始数据。
| 表名 | 说明 |
|---|---|
t_user |
用户表(用户名/昵称/金币/积分/等级/VIP) |
t_game_record |
对局记录(含回放数据 JSON) |
t_hero |
英雄配置(12 位英雄) |
t_user_hero |
用户英雄拥有情况 |
t_guild |
公会表(最大 30 人) |
t_guild_member |
公会成员(会长/副会长/成员) |
t_season |
赛季配置(含奖励和排位规则 JSON) |
t_season_user |
赛季用户排位数据 |
t_skin |
皮肤配置(6 套预置皮肤) |
t_user_skin |
用户皮肤拥有情况 |
t_ad_log |
广告日志(视频/插屏/激励) |
t_sign_record |
签到记录(连续签到天数) |
t_mail |
邮件系统(系统/奖励/活动邮件) |
t_daily_task |
每日任务进度 |
默认测试账号:
| 用户名 | 密码 |
|---|---|
| player1 | 123456 |
| player2 | 123456 |
| player3 | 123456 |
环境变量配置:
| 变量名 | 默认值 | 说明 |
|---|---|---|
DB_HOST |
localhost |
数据库主机 |
DB_PORT |
3306 |
数据库端口 |
DB_USERNAME |
root |
用户名 |
DB_PASSWORD |
123456 |
密码 |
DB_DATABASE |
douzhu_king |
数据库名 |
DB_SKIP |
false |
设为 true 跳过数据库连接 |
Redis 缓存说明
database/init-redis.lua 定义了 14 种缓存数据结构:
| Key 模式 | 类型 | 说明 |
|---|---|---|
online:{userId} |
Hash | 用户在线状态 |
matchmaking:queue |
List | 匹配队列 |
room:{roomId} |
Hash | 房间数据 |
cache:coins:{userId} |
String | 金币缓存(TTL 1 小时) |
cache:score:{userId} |
String | 积分缓存(TTL 1 小时) |
sign:{userId}:{date} |
Hash | 每日签到 |
daily_task:{userId}:{date} |
Hash | 每日任务进度 |
leaderboard:season:{seasonId} |
Sorted Set | 赛季排行榜 |
leaderboard:guild |
Sorted Set | 公会排行榜 |
ad:cd:{userId}:{adType} |
String | 广告冷却 |
heartbeat:{roomType} |
Sorted Set | 房间心跳检测 |
ratelimit:{userId}:{action} |
String | 消息限流 |
mail:unread:{userId} |
String | 未读邮件计数 |
lock:{resource} |
String | 分布式锁 |
API 接口
所有 API 以 /api/v1 为前缀。
英雄模块
| 方法 | 路径 | 说明 |
|---|---|---|
| GET | /hero/list |
获取全部英雄列表 |
| GET | /hero/:id |
获取单个英雄详情 |
| GET | /hero/user/heroes |
获取当前用户拥有的英雄 |
| POST | /hero/equip |
装备英雄 |
认证模块
| 方法 | 路径 | 说明 |
|---|---|---|
| POST | /auth/register |
用户注册 |
| POST | /auth/login |
用户登录(返回 JWT) |
健康检查
| 方法 | 路径 | 说明 |
|---|---|---|
| GET | /health |
服务健康状态 |
WebSocket 消息协议
连接地址:ws://localhost:3000/game
消息格式:{ type: string, data: object }
客户端 → 服务端
| type | data | 说明 |
|---|---|---|
join-match |
{ heroId } |
加入匹配队列 |
create-room |
{ heroId } |
创建自定义房间 |
join-room |
{ roomNumber, heroId } |
加入指定房间 |
leave-room |
- | 离开房间 |
start-game |
- | 房主开始游戏 |
bid |
{ score: 0-3 } |
叫地主(0=不叫) |
play-cards |
{ cards: [{id, suit, value}] } |
出牌 |
pass |
- | 不出(跳过) |
use-skill |
- | 使用英雄技能 |
服务端 → 客户端
| type | data | 说明 |
|---|---|---|
match-success |
{ roomId, players } |
匹配成功 |
room-created |
{ roomNumber, roomId } |
房间创建成功 |
room-joined |
{ roomId, players } |
加入房间成功 |
player-joined |
{ player } |
有玩家加入房间 |
player-left |
{ playerIdx } |
有玩家离开 |
game-start |
{ bottomCards, players, landlordIdx } |
游戏开始 |
turn-start |
{ currentPlayer } |
回合开始 |
player-bid |
{ playerIdx, score } |
玩家叫分 |
landlord-decided |
{ landlordIdx, bottomCards } |
地主确定 |
cards-played |
{ playerIdx, cards, remaining } |
玩家出牌 |
player-passed |
{ playerIdx, name } |
玩家不出 |
play-invalid |
{ error } |
出牌无效 |
skill-used |
{ playerIdx, skillName, remainingUses } |
技能使用 |
game-over |
{ winnerIdx, winnerName, isLandlordWin, multiplier } |
游戏结束 |
英雄技能系统
共 12 位英雄,分 4 个稀有度和 7 种元素属性。
英雄列表
| ID | 名称 | 稀有度 | 元素 | 技能 | 类型 | 效果 |
|---|---|---|---|---|---|---|
| 1 | 烈焰战神 | 传说 | 火 | 烈焰印记 | 被动 | 炸弹倍数额外 +1 |
| 2 | 冰霜女王 | 传说 | 水 | 寒冰护盾 | 被动 | 被炸弹时积分损失减半 |
| 3 | 疾风剑豪 | 史诗 | 风 | 御风飞行 | 被动 | 出牌倒计时 +10 秒 |
| 4 | 雷神之子 | 史诗 | 雷 | 雷霆一击 | 主动 | 随机查看对手一张手牌 |
| 5 | 大地守护者 | 史诗 | 地 | 坚如磐石 | 被动 | 不叫地主时积分损失减半 |
| 6 | 光影刺客 | 史诗 | 暗 | 暗影突袭 | 主动 | 偷看一张底牌 |
| 7 | 圣光骑士 | 稀有 | 光 | 神圣庇护 | 被动 | 出顺子时积分 +10 |
| 8 | 花仙子 | 稀有 | 地 | 花之守护 | 主动 | 强制对手再出一次 |
| 9 | 铁拳武僧 | 稀有 | 雷 | 铁拳破击 | 主动 | 下一手可出任意牌型 |
| 10 | 星际领航员 | 普通 | 风 | 星际导航 | 主动 | 查看对手剩余手牌数(每局 2 次) |
| 11 | 龙吟剑客 | 普通 | 火 | 龙吟 | 被动 | 叫地主成功倍数 +1 |
| 12 | 月影舞者 | 普通 | 暗 | 月影迷踪 | 主动 | 随机交换自己两张手牌 |
默认解锁英雄:星际领航员、龙吟剑客、月影舞者
技能使用规则
- 被动技能:自动生效,无需手动使用
- 主动技能:在出牌阶段点击技能按钮使用,每局限定使用次数
- 技能按钮仅在轮到自己出牌时显示
- 使用技能不会消耗出牌回合
部署管理
Nginx 反向代理规则
| 路径 | 代理目标 | 说明 |
|---|---|---|
/ |
本地静态文件 | Web 客户端 |
/api/ |
http://server:3000/api/ |
REST API |
/ws |
http://server:3000/ws |
WebSocket(超时 3600 秒) |
/health |
http://server:3000/health |
健康检查 |
健康检查
Docker 配置了服务端健康检查:
wget --spider -q http://localhost:3000/health
使用部署脚本检查所有服务:
bash deploy/scripts/deploy.sh health
数据库备份与恢复
# 备份(输出到 /opt/douzhu-king/backups/)
bash deploy/scripts/deploy.sh backup
# 恢复
bash deploy/scripts/deploy.sh rollback /opt/douzhu-king/backups/douzhu_king_20260708.sql
常见问题
Q: 启动服务端报 MySQL 连接错误?
A: 服务端支持降级模式,数据库不可用时仍可运行。如果需要数据库功能:
- 确认 MySQL 已启动:
systemctl status mysql或docker ps - 确认数据库已创建:
mysql -u root -p -e "SHOW DATABASES;" - 设置环境变量
DB_SKIP=false(默认值) - 或创建
.env文件配置正确的数据库连接参数
Q: 匹配后只有自己一个人?
A: 匹配队列需要 3 人满员才开始。如果 10 秒内未满员,系统会用 AI 自动补位(1 真人 + 2 AI)。如果希望多人对战,需要多个客户端同时连接服务器。
Q: Web 客户端连接不上 WebSocket?
A: 检查以下几点:
- 服务端是否已启动(
http://localhost:3000/health返回正常) - WebSocket 地址是否正确:
ws://localhost:3000/game - 浏览器控制台是否有跨域错误(确保在 CORS 允许的端口访问)
- 如果用 Docker 部署,使用
ws://服务器IP/ws而非ws://localhost
Q: 如何修改服务端口?
A: 通过环境变量 PORT 修改:
PORT=8080 npm run start:prod
或在 .env 文件中设置 PORT=8080。
Q: 微信小游戏如何连接服务器?
A: 在 game.js 中调用 wsClient.connect('wss://你的域名/game') 连接。生产环境需要使用 wss://(TLS 加密),并确保服务器已配置 SSL 证书。
Q: Docker 部署后如何查看日志?
A:
# 查看所有服务日志
docker compose logs -f
# 查看单个服务日志
docker compose logs -f server

收藏人数:
购买普通授权版(
试用
赞赏(0)
下载 42
赞赏 0
下载 12404858
赞赏 1930
赞赏
京公网安备:11010802035340号