从零复刻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
创建游戏状态对象:
const gameState = reactive({
isRunning: false,
score: 0,
speed: 5,
obstacles: [] as Obstacle[],
dino: {
x: 80,
y: 310,
velocity: 0,
isJumping: false
}
})
二、核心功能实现
2.1 Canvas渲染系统
2.1.1 画布初始化
在onMounted
生命周期中创建Canvas上下文:
const canvasRef = ref<HTMLCanvasElement>(null)
let ctx: CanvasRenderingContext2D | null = null
onMounted(() => {
const canvas = canvasRef.value
if (canvas) {
canvas.width = window.innerWidth
canvas.height = 400
ctx = canvas.getContext('2d')
}
})
2.1.2 游戏循环实现
采用requestAnimationFrame
实现60FPS渲染:
let animationId: number
const gameLoop = () => {
if (!ctx || !gameState.isRunning) return
clearCanvas()
updateGameState()
renderAll()
animationId = requestAnimationFrame(gameLoop)
}
2.2 物理系统实现
2.2.1 重力模拟
通过加速度计算实现真实跳跃效果:
const gravity = 0.6
const jumpForce = -15
const updateDino = () => {
if (gameState.dino.isJumping) {
gameState.dino.velocity += gravity
gameState.dino.y += gameState.dino.velocity
// 地面检测
if (gameState.dino.y > 310) {
gameState.dino.y = 310
gameState.dino.isJumping = false
gameState.dino.velocity = 0
}
}
}
2.2.2 障碍物生成
使用时间间隔动态生成障碍物:
const obstacleInterval = ref(2000)
let lastObstacleTime = 0
const generateObstacle = () => {
const types = ['cactus', 'bird']
const type = types[Math.floor(Math.random() * types.length)]
const x = canvasRef.value?.width || 800
gameState.obstacles.push({
x,
type,
width: type === 'cactus' ? 40 : 60,
height: type === 'cactus' ? 70 : 40
})
}
2.3 碰撞检测系统
2.3.1 AABB碰撞检测
实现基于矩形包围盒的碰撞检测:
const checkCollision = (dino: Dino, obstacle: Obstacle) => {
return dino.x < obstacle.x + obstacle.width &&
dino.x + 40 > obstacle.x &&
dino.y < obstacle.y + obstacle.height &&
dino.y + 50 > obstacle.y
}
2.3.2 碰撞响应
检测到碰撞时触发游戏结束:
const detectCollisions = () => {
for (const obstacle of gameState.obstacles) {
if (checkCollision(gameState.dino, obstacle)) {
endGame()
break
}
}
}
三、性能优化方案
3.1 脏矩形渲染
实现局部更新减少重绘区域:
const dirtyRects = ref<DOMRect[]>([])
const markDirty = (rect: DOMRect) => {
dirtyRects.value.push(rect)
}
const clearCanvas = () => {
if (!ctx) return
if (dirtyRects.value.length === 0) {
ctx.clearRect(0, 0, canvas.width, canvas.height)
} else {
for (const rect of dirtyRects.value) {
ctx.clearRect(rect.x, rect.y, rect.width, rect.height)
}
dirtyRects.value = []
}
}
3.2 对象池模式
预创建障碍物对象避免频繁GC:
const obstaclePool: Obstacle[] = []
const poolSize = 10
// 初始化对象池
for (let i = 0; i < poolSize; i++) {
obstaclePool.push({
x: 0,
y: 310,
type: 'cactus',
width: 40,
height: 70
})
}
const getObstacleFromPool = () => {
return obstaclePool.pop() || { x: 0, y: 310, type: 'cactus', width: 40, height: 70 }
}
四、扩展功能实现
4.1 难度递增系统
根据分数动态调整游戏速度:
const updateDifficulty = () => {
if (gameState.score % 100 === 0 && gameState.score > 0) {
gameState.speed += 0.5
obstacleInterval.value = Math.max(800, obstacleInterval.value - 100)
}
}
4.2 移动端适配
添加触摸事件支持:
const handleTouchStart = (e: TouchEvent) => {
if (!gameState.isRunning) {
startGame()
} else if (!gameState.dino.isJumping) {
gameState.dino.isJumping = true
gameState.dino.velocity = jumpForce
}
}
onMounted(() => {
window.addEventListener('touchstart', handleTouchStart)
})
五、完整实现示例
5.1 主组件集成
<template>
<div class="game-container">
<GameScore :score="gameState.score" />
<canvas ref="canvasRef" @click="handleJump"></canvas>
<GameController
:is-running="gameState.isRunning"
@start="startGame"
@pause="pauseGame"
/>
</div>
</template>
<script setup>
import { ref, reactive, onMounted } from 'vue'
import GameScore from './GameScore.vue'
import GameController from './GameController.vue'
// 游戏状态与逻辑实现...
</script>
5.2 部署优化建议
- 使用Vue的
v-once
指令优化静态UI - 启用生产模式构建:
vue-cli-service build --mode production
- 添加Service Worker实现离线缓存
- 使用Webpack的
TerserPlugin
进行代码压缩
六、常见问题解决方案
6.1 Canvas模糊问题
解决方案:确保Canvas尺寸与CSS尺寸匹配:
const resizeCanvas = () => {
const canvas = canvasRef.value
if (canvas) {
const dpr = window.devicePixelRatio || 1
canvas.style.width = `${window.innerWidth}px`
canvas.style.height = '400px'
canvas.width = window.innerWidth * dpr
canvas.height = 400 * dpr
ctx?.scale(dpr, dpr)
}
}
6.2 内存泄漏防范
- 在组件卸载时取消动画循环:
onUnmounted(() => {
cancelAnimationFrame(animationId)
})
- 及时清理事件监听器
- 使用WeakMap存储游戏对象引用
通过以上技术实现,我们成功构建了一个基于Vue3的Chrome小恐龙游戏复刻版。该实现不仅完整还原了原始游戏的核心玩法,还通过Vue的响应式系统实现了更清晰的状态管理。开发者可以基于此框架进一步扩展多人模式、道具系统等高级功能。
发表评论
登录后可评论,请前往 登录 或 注册