问题描述
如何将“用户数据”(即我的应用程序的任意数据)与PlayRho 0.10.0物理引擎中的主体相关联?
在Box2D 2.4.1物理引擎中,我可以使用userData
实例的b2BodyDef
字段将“用户数据”与主体相关联,并将其传递给{{1 }}函数并通过调用b2World::CreateBody
来取回值。您如何在PlayRho中做到这一点?
解决方法
可能的解决方案:
在您的应用程序中,可以使用一个数组,该数组的元素是您的用户数据值,并且其索引与在PlayRho中创建主体所返回的基础值相匹配。
例如,对于任何b2Body::GetUserData()
兼容的用户数据,简单/幼稚的实现可能是:
void*
但是,如果您想避免处理诸如内存泄漏之类的头痛问题,可以将int main() {
struct MyEntity {
int totalHealth;
int currentHealth;
int strength;
int intellect;
};
std::vector<void*> myUserData;
auto world = World{};
// If you want to pre-allocate 100 spaces...
myUserData.resize(100);
const auto body = world.CreateBody();
// If your # bodies is unlimited or you don't want to preallocate space...
if (body.get() >= myUserData.size()) myUserData.resize(body.get());
// Set your user data...
myUserData[body.get()] = new MyEntity();
// Gets your user data...
const auto myEntity = static_cast<MyEntity*>(myUserData[body.get()]);
// Frees your dynamically allocated MyEntity instances.
// Even with Box2D `userData` you may want to free these.
for (const auto& element: myUserDAta) {
delete element;
}
return 0;
}
设为myUserData
,并避免使用std::vector<MyEntity> myUserData;
和new MyEntity()
调用。 / p>
一些优点:
- 提供更大的灵活性。用户数据通常是特定于应用程序的。由于在使用PlayRho时可以自己实现此存储,因此您可以更轻松地将元素设置为所需的任何类型,而不必使物理引擎的所有使用都具有相同的用户数据类型。例如,您的用户数据类型可能是特定于世界的,而在Box2D中,您对其
delete element;
字段的所有使用都具有相同的类型。 - 避免浪费内存。并非所有应用程序都需要用户数据,因此那些不会浪费内存或让您修改库代码来避免浪费数据的人。
缺点:
- 这与Box2D有所不同。
- 如果您不希望拥有额外的灵活性,这可能需要您付出更多的编码工作(因为额外的灵活性也可以节省一些编码工作)。
背景/说明:
尽管PlayRho物理引擎是Box2D物理引擎的分支,但PlayRho却从参考语义(指针)转向了值语义(值) 。因此,替换了指针,并彻底删除了“用户数据”,而采用了这种可能的解决方案。此外,随着这种向价值语义的转变,创建主体的概念从从世界返回指向新主体的指针转变为基本上从世界返回指向新主体的整数索引。该索引充当世界中新实体的标识符,并且基本上是从世界开始的递增计数器,从0开始,每次创建新实体时都会递增。这意味着您可以使用基础主体ID值作为存储用户数据的元素的索引从数组中进行O(1)查找。使用userData
还可以提供O(1)查找,但是散列映射在现代硬件上的缓存友好性要比数组低,因此在Box2D中通过为每个主体预留用户数据值来避免此类开销更有意义比起PlayRho。