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

Vanilla JS伪物理引擎圆与凹边线段碰撞重叠问题求解

问题成因
  • 碰撞处理与速度应用顺序颠倒:当前逻辑是先做碰撞修正、再叠加移动速度,叠加速度后的新位置未经过碰撞校验,直接进入下一帧渲染,天然就会出现穿模问题。
  • 多碰撞串行处理逻辑缺陷:两条边的碰撞修正串行执行,修正第一条边碰撞后的位置,在修正第二条边碰撞时会被覆盖,很容易出现修正后再次穿透第一条边的情况,凹角场景下这个问题会被放大。
  • 碰撞检测存在硬编码bug:collide方法中判断碰撞阈值时使用了全局circle.radius,而非当前实例的this.radius,属于潜在稳定性问题。
修复方案

按照以下步骤修改代码,即可解决凹角重叠问题:

  1. 调整move方法的执行顺序,先叠加速度,再执行碰撞检测与修正
  2. 新增迭代碰撞修正逻辑,多次校验修正后的位置,避免多碰撞相互抵消的问题
  3. 修复碰撞检测里的硬编码问题

修改后的核心代码示例

先修正collide方法的硬编码:

collide(object) {
    let dx31 = this.center.x - object.start.x
    let dx21 = object.end.x - object.start.x

    let dy31 = this.center.y - object.start.y
    let dy21 = object.end.y - object.start.y

    let d = ((dx21 * dx21) + (dy21 * dy21))

    if (d != 0) d = ((dx31 * dx21) + (dy31 * dy21)) / d
    if (d < 0.0) d = 0
    if (d > 1.0) d = 1

    let dx = this.center.x - (object.start.x + (dx21 * d))
    let dy = this.center.y - (object.start.y + (dy21 * d))

    let magnitude = Math.sqrt((dx * dx) + (dy * dy))

    // 把原来的circle.radius改成this.radius
    if (this.radius >= magnitude) {
        return {
            collided: true,
            intersection: {
                x: this.center.x - dx,
                y: this.center.y - dy
            }

        }
    } else return {
        collided: false
    }
}

再替换Circle类的move方法:

move() {
    // 先应用移动速度
    this.center.x += this.velocity.x
    this.center.y += this.velocity.y

    // 迭代3次处理多碰撞,简单场景下足够覆盖所有冲突
    for (let iter = 0; iter < 3; iter++) {
        let hasCollision = false

        // 处理第一条线碰撞
        let collision = this.collide(line)
        if (collision.collided) {
            hasCollision = true
            // 计算修正方向
            const fixVec = new Vector(
                this.center.x - collision.intersection.x,
                this.center.y - collision.intersection.y
            )
            fixVec.normalize()
            // 计算重叠深度,直接修正位置
            const overlap = this.radius - Math.hypot(this.center.x - collision.intersection.x, this.center.y - collision.intersection.y)
            this.center.x += fixVec.x * overlap
            this.center.y += fixVec.y * overlap
        }

        // 处理第二条线碰撞
        collision = this.collide(line2)
        if (collision.collided) {
            hasCollision = true
            const fixVec = new Vector(
                this.center.x - collision.intersection.x,
                this.center.y - collision.intersection.y
            )
            fixVec.normalize()
            const overlap = this.radius - Math.hypot(this.center.x - collision.intersection.x, this.center.y - collision.intersection.y)
            this.center.x += fixVec.x * overlap
            this.center.y += fixVec.y * overlap
        }

        // 本轮没有碰撞,提前退出迭代
        if (!hasCollision) break
    }
}

修改完成后按住D键进入凹角位置,不会再出现同时穿透两条边的问题。

内容的提问来源于stack exchange,提问作者0blivio

相关产品推荐
方舟 Agent Plan

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

最近更新时间:2026.10.05 05:54:02