如何用原生JavaScript阻止Sprite移出Canvas画布?
如何用原生JavaScript阻止Sprite移出Canvas画布
我正在用原生JS、HTML和少量CSS开发游戏,创建了两个Sprite方块,但它们向Canvas左右边缘移动时停不下来。现有解决方案都是用其他语言或库,求原生JS的解决办法。
问题分析
看你代码里的两处核心问题:
- 在
Sprite类的update方法中,this.velocity.x == 0是比较运算符,不是赋值操作,根本没把速度设为0; - 就算改了赋值,
animate函数里每次都会重置velocity.x = 0,再根据按键重新设置速度,导致边界停止的逻辑被覆盖。
解决方案
要彻底解决这个问题,需要做两处关键修改:
- 修复赋值错误,同时在触碰边界时把Sprite的位置拉回画布范围内,避免偏移;
- 在移动逻辑中,判断Sprite是否已经处于画布边缘,禁止继续向边界方向移动。
修改后的完整代码
JavaScript 代码
const canvas = document.querySelector('#canvas'); const ctx = canvas.getContext("2d"); canvas.width = 1024; canvas.height = 576; function logMessage(msg) { document.querySelector('#myMessage').textContent += msg + '. '; } const gravity = 0.7; class Sprite { constructor({position, velocity}) { this.position = position; this.velocity = velocity; this.height = 150; this.width = 50; // 将宽度设为类属性,避免硬编码 this.lastKey; } draw() { ctx.fillStyle = 'red'; ctx.fillRect(this.position.x, this.position.y, this.width, this.height); } update() { this.draw(); this.position.x += this.velocity.x; this.position.y += this.velocity.y; // 左右边界检测与位置修正 // 左边界处理 if (this.position.x <= 0) { this.position.x = 0; // 拉回画布内 this.velocity.x = 0; // 停止x方向移动 logMessage("左边界触发"); } // 右边界处理(Sprite宽度+位置不能超过画布宽度) else if (this.position.x + this.width >= canvas.width) { this.position.x = canvas.width - this.width; // 拉回画布内 this.velocity.x = 0; // 停止x方向移动 logMessage("右边界触发"); } // 底部边界逻辑保留 if (this.position.y + this.height + this.velocity.y >= canvas.height) { this.velocity.y = 0; } else { this.velocity.y += gravity; } } } const Player = new Sprite({ position: { x: 0, y: 0 }, velocity: { x: 0, y: 0 } }) const Enemy = new Sprite({ position: { x: 400, y: 100 }, velocity: { x: 0, y: 0 } }) const keys = { w: { pressed: false }, a: { pressed: false }, d: { pressed: false }, ArrowUp: { pressed: false }, ArrowLeft: { pressed: false }, ArrowRight: { pressed: false } } function animate() { window.requestAnimationFrame(animate); ctx.fillStyle = 'black'; ctx.fillRect(0, 0, canvas.width, canvas.height); Player.update(); Enemy.update(); // 玩家移动逻辑:增加边界判断,禁止边缘外移动 Player.velocity.x = 0; if (keys.a.pressed && Player.lastKey === "a" && Player.position.x > 0) { Player.velocity.x = -5; } else if (keys.d.pressed && Player.lastKey === "d" && Player.position.x + Player.width < canvas.width) { Player.velocity.x = 5; } // 敌人移动逻辑同理 Enemy.velocity.x = 0; if (keys.ArrowLeft.pressed && Enemy.lastKey === "ArrowLeft" && Enemy.position.x > 0) { Enemy.velocity.x = -5; } else if (keys.ArrowRight.pressed && Enemy.lastKey === "ArrowRight" && Enemy.position.x + Enemy.width < canvas.width) { Enemy.velocity.x = 5; } } animate(); window.addEventListener('keydown', (event) => { switch (event.key) { case 'w': Player.velocity.y = -20; break; case 'a': keys.a.pressed = true; Player.lastKey = "a"; break; case 'd': keys.d.pressed = true; Player.lastKey = "d"; break; } switch (event.key) { case 'ArrowUp': Enemy.velocity.y = -20; break; case 'ArrowRight': keys.ArrowRight.pressed = true; Enemy.lastKey = 'ArrowRight'; break; case 'ArrowLeft': keys.ArrowLeft.pressed = true; Enemy.lastKey = 'ArrowLeft'; break; } }) window.addEventListener('keyup', (event) => { switch (event.key) { case 'w': keys.w.pressed = false; break; case 'a': keys.a.pressed = false; break; case 'd': keys.d.pressed = false; break; } switch (event.key) { case 'ArrowUp': keys.ArrowUp.pressed = false; break; case 'ArrowLeft': keys.ArrowLeft.pressed = false; break; case 'ArrowRight': keys.ArrowRight.pressed = false; break; } })
CSS 代码
#myConsole { background-color: black; color: white; min-height: 100px; }
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"> <meta name="author" content="Christian Davis"> <link rel="stylesheet" href="styles.css"> <title>Fighting Game</title> </head> <body> <canvas id="canvas"></canvas> <p id="myConsole">> <span id="myMessage"></span></p> <script src="app.js"></script> </body> </html>
关键修改说明
- 给
Sprite类添加了width属性,避免硬编码宽度值,提升代码可维护性; - 在
update方法中,不仅停止x方向速度,还将Sprite位置修正到画布边缘内,防止因速度导致的偏移; - 在移动逻辑中增加边界判断:只有当Sprite不在对应边缘时,才允许向该方向移动,彻底阻止移出画布。
内容的提问来源于stack exchange,提问作者That New Coder
相关产品推荐
相关产品推荐

