2013-07-11 52 views
0

某些上下文:我正在爲Cocos2D/Box2D編寫一個2D可破壞地形庫,它涉及C++和Objective-C的混合。我最近遇到了一個讓我難以想象不涉及平行陣列的解決方案的局面。使用Objective-C和C++避免平行數組

爲了在地形周圍定義物理邊界,必須首先對地形邊界進行跟蹤。我做了一個函數調用來跟蹤紋理中所有孤立像素體並緩存它們。這產生與密鑰等於包裹在一個NSValue一個CGPoint其是等於像素的獨特位置處的以下數據結構

  • 一個NSMutableDictionary「borderPixels」。這包含所有跟蹤的像素。
  • 一個圓形鏈表與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++容器中包含C++對象/指針而無需將橋接器強制轉換爲void *。問題是這些操作需要令人難以置信的高性能,參與橋樑鑄造的成本非常高。另外,我不想在每個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綠色邊界是物理邊界。

+0

你有沒有考慮過Chipmunk Indie/Pro?它有一個稱爲內置可破壞地形的自動幾何特徵。 http://www.youtube.com/watch?v=oacZwUGP11c – LearnCocos2D

+0

不,我從來沒有聽說過它。我一直想要一個Box2D可破壞地形解決方案。我大約有95%完成了解決方案...所以我想我可以完成它。我正在建造的圖書館允許用戶通過一次呼叫和經理多體碰撞來對待地形的破壞和物理重新定義。回想起來,我應該更多地環顧四周。順便說一句,讀你的書。很棒的閱讀! –

回答

2

從事橋樑鑄造是非常昂貴的

說的是誰?它仍然只是一個演員,基本上是免費/可以忽略的。橋接轉移或保留轉換會添加相應的引用計數方法調用,但在此您不需要。

解決您的問題非常簡單。你有traceBodyPoints數組包含TerPixel類的實例。

你只需要這個數組的包裝類,我們稱之爲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 
} 

現在你只需要在一個位置更新的身體,每個TerPixel需要檢查身體是否nil使用它之前。

最後,值得一提的是,以像素爲基礎的可破壞地形是矯枉過正的,特別是在視網膜設備上。除非您已經這麼做,否則請考慮創建跨多個像素的近似線形,因爲您並不需要像素完美的物理模擬精度。

+1

感謝您的回覆。我確實通過對頂點進行平均並調整曲率來平滑頂點。我只是沒有在這裏傳達這些信息,因爲我認爲這不相關。所以600個頂點的數組最終取決於對象如何變形。下班後我會更加關注這個解決方案。 –

+0

謝謝Steffen。這工作得很好。 –

+0

很酷。如果您向公衆發佈此產品,請告訴我,商業還是免費。 – LearnCocos2D