一些背景:我正在为 Cocos2D/Box2D 编写一个 2D 可破坏地形库,其中涉及 C++ 和 Objective-C 的混合。我最近遇到了一个困扰我的情况,我想不出不涉及并行数组的解决方案。
为了在地形周围定义物理边界,必须对地形边界进行初始跟踪。我进行了一个函数调用来跟踪纹理中所有孤立的像素体并缓存它们。这将创建以下数据结构
- 一个 NSMutableDictionary “borderPixels”,其键等于包裹在 NSValue 中的 CGPoint,该 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 主体 * 的方法。
据我所知,在带有 ARC 的 Objective-C 中,如果没有桥接转换为 void *,我不能在 Objective-C 容器中包含 C++ 对象/指针。问题是这些操作需要具有令人难以置信的性能,并且进行桥梁铸造的成本非常高。另外,我不想在每个 TerPixel 中都包含一个指向 Box2D 主体的指针。这将是一场噩梦,以确保没有悬空指针并且需要无意义的迭代来消除指针。
这是我创建物理边界的逻辑
-(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其中绿色边界是物理边界。