快速开始
本文档演示一个最小可运行的示例:2 人 SimpleGame,使用引擎内置插件完成"创建 Engine → 配置游戏 → 注册 Plugin → createGame → start → dispatch → subscribe"完整链路。
安装
要求 Node.js >= 18。
bash
# 克隆仓库后安装依赖
npm install最小示例
下面示例使用 StandardDeckPlugin + TurnPlugin + DrawPlugin + SimpleGamePlugin 4 个内置插件,完成一局完整的"出完手牌即胜"对局:
ts
import { GameEngine } from 'decklet'
import {
StandardDeckPlugin,
TurnPlugin,
DrawPlugin,
SimpleGamePlugin,
createSimplePlayCardAction,
playerHandZoneId
} from 'decklet/plugins'
// 1. 创建 Engine(可选传入 seed 让对局可回放)
const engine = new GameEngine({ seed: 123456 })
// 2. 订阅事件(可选)—— 通配监听所有事件
engine.subscribeAll((event) => {
console.log(`[event] ${event.type}`, event.payload)
})
// 3. 注册插件 → createGame → start
engine
.use(StandardDeckPlugin) // 创建 52 张标准牌堆,GAME_STARTED 时自动洗牌
.use(TurnPlugin) // 管理回合顺序与方向
.use(DrawPlugin) // 处理 DRAW_CARD action
.use(SimpleGamePlugin) // PLAY_CARD action handler + 胜负判定
.createGame({
players: [
{ id: 'p1', name: 'Alice', seat: 1 },
{ id: 'p2', name: 'Bob', seat: 2 }
]
})
engine.start() // 触发 GAME_STARTED → 初始洗牌 + 每人发 5 张牌
// 4. 查询状态
const state = engine.getState()
console.log(`当前玩家: ${state.currentPlayerId}`)
console.log(`Alice 的手牌: ${state.zones[playerHandZoneId('p1')]?.cards.length} 张`)
console.log(`Bob 的手牌: ${state.zones[playerHandZoneId('p2')]?.cards.length} 张`)
// 5. dispatch Action —— 当前玩家出第一张牌
let turn = 0
while (engine.getState().status === 'playing' && turn < 50) {
const currentId = engine.getState().currentPlayerId!
const hand = engine.getState().zones[playerHandZoneId(currentId)]!
const cardId = hand.cards[0]!
const result = engine.dispatch(createSimplePlayCardAction(currentId, [cardId]))
if (!result.ok) {
console.error('action rejected:', result.denyCode, result.denyReason)
break
}
turn++
}
console.log(`status: ${engine.getState().status}`)
console.log(`winners: ${engine.getState().winnerIds.join(', ')}`)运行:
bash
npm run example # 等价于 tsx examples/simple-game.ts关键 API
创建 Engine
ts
new GameEngine(config?: GameConfigInit & { validation?: ValidationMode })config 可省略,缺省值由 DEFAULT_GAME_CONFIG 提供。传入 seed 后引擎会使用 SeededRandomProvider,使对局可回放。
注册 Plugin
ts
engine.use(plugin: GamePlugin): this链式注册。必须在 createGame 之前调用 —— 插件的 rules / actions / events 会在 createGame 内通过 wirePlugins 统一注册到对应子系统。
创建对局
ts
engine.createGame(options: CreateGameOptions): thisCreateGameOptions 字段:
| 字段 | 类型 | 必填 | 说明 |
|---|---|---|---|
players | CreateGamePlayerInit[] | 是 | 玩家列表 |
gameId | string | 否 | 对局 id 覆盖;缺省取 config.gameId |
initialVariables | Record<string, unknown> | 否 | 初始 variables |
seed | number | 否 | 单局种子覆盖 |
CreateGamePlayerInit 字段:
| 字段 | 类型 | 必填 | 默认值 | 说明 |
|---|---|---|---|---|
id | string | 是 | — | 玩家 id |
name | string | 是 | — | 显示名 |
seat | number | 否 | 下标 +1 | 座位号;同局不可重复 |
status | PlayerStatus | 否 | 'active' | 玩家状态 |
data | Record<string, unknown> | 否 | {} | 游戏专属数据 |
启动对局
ts
engine.start(): this把对局状态从 waiting 切换到 playing,并发出 GAME_STARTED 事件。
派发 Action
ts
engine.dispatch(action: Action): DispatchResultDispatchResult 字段:
| 字段 | 类型 | 说明 |
|---|---|---|
ok | boolean | 是否通过 Rule 校验且无异常 |
action | Action | 派发的 Action |
denyReason | string? | Rule 拒绝原因 |
denyCode | string? | 稳定错误码 |
error | string? | 执行阶段抛错的 message |
events | GameEvent[] | 本 tick 内发出的事件 |
processedActions | ProcessedAction[] | 本 tick 内处理的所有 Action |
订阅事件
ts
// 订阅指定类型
const off = engine.subscribe('CARD_PLAYED', (event) => {
console.log(event.payload)
})
off() // 取消订阅
// 订阅所有事件(等价于 subscribe(WILDCARD, listener))
engine.subscribeAll((event) => {
console.log(event.type, event.payload)
})使用内置 Action 工厂
decklet 入口已导出 5 个基础 Action 工厂:
ts
import {
createDrawCardAction,
createPlayCardAction,
createMoveCardAction,
createEndTurnAction,
createPassAction
} from 'decklet'
// 抽 3 张牌
const draw = createDrawCardAction('p1', 3)
// 出一张牌到默认 discard 区
const play = createPlayCardAction('p1', ['card-001'])
// 在两个明确 zone 间迁移单张牌
const move = createMoveCardAction('card-001', 'deck', 'hand:p1', { playerId: 'p1' })
// 结束当前回合
const end = createEndTurnAction('p1')
// 过牌
const pass = createPassAction('p1')下一步
- 架构文档 — 各子系统如何协作
- 游戏生命周期 —
createGame/start/dispatch详细流程 - 插件系统 — 如何开发自定义 Plugin
- GameEngine API