发现可能的危险Box2D BUG

发现在一些特定的情况下,如果让有刚体的节点的active为false, 就会出现如下错误

box2d.umd.js:2778 Uncaught Error at b2TreeNode.get (:7456/scripting/engine/bin/.cache/dev/preview/external/%2540cocos/box2d.js:521)

发现出现在如下代码中获取userData为null时抛出一个异常

while (i < this.m_pairCount) {

  const primaryPair: b2Pair<T> = this.m_pairBuffer[i];

  const userDataA: T = primaryPair.proxyA.userData; // this.m_tree.GetUserData(primaryPair.proxyA);

  const userDataB: T = primaryPair.proxyB.userData; // this.m_tree.GetUserData(primaryPair.proxyB);

  callback(userDataA, userDataB);

  ++i;

  // Skip any duplicate pairs.

  while (i < this.m_pairCount) {

    const pair: b2Pair<T> = this.m_pairBuffer[i];

    if (pair.proxyA.m_id !== primaryPair.proxyA.m_id || pair.proxyB.m_id !== primaryPair.proxyB.m_id) {

      break;

    }

    ++i;

  }

}

排查了很久,发现box2d.ts中的如下代码可能有问题:

public BufferMove(proxy: b2TreeNode<T>): void {
    this.m_moveBuffer[this.m_moveCount] = proxy;
    ++this.m_moveCount;
  }

此处m_moveBuffer中可能已经存在了proxy, 导致后续的UnBufferMove不能完全从列表中移除proxy。
此BUG隐藏较深,危害较大,导致box2d在cocos的使用中,只要稍微复杂的带刚体节点的active=false的操作逻辑,就会出问题。
可以这样修改:

public BufferMove(proxy: b2TreeNode<T>): void {
    var index = this.m_moveBuffer.indexOf(proxy);
    if (index >= 0 && index < this.m_moveCount) return;
    this.m_moveBuffer[this.m_moveCount] = proxy;
    ++this.m_moveCount;
  }
2赞

经常出现如下错误

box2d.umd.js:3471 Uncaught Error
    at b2TreeNode.get (:7456/scripting/engine/bin/.cache/dev/preview/external/%2540cocos/box2d.js:702)
    at b2BroadPhase.UpdatePairs (:7456/scripting/engine/bin/.cache/dev/preview/external/%2540cocos/box2d.js:1042)
    at b2ContactManager.FindNewContacts (:7456/scripting/engine/bin/.cache/dev/preview/external/%2540cocos/box2d.js:3793)
    at b2World.Step (:7456/scripting/engine/bin/.cache/dev/preview/external/%2540cocos/box2d.js:6727)
    at b2PhysicsWorld.step (index.js:155744)
    at PhysicsSystem2D.postUpdate (index.js:158497)
    at Director.tick (index.js:8084)
    at callback (index.js:8658)

感谢反馈~

目测3.3.2好像未修复此问题。我想知道定制引擎的话,我如何手动修改box2d.ts后,然后编译到自定义引擎?
还有,上面的this.m_moveBuffer.indexOf(proxy)修正并不效率,有搜索开销。

能发下有问题的工程吗?

稍等,我要让问题重现。

active出问题最主要是因为你更新刚体的时机不正确。
我出现过好几次此类问题,但基本都是更新时间不对产生的。
1,不能在world锁定(正在step)时更新刚体
2,不能在box2d的任一callback(如beginContact)中执行此类操作
建议用node.scheduleOnce(… active = false)如果问题还能重现再反馈一下。
我目前active遇到的问题都自己通过这种方式解决了。

我很确定没有在box2d的碰撞回调中调用,也没有在steping中调用。可能是我的使用情况稍微复杂一点。

1赞

不过确实感觉引擎需要给出明确一点的错误提示,如果没有box2d比较深入的使用经验很容易就被这个错误给劝退了。

上传中:MiniEscape.zip…
重现问题的代码已经提供,直接新建游戏就到有问题的关卡,里面有个操作视频。项目逻辑有点复杂,不知道有没有什么帮助。
未修改的原始代码在 https://github.com/biliskener/MiniEscape

我的猜测是,节点在active和deactive的复杂逻辑时,相关节点在重叠区的时候会出类似问题。当然只是猜测。
我将box2d.ts进行上面的改动后,就没有类似问题了。所有关卡都没有任何问题。

1赞

超过4M, 怎么办?

https://pan.baidu.com/s/1G82LadnP0pVMxEzTM7lVZw
vkg6

我这里也提供一个必现的例子:
创建一个带有box2d物理component的节点(名字为box)放在场景并默认在编辑器中把active去掉勾。(隐藏)

运行时,任意时间,把这个box node添加到其它节点,比如carrierNode.addChild(box);
然后执行box.active = true,就会报错。

改为box.getComponent(RigidBody2D).scheduleOnce( box.active = true )就不会报错。

我有一个关卡这样改可以 但另一个就不行了