从零开始:Vue 实现 Chrome 小恐龙游戏
2025.10.11 17:06浏览量:0简介:本文详解如何使用 Vue 3 实现 Chrome 浏览器离线时的小恐龙游戏,覆盖物理引擎、碰撞检测、动画控制等核心模块,提供完整代码实现与性能优化方案。
一、项目概述与技术选型
Chrome 小恐龙游戏是浏览器在离线状态下显示的经典 2D 跳跃游戏,其核心机制包含:
- 基于 Canvas 的 2D 图形渲染
- 物理引擎驱动的角色运动
- 碰撞检测与障碍物生成
- 分数计算与游戏状态管理
选择 Vue 3 实现的优势在于:
- 响应式系统:利用
ref
和reactive
管理游戏状态 - 组合式 API:通过
setup()
函数组织逻辑代码 - 生命周期钩子:精准控制游戏初始化与销毁
- 组件化开发:将游戏元素拆分为可复用组件
项目结构建议:
src/
├── components/
│ ├── GameCanvas.vue # 主画布组件
│ ├── Dino.vue # 恐龙角色组件
│ ├── Obstacle.vue # 障碍物组件
│ └── Score.vue # 分数显示组件
├── composables/
│ ├── useGameLoop.ts # 游戏循环逻辑
│ └── usePhysics.ts # 物理引擎
└── App.vue # 主入口组件
二、核心实现步骤
1. 画布初始化与基础设置
在 GameCanvas.vue
中创建 Canvas 元素并设置基础参数:
<template>
<canvas
ref="canvasRef"
:width="width"
:height="height"
@click="handleJump"
></canvas>
</template>
<script setup>
import { ref, onMounted } from 'vue'
const canvasRef = ref(null)
const width = 800
const height = 300
let ctx = null
onMounted(() => {
ctx = canvasRef.value.getContext('2d')
// 初始化游戏背景
ctx.fillStyle = '#f7f7f7'
ctx.fillRect(0, 0, width, height)
})
</script>
2. 物理引擎实现
创建 usePhysics.ts
组合式函数处理重力与跳跃:
import { ref } from 'vue'
export function usePhysics() {
const gravity = 0.6
const jumpForce = -10
const velocity = ref(0)
const isJumping = ref(false)
const applyGravity = () => {
if (velocity.value < 10) { // 终端速度
velocity.value += gravity
}
}
const jump = () => {
if (!isJumping.value) {
velocity.value = jumpForce
isJumping.value = true
}
}
return { velocity, isJumping, applyGravity, jump }
}
3. 恐龙角色动画
在 Dino.vue
中实现角色动画:
<script setup>
import { ref, watch } from 'vue'
import { usePhysics } from '@/composables/usePhysics'
const { velocity, isJumping, applyGravity, jump } = usePhysics()
const position = ref(0)
const frame = ref(0)
const frames = [0, 1, 2] // 奔跑动画帧
// 更新角色位置
watch(velocity, (newVal) => {
position.value += newVal
if (position.value >= 0) {
isJumping.value = false
}
})
// 动画循环
const animate = () => {
frame.value = (frame.value + 0.2) % frames.length
requestAnimationFrame(animate)
}
defineExpose({ jump })
</script>
4. 障碍物生成与碰撞检测
实现障碍物类与碰撞检测逻辑:
// obstacle.ts
export class Obstacle {
x: number
width: number
height: number
type: 'cactus' | 'bird'
constructor(type: 'cactus' | 'bird' = 'cactus') {
this.type = type
this.width = type === 'cactus' ? 30 : 50
this.height = type === 'cactus' ? 50 : 30
this.x = 800 // 初始位置在画布右侧
}
update(speed: number) {
this.x -= speed
}
draw(ctx: CanvasRenderingContext2D) {
ctx.fillStyle = '#333'
if (this.type === 'cactus') {
ctx.fillRect(this.x, 220, this.width, this.height)
} else {
// 鸟类障碍物绘制
ctx.fillRect(this.x, 180, this.width, this.height)
}
}
}
// 碰撞检测函数
export function checkCollision(dinoY: number, obstacle: Obstacle) {
const dinoHeight = 60
const dinoWidth = 40
return (
dinoX + dinoWidth > obstacle.x &&
dinoX < obstacle.x + obstacle.width &&
(dinoY + dinoHeight > 220 || // 地面障碍物
dinoY < 180 + obstacle.height) // 空中障碍物
)
}
5. 游戏主循环实现
创建 useGameLoop.ts
管理游戏状态:
import { ref, onUnmounted } from 'vue'
import { Obstacle } from './obstacle'
export function useGameLoop() {
const obstacles = ref<Obstacle[]>([])
const score = ref(0)
const gameSpeed = ref(5)
const isRunning = ref(false)
let animationId: number
const generateObstacle = () => {
const types = ['cactus', 'cactus', 'bird'] as const
const type = types[Math.floor(Math.random() * types.length)]
obstacles.value.push(new Obstacle(type))
}
const update = () => {
obstacles.value.forEach(obs => {
obs.update(gameSpeed.value)
if (obs.x < -obs.width) {
obstacles.value = obstacles.value.filter(o => o !== obs)
score.value++
}
})
// 每2秒生成一个新障碍物
if (Math.random() < 0.005) {
generateObstacle()
}
}
const startLoop = () => {
isRunning.value = true
const loop = () => {
update()
animationId = requestAnimationFrame(loop)
}
loop()
}
onUnmounted(() => {
cancelAnimationFrame(animationId)
})
return { score, gameSpeed, isRunning, startLoop }
}
三、性能优化方案
- 对象池技术:复用障碍物对象减少内存分配
```typescript
const obstaclePool: Obstacle[] = []
for (let i = 0; i < 10; i++) {
obstaclePool.push(new Obstacle())
}
const getObstacle = (type: ‘cactus’ | ‘bird’) => {
const obstacle = obstaclePool.find(o => !o.inUse)
if (obstacle) {
obstacle.type = type
obstacle.inUse = true
return obstacle
}
return new Obstacle(type)
}
2. **分层渲染**:将静态背景与动态元素分离
```vue
<template>
<canvas ref="bgCanvas" :width="width" :height="height"></canvas>
<canvas ref="gameCanvas" :width="width" :height="height"></canvas>
</template>
- 节流处理:限制游戏状态更新频率
let lastUpdate = 0
const throttleUpdate = (callback: () => void, limit = 16) => {
const now = Date.now()
if (now - lastUpdate >= limit) {
callback()
lastUpdate = now
}
}
四、完整游戏集成
在 App.vue
中整合所有组件:
<template>
<div class="game-container">
<GameCanvas
ref="gameCanvas"
@game-over="handleGameOver"
/>
<Score :value="score" />
<button @click="startGame" :disabled="isRunning">
{{ isRunning ? '游戏中' : '开始游戏' }}
</button>
</div>
</template>
<script setup>
import { ref } from 'vue'
import GameCanvas from './components/GameCanvas.vue'
import Score from './components/Score.vue'
import { useGameLoop } from './composables/useGameLoop'
const { score, isRunning, startLoop } = useGameLoop()
const gameCanvas = ref(null)
const startGame = () => {
if (gameCanvas.value) {
gameCanvas.value.reset()
}
startLoop()
}
const handleGameOver = () => {
isRunning.value = false
}
</script>
五、扩展功能建议
移动端适配:添加触摸事件支持
const handleTouchStart = (e: TouchEvent) => {
if (e.touches.length === 1) {
const touch = e.touches[0]
if (touch.clientY < height * 0.7) {
// 触摸上半部分执行跳跃
jump()
}
}
}
难度递增系统:根据分数动态调整游戏速度
watch(score, (newScore) => {
if (newScore % 10 === 0) {
gameSpeed.value += 0.5
}
})
音效系统:集成 Web Audio API
const playJumpSound = () => {
const audioCtx = new (window.AudioContext || (window as any).webkitAudioContext)()
const oscillator = audioCtx.createOscillator()
const gainNode = audioCtx.createGain()
oscillator.connect(gainNode)
gainNode.connect(audioCtx.destination)
oscillator.type = 'square'
oscillator.frequency.setValueAtTime(440, audioCtx.currentTime)
gainNode.gain.setValueAtTime(0.1, audioCtx.currentTime)
gainNode.gain.exponentialRampToValueAtTime(0.01, audioCtx.currentTime + 0.3)
oscillator.start()
oscillator.stop(audioCtx.currentTime + 0.3)
}
该实现完整覆盖了 Chrome 小恐龙游戏的核心机制,通过 Vue 3 的组合式 API 实现了清晰的状态管理。实际开发中可根据需求进一步扩展游戏模式、添加特效系统或实现多人对战功能。完整代码仓库建议包含 TypeScript 类型定义、单元测试和构建配置文件,确保项目的可维护性。
发表评论
登录后可评论,请前往 登录 或 注册