使用Objective-C和C++避免并行数组
Avoiding parallel arrays with Objective-C and C++
一些上下文:我正在为Cocos2D/Box2D编写一个2D可破坏地形库,它涉及C++和Objective-C的混合。我最近遇到了一个困扰我的情况,我想不出一个不涉及并行数组的解决方案。
为了在地形周围定义物理边界,必须对地形边界进行初始跟踪。我调用了一个函数来跟踪纹理中所有孤立的像素体并缓存它们。这创建了以下数据结构
- 一个NSMutableDictionary"borderPixels",其键等于一个CGPoint,该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实体*相关联。
据我所知,在带有ARC的Objective-C中,如果不将C++对象/指针桥接到void*,我就无法将其包含在Objective-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,其中绿色边界是物理边界。
从事桥梁铸造是非常昂贵的
谁说的?它仍然只是一个演员阵容,基本上是免费的/可以忽略不计的。桥接转移或保留强制转换会添加相应的引用计数方法调用,但这里不需要。
解决你的问题真的很简单。您有一个包含TerPixel
类实例的traceBodyPoints
数组。
您只需要为这个数组提供一个包装器类,我们称之为TerrainBlob
。TerrainBlob类包含您的NSMutableArray traceBodyPoints
属性和b2Body:的另一个属性
@interface TerrainBlob : NSObject
@property NSMutableArray* traceBodyPoints;
@property b2Body* body;
@end
您可以改进TerPixel以包含对TerrainBlob的反向引用,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
}
现在您只需要在一个位置更新主体,每个TerPixel在使用之前都需要检查主体是否为nil
。
最后,值得一提的是,基于像素的可破坏地形过于致命,尤其是在Retina设备上。除非你已经在做了,否则考虑创建跨越多个像素的近似线形,因为物理模拟并不需要像素的完美精度。
- 遍历并行数组以确定C++中的最大数字
- 排序并行数组
- 如何从具有两列的.txt文件创建并行数组?
- C++赋值简介:并行数组
- 循环函数中的并行数组
- 对于循环和并行数组:未声明的标识符
- 如何使用并行数组使用 c++ 制作包含数量和单词的列表
- 对一个具有重复元素的数组进行排序时更新并行数组
- 将2D数组行存储在并行数组中
- 将并行数组与 txt 文件分开
- 选择在++中对并行数组排序
- 在并行数组上编写随机访问迭代器
- 如何将预类型化文件转换为并行数组并在 c++ 中找到最大的数字
- 从最高到最低对字符串数组和双数组进行排序(并行数组)并对齐文本
- 在检查现有元素时,从文件填充并行数组时出现问题
- 使用Objective-C和C++避免并行数组
- 如何对两个并行数组排序
- 从并行数组返回值,并在以后的函数中使用这些值
- 并行数组如何将int转换为字符串
- 将文本文件一行一行地读入并行数组