Files
Pandona-Engine/guide/advanced/README.md
2025-10-03 16:49:53 +08:00

455 lines
9.3 KiB
Markdown
Raw Blame History

This file contains ambiguous Unicode characters

This file contains Unicode characters that might be confused with other characters. If you think that this is intentional, you can safely ignore this warning. Use the Escape button to reveal them.

# 进阶主题
在掌握了PE引擎的基础知识后我们可以探索一些更高级的功能和概念。这些进阶主题将帮助你构建更复杂、更高效的应用。
## 目录
- [动画系统](./animation)
- [状态管理](./state-management)
- [插件系统](./plugins)
- [性能优化](./performance)
- [测试](./testing)
- [部署](./deployment)
## 动画系统
PE引擎内置了强大的动画系统支持补间动画、帧动画和序列动画。
### 补间动画
补间动画允许你在两个状态之间创建平滑的过渡:
```javascript
// 创建补间动画
const tween = game.tween(element.element)
.to({
left: '500px',
top: '300px',
opacity: 0.5
}, 2000) // 持续2秒
.easing('easeInOutQuad') // 缓动函数
.onUpdate(() => {
console.log('动画更新')
})
.onComplete(() => {
console.log('动画完成')
})
.start()
```
### 帧动画
帧动画通过连续播放一系列图像来创建动画效果:
```javascript
// 创建帧动画
game.createFrameAnimation('walk', [
'img/walk1.png',
'img/walk2.png',
'img/walk3.png',
'img/walk4.png'
], 10) // 10帧每秒
// 播放帧动画
game.playFrameAnimation(sprite, 'walk', true) // 循环播放
```
### 序列动画
序列动画允许你按顺序播放多个动画:
```javascript
// 创建动画序列
game.createSequence('moveAndFade', [
{
target: element.element,
props: { left: '500px' },
duration: 1000
},
{
target: element.element,
props: { opacity: 0 },
duration: 500
}
])
// 播放序列动画
game.playSequence('moveAndFade')
```
## 状态管理
对于复杂应用合理的状态管理至关重要。PE引擎提供了灵活的状态管理方案。
### 全局状态
```javascript
// 创建全局状态管理器
class StateManager {
constructor() {
this.state = {}
this.listeners = {}
}
// 设置状态
setState(key, value) {
this.state[key] = value
this.notifyListeners(key, value)
}
// 获取状态
getState(key) {
return this.state[key]
}
// 订阅状态变化
subscribe(key, callback) {
if (!this.listeners[key]) {
this.listeners[key] = []
}
this.listeners[key].push(callback)
}
// 通知监听器
notifyListeners(key, value) {
if (this.listeners[key]) {
this.listeners[key].forEach(callback => callback(value))
}
}
}
// 创建全局状态管理器实例
const stateManager = new StateManager()
// 在组件中使用
stateManager.setState('user', { name: '张三', age: 25 })
stateManager.subscribe('user', (user) => {
console.log('用户信息更新:', user)
})
```
### 场景状态
每个场景也可以有自己的状态管理:
```html
<script>
// 场景内部状态
let sceneState = {
data: [],
loading: false,
error: null
}
// 更新场景状态
function updateState(newState) {
sceneState = { ...sceneState, ...newState }
updateUI()
}
// 异步数据加载
async function loadData() {
updateState({ loading: true })
try {
const data = await fetchData()
updateState({ data, loading: false })
} catch (error) {
updateState({ error: error.message, loading: false })
}
}
</script>
```
## 插件系统
PE引擎支持插件系统允许你扩展引擎的功能。
### 创建插件
```javascript
// 定义插件
const LoggerPlugin = {
name: 'LoggerPlugin',
install(engine, options) {
console.log('LoggerPlugin installed with options:', options)
// 扩展引擎功能
engine.log = function(message) {
console.log(`[PE Logger]: ${message}`)
}
// 监听引擎事件
engine.eventBus.on('sceneChanged', (data) => {
this.log(`Scene changed to: ${data.path}`)
})
}
}
// 使用插件
game.use(LoggerPlugin, { level: 'debug' })
```
### 内置插件
PE引擎提供了一些有用的内置插件
```javascript
// 路由插件
import { RouterPlugin } from 'pe-engine/plugins'
game.use(RouterPlugin, {
mode: 'history', // 或 'hash'
routes: [
{ path: '/', component: 'Home' },
{ path: '/about', component: 'About' }
]
})
// 状态管理插件
import { StatePlugin } from 'pe-engine/plugins'
game.use(StatePlugin, {
initialState: {
user: null,
theme: 'light'
}
})
```
## 性能优化
构建高性能的PE应用需要注意以下几个方面
### 1. 虚拟化列表
对于大量数据的列表渲染,使用虚拟化技术:
```javascript
// 虚拟化列表组件
class VirtualList {
constructor(container, items, itemHeight) {
this.container = container
this.items = items
this.itemHeight = itemHeight
this.visibleCount = Math.ceil(container.clientHeight / itemHeight) + 2
this.startIndex = 0
this.render()
this.bindEvents()
}
render() {
const fragment = document.createDocumentFragment()
const endIndex = Math.min(this.startIndex + this.visibleCount, this.items.length)
for (let i = this.startIndex; i < endIndex; i++) {
const itemElement = this.createItemElement(this.items[i], i)
itemElement.style.transform = `translateY(${i * this.itemHeight}px)`
fragment.appendChild(itemElement)
}
this.container.innerHTML = ''
this.container.appendChild(fragment)
}
createItemElement(item, index) {
const element = document.createElement('div')
element.className = 'list-item'
element.textContent = item.text
element.style.height = `${this.itemHeight}px`
element.style.position = 'absolute'
element.style.width = '100%'
return element
}
bindEvents() {
this.container.addEventListener('scroll', () => {
const newStartIndex = Math.floor(this.container.scrollTop / this.itemHeight)
if (newStartIndex !== this.startIndex) {
this.startIndex = newStartIndex
this.render()
}
})
}
}
```
### 2. 防抖和节流
对于频繁触发的操作,使用防抖和节流:
```javascript
// 防抖函数
function debounce(func, wait) {
let timeout
return function(...args) {
clearTimeout(timeout)
timeout = setTimeout(() => func.apply(this, args), wait)
}
}
// 节流函数
function throttle(func, limit) {
let inThrottle
return function(...args) {
if (!inThrottle) {
func.apply(this, args)
inThrottle = true
setTimeout(() => inThrottle = false, limit)
}
}
}
// 使用示例
const handleResize = debounce(() => {
console.log('窗口大小改变')
}, 300)
const handleScroll = throttle(() => {
console.log('页面滚动')
}, 100)
window.addEventListener('resize', handleResize)
window.addEventListener('scroll', handleScroll)
```
### 3. 懒加载
对于图片和组件,使用懒加载技术:
```javascript
// 图片懒加载
class ImageLazyLoader {
constructor() {
this.images = []
this.observer = new IntersectionObserver((entries) => {
entries.forEach(entry => {
if (entry.isIntersecting) {
this.loadImage(entry.target)
this.observer.unobserve(entry.target)
}
})
})
}
loadImage(img) {
const src = img.dataset.src
if (src) {
img.src = src
img.classList.remove('lazy')
img.classList.add('loaded')
}
}
observe(img) {
this.observer.observe(img)
}
}
// 使用懒加载
const lazyLoader = new ImageLazyLoader()
document.querySelectorAll('img[data-src]').forEach(img => {
lazyLoader.observe(img)
})
```
## 测试
编写测试是确保应用质量的重要环节。
### 单元测试
使用Jest等测试框架编写单元测试
```javascript
// 测试元素创建功能
describe('Element Creation', () => {
test('should create sprite element', () => {
const sprite = game.create('sprite', { x: 100, y: 100 })
expect(sprite).toBeDefined()
expect(sprite.getX()).toBe(100)
expect(sprite.getY()).toBe(100)
})
test('should create box element', () => {
const box = game.create('box', { width: 200, height: 100 })
expect(box.getWidth()).toBe(200)
expect(box.getHeight()).toBe(100)
})
})
```
### 集成测试
测试组件和场景的集成:
```javascript
// 测试场景切换
describe('Scene Navigation', () => {
test('should navigate to about page', async () => {
// 模拟场景切换
await game.switchToPath('/about')
// 验证场景是否正确加载
const currentScene = game.getCurrentScene()
expect(currentScene.path).toBe('/about')
})
})
```
## 部署
将PE应用部署到生产环境需要注意以下几点
### 构建优化
```javascript
// vite.config.js
import { defineConfig } from 'vite'
import { resolve } from 'path'
export default defineConfig({
build: {
// 代码分割
rollupOptions: {
output: {
manualChunks: {
vendor: ['pe-engine'],
utils: ['./src/utils'],
}
}
},
// 压缩
minify: 'terser',
terserOptions: {
compress: {
drop_console: true,
drop_debugger: true
}
}
},
// 静态资源处理
assetsInclude: ['**/*.pe', '**/*.less']
})
```
### 环境配置
```javascript
// 配置不同环境
const config = {
development: {
apiBaseUrl: 'http://localhost:3000',
debug: true
},
production: {
apiBaseUrl: 'https://api.example.com',
debug: false
}
}
const currentConfig = config[process.env.NODE_ENV || 'development']
```
通过以上进阶主题的学习你将能够构建更复杂、更高效的PE应用。在接下来的章节中我们将深入探讨每个主题的更多细节。