logo

从零复刻Chrome小恐龙游戏:Vue3响应式架构下的实现与优化

作者:十万个为什么2025.09.23 12:22浏览量:0

简介:本文深入解析如何使用Vue3实现Chrome小恐龙游戏,涵盖Canvas渲染、键盘事件处理、碰撞检测等核心功能,提供完整代码示例与性能优化方案。

一、项目架构设计

1.1 组件化拆分策略

采用Vue3单文件组件模式,将游戏拆分为三个核心组件:

  • GameCanvas.vue:封装Canvas渲染逻辑,负责游戏画布的创建与更新
  • GameController.vue:处理键盘事件与游戏状态管理
  • GameScore.vue:显示分数与游戏状态UI

这种拆分方式符合Vue3的组合式API设计理念,每个组件专注于单一职责。通过provide/inject实现跨组件通信,避免props层层传递。

1.2 响应式数据模型

使用Vue3的reactive创建游戏状态对象:

  1. const gameState = reactive({
  2. isRunning: false,
  3. score: 0,
  4. speed: 5,
  5. obstacles: [] as Obstacle[],
  6. dino: {
  7. x: 80,
  8. y: 310,
  9. velocity: 0,
  10. isJumping: false
  11. }
  12. })

二、核心功能实现

2.1 Canvas渲染系统

2.1.1 画布初始化

onMounted生命周期中创建Canvas上下文:

  1. const canvasRef = ref<HTMLCanvasElement>(null)
  2. let ctx: CanvasRenderingContext2D | null = null
  3. onMounted(() => {
  4. const canvas = canvasRef.value
  5. if (canvas) {
  6. canvas.width = window.innerWidth
  7. canvas.height = 400
  8. ctx = canvas.getContext('2d')
  9. }
  10. })

2.1.2 游戏循环实现

采用requestAnimationFrame实现60FPS渲染:

  1. let animationId: number
  2. const gameLoop = () => {
  3. if (!ctx || !gameState.isRunning) return
  4. clearCanvas()
  5. updateGameState()
  6. renderAll()
  7. animationId = requestAnimationFrame(gameLoop)
  8. }

2.2 物理系统实现

2.2.1 重力模拟

通过加速度计算实现真实跳跃效果:

  1. const gravity = 0.6
  2. const jumpForce = -15
  3. const updateDino = () => {
  4. if (gameState.dino.isJumping) {
  5. gameState.dino.velocity += gravity
  6. gameState.dino.y += gameState.dino.velocity
  7. // 地面检测
  8. if (gameState.dino.y > 310) {
  9. gameState.dino.y = 310
  10. gameState.dino.isJumping = false
  11. gameState.dino.velocity = 0
  12. }
  13. }
  14. }

2.2.2 障碍物生成

使用时间间隔动态生成障碍物:

  1. const obstacleInterval = ref(2000)
  2. let lastObstacleTime = 0
  3. const generateObstacle = () => {
  4. const types = ['cactus', 'bird']
  5. const type = types[Math.floor(Math.random() * types.length)]
  6. const x = canvasRef.value?.width || 800
  7. gameState.obstacles.push({
  8. x,
  9. type,
  10. width: type === 'cactus' ? 40 : 60,
  11. height: type === 'cactus' ? 70 : 40
  12. })
  13. }

2.3 碰撞检测系统

2.3.1 AABB碰撞检测

实现基于矩形包围盒的碰撞检测:

  1. const checkCollision = (dino: Dino, obstacle: Obstacle) => {
  2. return dino.x < obstacle.x + obstacle.width &&
  3. dino.x + 40 > obstacle.x &&
  4. dino.y < obstacle.y + obstacle.height &&
  5. dino.y + 50 > obstacle.y
  6. }

2.3.2 碰撞响应

检测到碰撞时触发游戏结束:

  1. const detectCollisions = () => {
  2. for (const obstacle of gameState.obstacles) {
  3. if (checkCollision(gameState.dino, obstacle)) {
  4. endGame()
  5. break
  6. }
  7. }
  8. }

三、性能优化方案

3.1 脏矩形渲染

实现局部更新减少重绘区域:

  1. const dirtyRects = ref<DOMRect[]>([])
  2. const markDirty = (rect: DOMRect) => {
  3. dirtyRects.value.push(rect)
  4. }
  5. const clearCanvas = () => {
  6. if (!ctx) return
  7. if (dirtyRects.value.length === 0) {
  8. ctx.clearRect(0, 0, canvas.width, canvas.height)
  9. } else {
  10. for (const rect of dirtyRects.value) {
  11. ctx.clearRect(rect.x, rect.y, rect.width, rect.height)
  12. }
  13. dirtyRects.value = []
  14. }
  15. }

3.2 对象池模式

预创建障碍物对象避免频繁GC:

  1. const obstaclePool: Obstacle[] = []
  2. const poolSize = 10
  3. // 初始化对象池
  4. for (let i = 0; i < poolSize; i++) {
  5. obstaclePool.push({
  6. x: 0,
  7. y: 310,
  8. type: 'cactus',
  9. width: 40,
  10. height: 70
  11. })
  12. }
  13. const getObstacleFromPool = () => {
  14. return obstaclePool.pop() || { x: 0, y: 310, type: 'cactus', width: 40, height: 70 }
  15. }

四、扩展功能实现

4.1 难度递增系统

根据分数动态调整游戏速度:

  1. const updateDifficulty = () => {
  2. if (gameState.score % 100 === 0 && gameState.score > 0) {
  3. gameState.speed += 0.5
  4. obstacleInterval.value = Math.max(800, obstacleInterval.value - 100)
  5. }
  6. }

4.2 移动端适配

添加触摸事件支持:

  1. const handleTouchStart = (e: TouchEvent) => {
  2. if (!gameState.isRunning) {
  3. startGame()
  4. } else if (!gameState.dino.isJumping) {
  5. gameState.dino.isJumping = true
  6. gameState.dino.velocity = jumpForce
  7. }
  8. }
  9. onMounted(() => {
  10. window.addEventListener('touchstart', handleTouchStart)
  11. })

五、完整实现示例

5.1 主组件集成

  1. <template>
  2. <div class="game-container">
  3. <GameScore :score="gameState.score" />
  4. <canvas ref="canvasRef" @click="handleJump"></canvas>
  5. <GameController
  6. :is-running="gameState.isRunning"
  7. @start="startGame"
  8. @pause="pauseGame"
  9. />
  10. </div>
  11. </template>
  12. <script setup>
  13. import { ref, reactive, onMounted } from 'vue'
  14. import GameScore from './GameScore.vue'
  15. import GameController from './GameController.vue'
  16. // 游戏状态与逻辑实现...
  17. </script>

5.2 部署优化建议

  1. 使用Vue的v-once指令优化静态UI
  2. 启用生产模式构建:vue-cli-service build --mode production
  3. 添加Service Worker实现离线缓存
  4. 使用Webpack的TerserPlugin进行代码压缩

六、常见问题解决方案

6.1 Canvas模糊问题

解决方案:确保Canvas尺寸与CSS尺寸匹配:

  1. const resizeCanvas = () => {
  2. const canvas = canvasRef.value
  3. if (canvas) {
  4. const dpr = window.devicePixelRatio || 1
  5. canvas.style.width = `${window.innerWidth}px`
  6. canvas.style.height = '400px'
  7. canvas.width = window.innerWidth * dpr
  8. canvas.height = 400 * dpr
  9. ctx?.scale(dpr, dpr)
  10. }
  11. }

6.2 内存泄漏防范

  1. 在组件卸载时取消动画循环:
    1. onUnmounted(() => {
    2. cancelAnimationFrame(animationId)
    3. })
  2. 及时清理事件监听器
  3. 使用WeakMap存储游戏对象引用

通过以上技术实现,我们成功构建了一个基于Vue3的Chrome小恐龙游戏复刻版。该实现不仅完整还原了原始游戏的核心玩法,还通过Vue的响应式系统实现了更清晰的状态管理。开发者可以基于此框架进一步扩展多人模式、道具系统等高级功能。

相关文章推荐

发表评论