一些背景:我正在为 Cocos2D/Box2D 编写一个 2D 可破坏地形库,它涉及 C++ 和 Objective-C 的混合体。我最近遇到了一个让我很困惑的情况,我想不出一个不涉及并行数组的解决方案。
为了在地形周围定义物理边界,必须对地形边界进行初始追踪。我进行了一个函数调用来跟踪纹理中所有孤立的像素体并缓存它们。这将创建以下数据结构
- 一个 NSMutableDictionary“borderPixels”,其键等于 CGPoint 包裹在 NSValue 中,NSValue 等于像素的唯一位置。这包含所有跟踪像素。
- 一个循环链表,其中 TerPixels 指向它们的下一个相邻像素
- 一个 NSMutableArray“traceBodyPoints”,它包含一个 TerPixel,表示地形主体的“起点”。我只在需要跟踪物理体的地方存储 TerPixel *。因此,如果地形体已被修改,我会将修改后的体中的任何单个 TerPixel * 插入到此数组中。然后我可以引用其中的每一个并遍历链表来追踪物理体。
下面是一些有助于更好地描绘情况的代码:
-(void)traverseBoundaryPoints:(CGPoint)startPt {
if (!borderPixels) borderPixels = [[NSMutableDictionary alloc] init]; // Temp
if (!traceBodyPoints) traceBodyPoints = [[NSMutableArray alloc] init]; // Temp
TerPixel * start = [[TerPixel alloc] initWithCoords:startPt.x ypt:startPt.y prevx:-1 prevy:0];
TerPixel * next = start;
//CCLOG(@"Start of traverseBoundary next.x and next.y %d, %d", next.x, next.y);
TerPixel * old;
while (true) {
old = next;
next = [self findNextBoundaryPixel:next];
[next setNSP:[old subTerPixel:next]];
old.nextBorderPixel = next;
if (next.x == start.x && next.y == start.y) {
CCLOG(@"SUCCESS :: start = next");
next.nextBorderPixel = start; // Make the linked list circular
NSValue * pixLocVal = [next getAsValueWithPoint];
[borderPixels setObject:next forKey:pixLocVal];
// Add the pixel to the tracePoints array to be traversed/traced later
[traceBodyPoints addObject:start];
break;
} // end if
// Connect the linked list components
NSValue * pixLocVal = [next getAsValueWithPoint];
[borderPixels setObject:next forKey:pixLocVal];
} // end while
} // end traverse function
这是我找不到解决方案的地方。我需要将 traceBodyPoints 数组中的每个 TerPixel * 与将创建并添加到物理世界的 Box2D b2Body 相关联。在我的库中,纹理中每个孤立的像素体对应于一个 Box2D 体。因此,当发生破坏大块地形的事件时,我需要破坏与被破坏像素相关联的物体并仅追溯改变的物体。这意味着我需要一种方法将任何给定的 TerPixel * 关联到 Box2D body *。
在带有 ARC 的 Objective-C 中,据我所知,如果没有桥接转换为 void *,我不能在 Objective-C 容器中包含 C++ 对象/指针。问题是这些操作需要具有令人难以置信的性能,而从事桥梁类型转换的成本非常高。另外,我不想在每个 TerPixel 中都包含指向 Box2D 主体的指针。这将是一场噩梦,以确保没有悬垂的指针,并且需要无意义的迭代到 nil 指针。
这是我创建物理边界的逻辑
-(void)createPhysicsBoundaries {
if ([self->traceBodyPoints count] == 0) {
CCLOG(@"createPhysicsBoundaries-> No bodies to trace");
return;
}
// NEED LOGIC HERE TO DELETE ALTERED BODIES
// NEED TO DELETE EXISTING BOX2D BODY AND RE-TRACE A NEW ONE
// For each body that has been altered, traverse linked list to trace the body
for (TerPixel * startPixel in self->traceBodyPoints) {
TerPixel * tracePixel = startPixel.nextBorderPixel;
b2BodyDef tDef;
tDef.position.Set(0, 0);
b2Body * b = self->world->CreateBody(&tDef);
self->groundBodies->push_back(b);
b->SetUserData((__bridge void*) self);
b2EdgeShape edgeShape;
CCLOG(@"StartPixel %d, %d", startPixel.x, startPixel.y);
while (tracePixel != startPixel) {
b2Vec2 start = b2Vec2(tracePixel.x/PTM_RATIO, tracePixel.y/PTM_RATIO);
//CCLOG(@"TracePixel BEFORE %d, %d", tracePixel.x, tracePixel.y);
tracePixel = tracePixel.nextBorderPixel;
//CCLOG(@"TracePixel AFTER %d, %d", tracePixel.x, tracePixel.y);
b2Vec2 end = b2Vec2(tracePixel.x/PTM_RATIO, tracePixel.y/PTM_RATIO);
edgeShape.Set(start,end);
b->CreateFixture(&edgeShape, 0);
} // end while
} // end for
} // end createPhysicsBoundaries
希望这是有道理的。如果您需要直观了解正在发生的事情,这里有一个视频。 http://www.youtube.com/watch?v=IUsgjYLr6e0&feature=youtu.be其中绿色边界是物理边界。
最佳答案
engaging in bridge casting is very costly
谁说的?它仍然只是一个 Actor ,基本上是免费的/可以忽略不计。桥接传输或保留转换会添加相应的引用计数方法调用,但您在这里不需要。
解决您的问题非常简单。您有包含 TerPixel
类实例的 traceBodyPoints
数组。
你只需要一个这个数组的包装类,我们称之为TerrainBlob
。 TerrainBlob 类包含您的 NSMutableArray traceBodyPoints
属性和 b2Body 的另一个属性:
@interface TerrainBlob : NSObject
@property NSMutableArray* traceBodyPoints;
@property b2Body* body;
@end
您可以改进 TerPixel 以包含对 TerrainBlob 的反向引用,该引用必须是弱的以避免保留循环。这样每个像素都可以访问 b2Body。您还可以在 TerrainBlob 中添加一个方法,该方法添加一个 TerPixel 并为方便起见正确设置 terrainBlob 属性。
@interface TerPixel : NSObject
...
@property (weak) TerrainBlob* terrainBlob;
@end
然后您可以从 TerPixel 中访问 b2Body:
b2Body* body = _terrainBlob.body;
if (body)
{
// do something with body
}
现在只需要更新一个位置的body,每个TerPixel在使用前都需要检查body是否为nil
。
最后,值得一提的是,基于像素的可破坏地形有点矫枉过正,尤其是在 Retina 设备上。除非您已经这样做了,否则请考虑创建跨越多个像素的近似线形,因为您实际上不需要像素完美的精度来进行物理模拟。
关于c++ - 使用 Objective-C 和 C++ 避免并行数组,我们在Stack Overflow上找到一个类似的问题: https://stackoverflow.com/questions/17599343/