Files
2025-10-03 16:49:53 +08:00

9.3 KiB
Raw Permalink Blame History

进阶主题

在掌握了PE引擎的基础知识后我们可以探索一些更高级的功能和概念。这些进阶主题将帮助你构建更复杂、更高效的应用。

目录

动画系统

PE引擎内置了强大的动画系统支持补间动画、帧动画和序列动画。

补间动画

补间动画允许你在两个状态之间创建平滑的过渡:

// 创建补间动画
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()

帧动画

帧动画通过连续播放一系列图像来创建动画效果:

// 创建帧动画
game.createFrameAnimation('walk', [
  'img/walk1.png',
  'img/walk2.png',
  'img/walk3.png',
  'img/walk4.png'
], 10) // 10帧每秒

// 播放帧动画
game.playFrameAnimation(sprite, 'walk', true) // 循环播放

序列动画

序列动画允许你按顺序播放多个动画:

// 创建动画序列
game.createSequence('moveAndFade', [
  {
    target: element.element,
    props: { left: '500px' },
    duration: 1000
  },
  {
    target: element.element,
    props: { opacity: 0 },
    duration: 500
  }
])

// 播放序列动画
game.playSequence('moveAndFade')

状态管理

对于复杂应用合理的状态管理至关重要。PE引擎提供了灵活的状态管理方案。

全局状态

// 创建全局状态管理器
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)
})

场景状态

每个场景也可以有自己的状态管理:

<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引擎支持插件系统允许你扩展引擎的功能。

创建插件

// 定义插件
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引擎提供了一些有用的内置插件

// 路由插件
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. 虚拟化列表

对于大量数据的列表渲染,使用虚拟化技术:

// 虚拟化列表组件
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. 防抖和节流

对于频繁触发的操作,使用防抖和节流:

// 防抖函数
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. 懒加载

对于图片和组件,使用懒加载技术:

// 图片懒加载
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等测试框架编写单元测试

// 测试元素创建功能
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)
  })
})

集成测试

测试组件和场景的集成:

// 测试场景切换
describe('Scene Navigation', () => {
  test('should navigate to about page', async () => {
    // 模拟场景切换
    await game.switchToPath('/about')
    
    // 验证场景是否正确加载
    const currentScene = game.getCurrentScene()
    expect(currentScene.path).toBe('/about')
  })
})

部署

将PE应用部署到生产环境需要注意以下几点

构建优化

// 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']
})

环境配置

// 配置不同环境
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应用。在接下来的章节中我们将深入探讨每个主题的更多细节。