pet-engine
v1.0.0
Published
A flexible, type-safe pet animation engine written in TypeScript
Maintainers
Readme
pet-engine
介绍
pet-engine 是一个基于 TypeScript + Canvas 2D 的宠物动画引擎,支持通过 Vue 3 组件或独立核心类进行调用。引擎内置帧动画播放、层级有限状态机(HFSM)、自主行为控制、物理模拟与交互系统,可用于桌面宠物、互动动画等场景。
软件架构
引擎采用模块化设计,核心模块职责如下:
| 模块 | 文件 | 职责 |
|------|------|------|
| PetPlayer | src/core/PetPlayer.ts | 核心控制器,负责初始化、资源加载、主循环调度,以及整合动画、行为、物理、交互、渲染等子系统 |
| AnimationPlayer | src/core/AnimationPlayer.ts | 帧动画播放器,根据 fps 和帧范围驱动逐帧切换,支持循环与非循环播放,提供 onComplete 回调 |
| AssetManager | src/core/AssetManager.ts | 图片资源管理器,负责异步加载、缓存和释放 PNG 帧图 |
| StateMachine | src/core/StateMachine.ts | 动作状态机,管理当前动作状态,支持通过 transitions 配置限制动作之间的合法转移 |
| BehaviorController | src/core/BehaviorController.ts | 自主行为控制器,支持 idle( idle 待机)和 path(路径移动/游荡)两种状态类型,可配置状态转移概率、速度范围、停顿时间等 |
| PhysicsController | src/core/PhysicsController.ts | 物理控制器,支持重力加速度与终端速度模拟,提供 jump 脉冲接口 |
| InteractionSystem | src/core/InteractionSystem.ts | 交互系统,处理 Pointer 事件的按下、移动、抬起,支持拖拽阈值判定、释放行为(stay / physics) |
| Renderer | src/core/Renderer.ts | Canvas 2D 渲染器,负责逐帧清屏与绘图 |
| EventEmitter | src/core/EventEmitter.ts | 类型安全的事件中心,支持 move、resize、actionChange、petting、caught 等事件 |
| PetPlayer.vue | src/PetPlayer.vue | Vue 3 组件封装,内置 canvas 元素与生命周期管理,暴露 player / canvas 实例 |
安装教程
# 克隆仓库
git clone <仓库地址>
cd pet-engine
# 安装依赖
pnpm install作为 npm 模块引入到现有项目中:
import { PetPlayerCore, PetPlayer, PetModel } from 'pet-engine'使用说明
1. 模型配置(PetModel)
引擎通过 PetModel JSON 配置驱动。一个最小示例如下:
{
"id": "cat-01",
"name": "示例猫咪",
"canvas": {
"defaultScale": 1,
"anchor": { "x": 0.5, "y": 1 }
},
"actions": {
"idle": {
"loop": true,
"fps": 8,
"frames": { "width": 128, "height": 128, "start": 1, "end": 4 }
},
"walk": {
"loop": true,
"fps": 12,
"moveSpeed": 120,
"frames": { "width": 128, "height": 128, "start": 5, "end": 12 }
},
"petting": {
"loop": false,
"fps": 10,
"frames": { "width": 128, "height": 128, "start": 13, "end": 20 }
}
},
"transitions": {
"idle": ["walk", "petting"],
"walk": ["idle", "petting"],
"petting": ["idle"]
},
"behavior": {
"defaultState": "wander",
"states": {
"wander": {
"type": "path",
"actions": ["walk"],
"speed": [80, 150],
"duration": [3000, 8000],
"edgeBehavior": "turn",
"transitions": [
{ "to": "rest", "probability": 0.3 }
]
},
"rest": {
"type": "idle",
"actions": ["idle"],
"duration": [2000, 5000],
"transitions": [
{ "to": "wander", "probability": 1 }
]
}
}
},
"interaction": {
"draggable": true,
"drag": {
"action": "caught",
"followCursor": true,
"releaseBehavior": "physics"
},
"hover": {
"action": "teasing"
}
},
"physics": {
"gravity": 980,
"terminalVelocity": 2000
}
}图片资源按 动作名/帧序号.png 存放,例如 walk/005.png、walk/006.png。
2. 核心类独立使用
import { PetPlayerCore, PetModel } from 'pet-engine'
const canvas = document.getElementById('pet-canvas') as HTMLCanvasElement
const player = new PetPlayerCore(canvas, '/models/cat-01')
// 方式一:从远程加载 pet.json
await player.load()
// 方式二:直接传入模型数据与图片 URL 映射
const modelData: PetModel = { /* ... */ }
const imageUrlMap: Record<string, string> = {
'walk/005.png': 'https://example.com/walk_005.png'
}
await player.load(modelData, imageUrlMap)
// 设置屏幕边界
player.behavior.setScreenSize(window.innerWidth, window.innerHeight)
// 监听事件
player.events.on('move', () => console.log('宠物移动了'))
player.events.on('petting', () => console.log('抚摸触发'))
player.events.on('caught', () => console.log('被抓起来了'))
player.events.on('resize', ({ width, height, anchorX, anchorY }) => {
// 可在此同步外层容器尺寸
})
// 启动引擎
player.start()
// 主动播放动作
player.play('walk')
// 暂停 / 恢复
player.pause()
player.resume()
// 销毁
player.stop()3. Vue 3 组件使用
<script setup lang="ts">
import { ref } from 'vue'
import { PetPlayer, PetModel } from 'pet-engine'
const petRef = ref<InstanceType<typeof PetPlayer>>()
const modelData: PetModel = { /* ... */ }
const imageUrlMap: Record<string, string> = { /* ... */ }
function onReady() {
console.log('宠物准备就绪')
// 通过 petRef.value?.player 访问核心实例
}
function onMove() {
// 宠物位置/尺寸发生变化
}
</script>
<template>
<PetPlayer
ref="petRef"
model="/models/cat-01"
:scale="1"
:screen="{ width: 1920, height: 1080 }"
:model-data="modelData"
:image-url-map="imageUrlMap"
@ready="onReady"
@move="onMove"
@resize="onResize"
@petting="onPetting"
@caught="onCaught"
@error="onError"
/>
</template>4. 开发与构建
# 启动开发服务器(预览 demo/App.vue)
pnpm dev
# 类型检查并构建库
pnpm build
# 预览构建产物
pnpm preview构建产物位于 dist/ 目录:
pet-engine.js— ES Module 格式pet-engine.umd.cjs— UMD 格式index.d.ts— TypeScript 类型声明
5. 交互与事件说明
| 事件 | 触发时机 |
|------|----------|
| move | 宠物位置或画布尺寸发生变化 |
| resize | 画布尺寸因帧图变化而调整 |
| actionChange | 动作状态发生切换 |
| petting | 点击宠物(未触发拖拽) |
| caught | 拖拽后释放宠物 |
交互行为由PetModel.interaction` 配置:
draggable: 是否可拖拽drag.action: 拖拽时播放的动作名drag.releaseBehavior: 释放后行为,stay(停留)或physics(受物理下落)hover.action: 悬停时播放的动作名
参与贡献
- Fork 本仓库
- 新建
Feat_xxx分支 - 提交代码
- 新建 Pull Request
