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

如何在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

相关产品推荐
方舟 Agent Plan

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

最近更新时间:2026.10.07 22:18:04