Canvas游戏开发疑问:为何需在玩家底部位置计算中加入velocity?
为什么落地检测要加上velocity.y?
核心原因是:防止玩家角色“穿”进地面里,避免出现角色陷进地面的视觉bug。
先理清楚你代码里update()函数的执行顺序(每一次动画帧都会跑一遍):
- 画出当前位置的玩家
- 用当前的
velocity.y更新玩家的position.y(让玩家完成本次移动) - 判断下一次移动后玩家会不会撞地面:如果不会,就继续让重力加速;如果会,就把速度清零,让玩家停在地面。
只判断当前底部位置为什么不行?
举个具体的数字例子:
- 画布高度
canvas.height是650(地面的y坐标) - 玩家当前的底部位置(
position.y + height)是640,离地面还有10像素 - 当前
velocity.y是20(因为重力一直在拉,下落速度越来越快)
如果只写this.position.y + this.height <= canvas.height:
- 640 ≤ 650,条件成立,代码会给
velocity.y再加重力(比如变成27.4) - 下一次动画帧,玩家会用这个新速度移动:
position.y += 27.4,底部直接变成640+27.4=667.4,超过了地面的650,角色就陷进地面里了,看起来很奇怪。
加上velocity.y后解决了什么?
现在用this.position.y + this.height + this.velocity.y <= canvas.height判断:
- 这个式子算的是下一次移动后玩家的底部位置:640 + 20 = 660
- 660 > 650,条件不成立,代码直接把
velocity.y设为0 - 下一次动画帧,玩家移动距离是0,就停在当前位置,不会再往下掉,自然不会穿进地面。
再看刚好落地的情况
当玩家底部刚好到650(刚好踩在地面):
- 如果不加velocity.y,
650 ≤ 650条件成立,会继续加重力,velocity.y变大,下一次移动就会让底部超过650 - 加上velocity.y后,
650 + velocity.y(此时velocity.y是之前的下落速度,是正数)会大于650,条件不成立,把velocity.y设为0,下一次就不会移动了,稳稳停在地面上。
说白了,这行代码是在提前预判下一次移动会不会撞墙/落地,提前把速度停下来,避免角色“穿模”。
你的完整代码:
let canvas = document.getElementById("canvas"); let ctx = canvas.getContext("2d"); canvasWidth = 770; canvasHeight = 650; canvas.width = canvasWidth; canvas.height = canvasHeight; let gravity = 7.4; class Player { constructor() { this.position = { x: 175, y: 0 } this.velocity = { x: 0, y: 0 } this.width = 65; this.height = 60; } draw() { ctx.fillStyle = "goldenrod"; ctx.fillRect(this.position.x, this.position.y, this.width, this.height) } update() { this.draw(); this.position.y += this.velocity.y; if(this.position.y + this.height + this.velocity.y <= canvas.height) { this.velocity.y += gravity; } else { this.velocity.y = 0 } } } let player = new Player(); player.draw() function animate() { requestAnimationFrame(animate) ctx.clearRect(0, 0, canvasWidth, canvasHeight); player.update(); } animate()
内容的提问来源于stack exchange,提问作者Heavenly Gater
相关产品推荐
相关产品推荐

