0

いくつかのコンテキスト: C++ と Objective-C のハイブリッドを含む Cocos2D/Box2D 用の 2D Destructible 地形ライブラリを作成しています。私は最近、並列配列を含まない解決策が思いつかない状況に遭遇しました。

地形の周囲に物理境界を定義するには、地形の境界から最初のトレースを作成する必要があります。関数呼び出しを行って、テクスチャ内の分離されたすべてのピクセル ボディをトレースし、それらをキャッシュします。これにより、次のデータ構造が作成されます

  • ピクセルの一意の位置に等しい NSValue にラップされた CGPoint に等しいキーを持つ NSMutableDictionary "borderPixels"。これは、トレースされたすべてのピクセルを保持します。
  • TerPixels が次の隣接ピクセルを指す循環リンク リスト
  • 地形本体の「開始」点を表す単一の TerPixel を保持する NSMutableArray "traceBodyPoints"。ここには、物理​​体をトレースする必要がある 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緑の境界は物理境界です。

4

1 に答える 1