You need to enable JavaScript to run this app.
优惠活动
大模型
产品
解决方案
定价
更多

Vanilla JS/HTML/CSS 2D动画游戏蜘蛛卡顿及蛛网残留问题求助

2D游戏蜘蛛角色bug修复方案

问题现象

开发2D动画游戏时,蜘蛛角色出现两个异常:

  • 部分蜘蛛卡在路径上无法移动
  • 部分蜘蛛爬出屏幕后,蛛网仍残留不消失

问题根源

  1. Spider类构造函数参数缺失:
    Spider类构造函数未接收game参数,导致调用super(game)时传入undefined,后续this.game.width、this.game.height计算失效,生成无效的位置和移动边界值,引发蜘蛛卡顿。
  2. 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

相关产品推荐
方舟 Agent Plan

超全模态模型 × Harness 升级,最新支持 Deepseek-V4.1-Flash、GLM-5.3 系列、Doubao-Seedream-5.0-pro、Kimi-K3 (部分), 限时 9.9 元起

最近更新时间:2026.08.22 11:48:59