面向对象JavaScript:如何创建并运行同一对象的多个实例?
面向对象JavaScript躲避方块游戏开发指南
嘿,很高兴看到你用做游戏来学习OOP JavaScript,这绝对是最有趣的学习方式之一!既然你的Player对象已经正常运行,主循环的定时器也搭好了,那我们一步步把剩下的核心功能补全,让游戏真正跑起来吧。
1. 敌人方块的OOP实现
先给敌人也创建一个类,和你的Player保持一致的面向对象风格,代码结构会更清晰:
class Enemy { constructor(x, y, width, height, speed) { this.x = x; this.y = y; this.width = width; this.height = height; this.speed = speed; } // 敌人从右向左移动的逻辑 update() { this.x -= this.speed; } // 绘制敌人方块 draw(ctx) { ctx.fillStyle = '#ff4444'; // 用红色区分玩家方块 ctx.fillRect(this.x, this.y, this.width, this.height); } }
2. 敌人的生成与管理
在主循环外创建一个数组来存储所有敌人,再定时生成新的敌人(避免一次性生成太多,影响游戏体验):
const enemies = []; // 每1.5秒生成一个随机位置的敌人 const enemySpawnInterval = setInterval(() => { // 随机生成y坐标,确保敌人在画布范围内 const randomY = Math.random() * (canvas.height - 50); enemies.push(new Enemy(canvas.width, randomY, 50, 50, 3)); }, 1500);
3. 主循环的核心逻辑完善
把敌人的更新、绘制,以及关键的碰撞检测逻辑,都整合到你的主循环里:
// 启动主循环(建议用requestAnimationFrame替代setInterval,更流畅) function mainLoop() { // 先清空画布,避免方块移动留下残影 ctx.clearRect(0, 0, canvas.width, canvas.height); // 更新并绘制玩家 player.update(); player.draw(ctx); // 遍历敌人列表:更新位置、绘制、清理超出屏幕的敌人 for (let i = enemies.length - 1; i >= 0; i--) { const enemy = enemies[i]; enemy.update(); enemy.draw(ctx); // 移除左侧超出屏幕的敌人,节省性能 if (enemy.x + enemy.width < 0) { enemies.splice(i, 1); } // 检测玩家与敌人是否碰撞 if (checkCollision(player, enemy)) { gameOver(); return; // 碰撞后直接终止当前循环 } } // 持续调用循环,和浏览器刷新同步 requestAnimationFrame(mainLoop); } // 矩形碰撞检测函数(通用逻辑,适用于玩家和敌人) function checkCollision(rect1, rect2) { return rect1.x < rect2.x + rect2.width && rect1.x + rect1.width > rect2.x && rect1.y < rect2.y + rect2.height && rect1.y + rect1.height > rect2.y; } // 游戏结束处理函数 function gameOver() { clearInterval(enemySpawnInterval); // 停止生成敌人 ctx.fillStyle = '#000'; ctx.font = '48px Arial'; ctx.textAlign = 'center'; ctx.fillText('Game Over!', canvas.width / 2, canvas.height / 2); } // 启动游戏 mainLoop();
4. 玩家移动的完善(如果还没实现的话)
给你的Player类加上键盘控制逻辑,让玩家能上下移动躲避敌人:
class Player { constructor(x, y, width, height, speed) { this.x = x; this.y = y; this.width = width; this.height = height; this.speed = speed; // 记录按键状态,避免按住按键时移动不连贯 this.keys = { up: false, down: false }; // 绑定键盘事件 document.addEventListener('keydown', (e) => this.handleKeyDown(e)); document.addEventListener('keyup', (e) => this.handleKeyUp(e)); } handleKeyDown(e) { if (e.key === 'ArrowUp') this.keys.up = true; if (e.key === 'ArrowDown') this.keys.down = true; } handleKeyUp(e) { if (e.key === 'ArrowUp') this.keys.up = false; if (e.key === 'ArrowDown') this.keys.down = false; } update() { // 上下移动,同时限制玩家不出画布边界 if (this.keys.up && this.y > 0) { this.y -= this.speed; } if (this.keys.down && this.y + this.height < canvas.height) { this.y += this.speed; } } draw(ctx) { ctx.fillStyle = '#4285f4'; // 蓝色玩家方块 ctx.fillRect(this.x, this.y, this.width, this.height); } } // 初始化玩家(比如放在画布左侧中间位置) const player = new Player(50, canvas.height/2 - 25, 50, 50, 5);
一些进阶小提示
- 可以给敌人设置随机速度,让游戏难度随时间递增;
- 加入分数系统,每躲过一个敌人加1分,增强游戏趣味性;
- 用
requestAnimationFrame替代setInterval做主循环,它会和浏览器刷新节奏同步,游戏更流畅,也更节省系统资源。
内容的提问来源于stack exchange,提问作者Jakub Chaloupka
相关产品推荐
相关产品推荐

