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

如何正确使用Ammo.js的setUserPointer/getUserPointer获取碰撞物体名称

根因分析
  • 第一种setUserPointer方案失效原因:你使用的Web版本Bullet物理引擎(大概率是Ammo.js)的setUserPointer是C++接口的封装,仅支持接收WASM堆内存的数字指针,无法直接存储JS对象引用,所以你存的JS对象会被直接忽略,调用getUserPointer自然拿不到有效数据。
  • 第二种直接挂载自定义属性方案失效原因:getManifoldByIndexInternal返回的body0/body1是C++刚体对象的临时JS包装实例,每次调用接口获取碰撞体都会生成全新的JS对象,你之前在创建刚体时挂载的自定义属性仅存在于当时的JS实例上,和碰撞回调里拿到的实例不是同一个对象,因此读取不到。
可行解决方案

推荐使用「用户索引+全局映射表」的方案实现,不需要操作WASM内存,稳定性高:

  1. 首先创建全局映射表存储刚体对应的数据
// 全局存储:key为刚体的userIndex整数值,value为你需要存储的自定义数据
const bodyUserData = new Map<number, { name: string }>();
// 用于生成不重复的刚体id
let nextBodyId = 1;
  1. 创建刚体时存入映射关系
// 给刚体设置唯一的用户索引
this.body.setUserIndex(nextBodyId);
// 把自定义数据存入全局映射表
bodyUserData.set(nextBodyId, { name: name });
// 再把刚体加入物理世界
physicsWorld.addRigidBody(this.body);
nextBodyId++;
  1. 碰撞检测时从映射表读取数据
function detectCollison(): void
{
    const dispatcher = physicsWorld.getDispatcher();
    const numManifolds = dispatcher.getNumManifolds();

    for (let i = 0; i < numManifolds; i++)
    {
        const contactManifold = dispatcher.getManifoldByIndexInternal(i);
        const body0 = contactManifold.getBody0();
        const body1 = contactManifold.getBody1();

        // 读取刚体的用户索引,再从全局映射表拿数据
        const data0 = bodyUserData.get(body0.getUserIndex());
        const data1 = bodyUserData.get(body1.getUserIndex());

        console.log("first object: " + data0?.name);
        console.log("second object: " + data1?.name);
    }
}

如果有刚体销毁的需求,记得同步调用bodyUserData.delete(对应id)清理映射表,避免内存泄漏。

内容的提问来源于stack exchange,提问作者8Observer8

相关产品推荐
方舟 Agent Plan

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

最近更新时间:2026.10.05 18:57:02