183 lines
4.4 KiB
Markdown
183 lines
4.4 KiB
Markdown
|
|
# 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
|