Vanilla JS/HTML/CSS 2D动画游戏蜘蛛卡顿及蛛网残留问题求助
2D游戏蜘蛛角色bug修复方案
问题现象
开发2D动画游戏时,蜘蛛角色出现两个异常:
- 部分蜘蛛卡在路径上无法移动
- 部分蜘蛛爬出屏幕后,蛛网仍残留不消失
问题根源
- Spider类构造函数参数缺失:
Spider类构造函数未接收game参数,导致调用super(game)时传入undefined,后续this.game.width、this.game.height计算失效,生成无效的位置和移动边界值,引发蜘蛛卡顿。 - update方法逻辑顺序错误:
Spider的update方法先调用父类的x轴移动判断,但蜘蛛vx为0,该判断无效;同时上边界删除条件的位置逻辑顺序颠倒,导致蜘蛛未正确触发删除,残留蛛网。
修复代码
JavaScript部分
document.addEventListener('DOMContentLoaded', function() { const canvas = document.getElementById('canvas1'); const ctx = canvas.getContext('2d'); canvas.width = 500; canvas.height = 800; class Game { constructor(ctx, width, height) { this.ctx = ctx; this.width = width; this.height = height; this.enemies = []; this.enemyInterval = 400; this.enemyTimer = 0; this.enemyTypes = ["worm", "ghost", "spider"]; } update(deltaTime) { this.enemies = this.enemies.filter(object => !object.markedForDeletion); if (this.enemyTimer > this.enemyInterval) { this.#addNewEnemy(); this.enemyTimer = 0; } else { this.enemyTimer += deltaTime; } this.enemies.forEach(object => object.update(deltaTime)); } draw() { this.enemies.forEach(object => object.draw(this.ctx)); } #addNewEnemy() { const randomEnemy = this.enemyTypes[Math.floor(Math.random() * this.enemyTypes.length)]; if (randomEnemy === "worm") this.enemies.push(new Worm(this)); else if (randomEnemy === "ghost") this.enemies.push(new Ghost(this)); else if (randomEnemy === "spider") this.enemies.push(new Spider(this)); } } class Enemy { constructor(game) { this.game = game; this.markedForDeletion = false; this.frameX = 0; this.maxFrame = 5; this.frameInterval = 100; this.frameTimer = 0; } update(deltaTime) { this.x -= this.vx * deltaTime; if (this.x < 0 - this.width) this.markedForDeletion = true; if (this.frameTimer > this.frameInterval) { if (this.frameX < this.maxFrame) this.frameX++; else this.frameX = 0; this.frameTimer = 0; } else { this.frameTimer += deltaTime; } } draw(ctx) { ctx.drawImage(this.image, this.frameX * this.spriteWidth, 0, this.spriteWidth, this.spriteHeight, this.x, this.y, this.width, this.height); } } class Spider extends Enemy{ constructor(game) { super(game); this.spriteWidth = 310; this.spriteHeight = 175; this.width = this.spriteWidth/2; this.height = this.spriteHeight/2; this.x = Math.random() * this.game.width; this.y = 0 - this.height; this.image = document.getElementById('spider'); this.vx = 0; this.vy = Math.random() * 0.1 + 0.1; this.maxLength = Math.random() * this.game.height * 0.7; } update(deltaTime) { this.y += this.vy * deltaTime; if (this.y > this.maxLength) this.vy *= -1; if (this.y < -this.height * 1.5) this.markedForDeletion = true; super.update(deltaTime); } draw(ctx) { if (!this.markedForDeletion) { ctx.beginPath(); ctx.moveTo(this.x + this.width/2, 0); ctx.lineTo(this.x + this.width/2, this.y + 10); ctx.stroke(); } super.draw(ctx); } } class Worm extends Enemy { constructor(game) { super(game); this.spriteWidth = 229; this.spriteHeight = 171; this.width = this.spriteWidth/2; this.height = this.spriteHeight/2; this.x = this.game.width; this.y = this.game.height - this.height; this.image = document.getElementById('worm'); this.vx = Math.random() * 0.1 + 0.1; } } class Ghost extends Enemy { constructor(game) { super(game); this.spriteWidth = 261; this.spriteHeight = 209; this.width = this.spriteWidth/2; this.height = this.spriteHeight/2; this.x = this.game.width; this.y = Math.random() * this.game.height * 0.6; this.image = document.getElementById('ghost'); this.vx = Math.random() * 0.2 + 0.1; this.angle = 0; this.curve = Math.random() * 3; } update(deltaTime) { super.update(deltaTime); this.y += Math.sin(this.angle) * this.curve; this.angle += 0.04; } } const game = new Game(ctx, canvas.width, canvas.height); let lastTime = 0; function animate(timeStamp) { ctx.clearRect(0, 0, canvas.width, canvas.height); const deltaTime = timeStamp - lastTime; lastTime = timeStamp; game.update(deltaTime); game.draw(); requestAnimationFrame(animate); } animate(0); })
CSS部分
#canvas1 { border: 3px solid black; width: 500px; height: 800px; position: absolute; top: 50%; left: 50%; transform: translate(-50%, -50%); } img { display: none; }
HTML部分
<!DOCTYPE html> <html lang="en"> <head> <meta charset="UTF-8"> <meta http-equiv="X-UA-Compatible" content="IE=edge"> <meta name="viewport" content="width=device-width, initial-scale=1.0"> <title>Enemy Variety</title> <link rel="stylesheet" href="style.css"> </head> <body> <canvas id="canvas1"></canvas> <img src="images/enemy_worm.png" id="worm"> <img src="images/enemy_ghost.png" id="ghost"> <img src="images/enemy_spider.png" id="spider"> <script src="script.js"></script> </body> </html>
额外说明
- 补充了原代码缺失的Worm和Ghost类,避免运行时报错
- 将蜘蛛图片的获取方式改为
document.getElementById('spider'),避免依赖未声明的全局变量 - 修正了
lastTime初始值为0,避免首次动画帧的deltaTime异常
内容的提问来源于stack exchange,提问作者norwegian_forest
相关产品推荐
相关产品推荐

