# boardgame-core 基于 Preact Signals 的桌游状态管理库。 ## 特性 - **响应式状态管理**: 使用 [@preact/signals-core](https://preactjs.com/guide/v10/signals/) 实现细粒度响应式 - **类型安全**: 完整的 TypeScript 支持 - **核心概念**: - **Part**: 游戏组件(棋子、卡牌、板块) - **Region**: 容器区域(支持 keyed/unkeyed 两种模式) - **Placement**: Part 在 Region 中的引用 ## 安装 ```bash npm install ``` ## 快速开始 ### 1. 创建游戏状态 ```typescript import { createGameState } from 'boardgame-core'; const gameState = createGameState({ id: 'game-1', name: 'My Board Game', }); ``` ### 2. 创建 Parts(游戏组件) ```typescript import { createMeepleAction, createCardAction, createTileAction } from 'boardgame-core'; // 创建棋子 const meeple = createMeepleAction(gameState, 'meeple-1', 'red', { name: 'Player 1', }); // 创建卡牌 const card = createCardAction(gameState, 'card-1', { suit: 'hearts', value: 10, }); // 创建板块 const tile = createTileAction(gameState, 'tile-1', { pattern: 'forest', rotation: 90, }); ``` ### 3. 创建 Regions(区域) ```typescript import { createRegionAction, RegionType } from 'boardgame-core'; // Unkeyed Region - 适用于牌库、弃牌堆等 const deck = createRegionAction(gameState, { id: 'deck', type: RegionType.Unkeyed, name: 'Draw Deck', }); // Keyed Region - 适用于版图、玩家区域等有固定位置的区域 const board = createRegionAction(gameState, { id: 'board', type: RegionType.Keyed, name: 'Game Board', }); // 带容量的区域(如手牌限制) const hand = createRegionAction(gameState, { id: 'hand', type: RegionType.Unkeyed, capacity: 5, }); ``` ### 4. 创建 Placements(放置) ```typescript import { createPlacementAction } from 'boardgame-core'; // 将棋子放置在版图上 const placement = createPlacementAction(gameState, { id: 'placement-1', partId: 'meeple-1', regionId: 'board', position: { x: 3, y: 4 }, }); ``` ### 5. 使用 Actions 操作状态 ```typescript import { movePlacementAction, flipPlacementAction, setSlotAction, updatePartAction, } from 'boardgame-core'; // 移动 Placement 到另一个区域 movePlacementAction(gameState, 'placement-1', 'hand'); // 翻转卡牌(面朝上/面朝下) flipPlacementAction(gameState, 'placement-1'); // 在 Keyed Region 中设置槽位 setSlotAction(gameState, 'board', 'A1', 'placement-1'); // 更新 Part 属性 updatePartAction(gameState, 'meeple-1', { metadata: { score: 10 } }); ``` ## API 参考 ### Part Actions | Action | 描述 | |--------|------| | `createPartAction` | 创建通用 Part | | `createMeepleAction` | 创建棋子 | | `createCardAction` | 创建卡牌 | | `createTileAction` | 创建板块 | | `updatePartAction` | 更新 Part 属性 | | `removePartAction` | 移除 Part | | `getPartAction` | 获取 Part | ### Region Actions | Action | 描述 | |--------|------| | `createRegionAction` | 创建 Region | | `getRegionAction` | 获取 Region | | `removeRegionAction` | 移除 Region | | `addPlacementToRegionAction` | 添加 Placement 到 Unkeyed Region | | `removePlacementFromRegionAction` | 从 Region 移除 Placement | | `setSlotAction` | 设置 Keyed Region 的槽位 | | `getSlotAction` | 获取 Keyed Region 的槽位 | | `clearRegionAction` | 清空 Region | | `getRegionPlacementCountAction` | 获取 Region 中 Placement 数量 | | `isRegionEmptyAction` | 检查 Region 是否为空 | | `isRegionFullAction` | 检查 Region 是否已满 | ### Placement Actions | Action | 描述 | |--------|------| | `createPlacementAction` | 创建 Placement | | `getPlacementAction` | 获取 Placement | | `removePlacementAction` | 移除 Placement | | `movePlacementAction` | 移动 Placement 到另一个 Region | | `updatePlacementPositionAction` | 更新 Placement 位置 | | `updatePlacementRotationAction` | 更新 Placement 旋转角度 | | `flipPlacementAction` | 翻转 Placement | | `updatePlacementPartAction` | 更新 Placement 的 Part 引用 | | `swapPlacementsAction` | 交换两个 Placement 的位置 | | `setPlacementFaceAction` | 设置 Placement 面朝上/下 | | `getPlacementsInRegionAction` | 获取 Region 中的所有 Placements | | `getPlacementsOfPartAction` | 获取 Part 的所有 Placements | ## 运行测试 ```bash npm test # 监视模式 npm run test:run # 运行一次 ``` ## 构建 ```bash npm run build ``` ## 许可证 MIT