cocos2d之Box2D詳解 刪除物理世界對象
DionysosLai 2014-5-8
物理世界對象,有創造,就有銷燬。
通常,我們在更新函數中會這樣寫到:
void HelloWorld::update(float dt)
{
/// 第一件事情就是調用world對象的step方法,這樣它就可以進行物理仿真了。
/// 這裏的兩個參數分別是“速度迭代次數”和“位置迭代次數”--你應該設置他們的範圍在8-10之間。(譯者:這裏的數字越小,
/// 精度越小,但是效率更高。數字越大,仿真越精確,但同時耗時更多。8一般是個折中,如果學過數值分析,應該知道迭代步數的具體作用)。
world->Step(dt, 10, 10);
/// 使我們的精靈匹配物理仿真。
for (b2Body *b = world->GetBodyList(); b; b = b->GetNext())
{
/// 遍歷world對象裏面的所有body,然後看body的user data屬性是否爲空,如果不爲空,就可以強制轉換成精靈對象。接下來,就可以根據body的位置來更新精靈的位置了。
if (b->GetUserData() != NULL)
{
CCSprite* ballData = (CCSprite*)b->GetUserData();
ballData->setPosition(ccp(b->GetPosition().x*PTM_RATIO,
b->GetPosition().y*PTM_RATIO));
/// 弧度值轉化爲角度值 cocos2d裏面使用的是角度值,而box2d裏面使用的是弧度值。單位不統一,所以需要轉化。爲什麼前面*-1呢?
/// 因爲cocos2d的角度是順時針,而box2d是逆時針。
ballData->setRotation(-1*CC_RADIANS_TO_DEGREES(b->GetAngle()));
}
}
}
在這裏,我們做幾件事,一是:遍歷物理世界中的對象;將物理世界對象數據,轉換成我們的數據對象,然後更新對象的位置和旋轉度。
如果我們要銷燬其中的某個物理世界對象。通常我們會賦予我們的對象一個屬性,然後根據這個屬性來判斷是否要銷燬該對象。
如下面代碼所示:
m_world->Step(delta, 10, 10);
/// 使我們的精靈匹配物理仿真。
for (b2Body *b = m_world->GetBodyList(); b; ->GetNext())
{
if (b->GetUserData() != NULL)
{
boxSprite* ballData = (boxSprite*) b ->GetUserData();
if (ballData->getDead())
{
m_world->DestroyBody(b);
}
else
{
ballData->setPosition(ccp(b ->GetPosition().x*PTM_RATIO,
b ->GetPosition().y*PTM_RATIO));
ballData->setRotation(-1*CC_RADIANS_TO_DEGREES(b ->GetAngle()));
}
}
}
Ps:ballData->getDead(),這裏的getDead函數,就是我們對對象賦予的一個屬性,來說判斷我們是否要銷燬對象。
這段代碼有個很嚴重的問題,就是當我們銷燬對象時,這個對象的所有信息都將被消除,那麼我們將會去不到去下一個節點信息,正確的做法就是要提前獲取下一個節點,同時b->GetUserData() == NULL 情況下,我們也要獲取下一個節點,修改代碼如下:
m_world->Step(delta, 10, 10);
/// 使我們的精靈匹配物理仿真。
for (b2Body *b = m_world->GetBodyList(); b; )
{
if (b->GetUserData() != NULL)
{
b2Body* b2node = b;
b = b2node->GetNext();
boxSprite* ballData = (boxSprite*)b2node->GetUserData();
if (ballData->getDead())
{
m_world->DestroyBody(b2node);
}
else
{
ballData->setPosition(ccp(b2node->GetPosition().x*PTM_RATIO,
b2node->GetPosition().y*PTM_RATIO));
ballData->setRotation(-1*CC_RADIANS_TO_DEGREES(b2node->GetAngle()));
}
}
else
{
b = b->GetNext();
}
}
當然這是一個方法,如果不考慮效率的話,我們通過不修正我們對象的位置信息,我們也可以看起來,就像是將對象銷燬掉,即在刪除這段代碼即可:
ballData->setPosition(ccp(b2node->GetPosition().x*PTM_RATIO,b2node->GetPosition().y*PTM_RATIO));
ballData->setRotation(-1*CC_RADIANS_TO_DEGREES(b2node->GetAngle()));
這是刪除對象一個方法,還有一個方法就是,我們可以將要刪除對象保存在一個臨時容器中,等物體鏈表遍歷完成之後,就可以刪除臨時容器中的物體了。