如何在JS Canvas平台跳跃游戏中实现Player与Platform类碰撞检测
圆形玩家与平台碰撞检测实现方案
前置问题修复
你的现有代码存在平台重复创建的问题:动画循环animate每次执行都会往plats数组中新增平台实例,会导致内存占用持续升高,且无意义。我们先把平台实例化逻辑移到动画循环外:
// 原有平台配置 let platforms = [ [0, (height / 10) * 8, 200, 50, '#0E2A66'] ] // 直接一次性实例化所有平台,不要放在动画循环里 let plats = platforms.map(plat => new Platform(plat[0], plat[1], plat[2], plat[3], plat[4]))
Player类修改
我们需要存储玩家上一帧的Y坐标,用来判断碰撞方向,避免从平台下方穿过时误触发碰撞:
class Player { constructor(x, y, radius, color, speedX, speedY) { this.x = x this.y = y this.prevY = y // 新增:存储上一帧Y坐标 this.radius = radius this.color = color this.speedX = speedX this.speedY = speedY this.accY = 0 this.accX = 0 } draw() { c.beginPath() c.arc(this.x, this.y, this.radius, 0, Math.PI * 2, false) c.fillStyle = this.color c.fill() } update() { this.prevY = this.y // 更新上一帧坐标 this.accX = 0 this.accY = 0.5 // apply fricktion this.accX += this.speedX * fricktion // equations of motion this.speedX += this.accX this.speedY += this.accY this.x += this.speedX + 0.5 * this.accX this.y += this.speedY + 0.5 * this.accY } }
碰撞检测代码实现
在你标注需要实现碰撞的位置添加如下判断逻辑即可:
plats.forEach((p) => { p.draw() // 碰撞检测逻辑 const playerBottom = player.y + player.radius const playerPrevBottom = player.prevY + player.radius const platformTop = p.y // 四个条件同时满足才判定为落在平台上 const isCollide = playerBottom >= platformTop // 玩家底部超过平台顶部 && playerPrevBottom < platformTop // 上一帧玩家底部还在平台上方,说明是下落过程碰到 && player.x >= p.x // 玩家X在平台左边界右侧 && player.x <= p.x + p.width // 玩家X在平台右边界左侧 if (isCollide) { // 把玩家位置修正到刚好底部贴平台顶部 player.y = platformTop - player.radius // 重置垂直速度,停止下落 player.speedY = 0 } })
动画循环简化
把动画循环里重复创建平台的逻辑删掉,最终animate函数调整为:
function animate() { animationId = requestAnimationFrame(animate) c.fillStyle = 'rgba(0, 0, 0, 0.1)' c.fillRect(0, 0, canvas.width, canvas.height) player.update() player.draw() plats.forEach((p) => { p.draw() // 上面写的碰撞检测逻辑放这里 }) }
运行修改后的代码,玩家下落就会自动停在平台上,满足你要的圆形底部刚好落在平台顶部的效果。
内容的提问来源于stack exchange,提问作者user15756255
相关产品推荐
相关产品推荐

