だいたい47度

スポンサーサイト

上記の広告は1ヶ月以上更新のないブログに表示されています。
新しい記事を書く事で広告が消せます。

PageTop

Box2Dの衝突検知b2Contactとb2ContactListener(cocos2d)

Box2Dの物体同士の衝突感知のメモ。

簡易な実装はb2Contact
Box2Dで簡単な衝突感知はb2Contactを使って実装します。

b2ContactEdge* edge = targetBody->GetContactList();
while (edge){
b2Contact* contact = edge->contact;
if (contact->IsTouching()){......}//contactから衝突しているfixtureをGetして必要な処理を行う
edge = edge->next;
}

しかし、b2Contactでは、callの間に衝突したものは検知できません。あるcall後に衝突し、次のcall時には跳ね返って衝突が解除されてしまっていた場合、検知されないのです。それでも問題ないゲームであればb2Contactを使うのが良さそうです。

b2ContactListenerを使った実装
正確に衝突を感知する必要がある場合などは、contact listenerを上書きして使います。

基本的にはこちらを参考にして実装しました。

簡単に中身を説明すると、衝突した物体の組み合わせ全てを構造体MyContactのベクタで管理し、ゲームからはベクタの中身をチェックすることで衝突を感知しています。衝突時(BeginContact)にMyContactを作成しベクタに登録、衝突終了時(EndContact)にベクタから削除というようにしているわけです。

しかし、実際使ってみると、たびたび衝突感知が効いていないようでした。再現条件がわからないのですが、ゲームをしていると数十回に一回くらいの頻度で起こっています。

ちょっと調べてみた結果、ゲームからベクタの中身を走査する前にEndContactされているようでした。考えてみればそうか、b2Contactを使ったのと同じになっているじゃん。

ので、ベクタの中身を消す処理を作って、ゲーム側が走査後にその処理を呼ぶことで対応しました。

//MyContactListener.mm
void MyContactListener::BeginContact(b2Contact* contact) {
MyContact myContact = { contact->GetFixtureA(), contact->GetFixtureB() };
_contacts.push_back(myContact);
}

void MyContactListener::ClearContactsData(){
_contacts.clear();
}

void MyContactListener::EndContact(b2Contact* contact) {
}

//GameLayer.mm
- (void)update:(ccTime)dt{
for(pos = listener->_contacts.begin(); pos != listener->_contacts.end(); ++pos)
{......}//チェック処理

listener->ClearContactsData();
}

うん、これでOK。

Learning Cocos2D: A Hands-On Guide to Building iOS Games with Cocos2D, Box2D, and ChipmunkLearning Cocos2D: A Hands-On Guide to Building iOS Games with Cocos2D, Box2D, and Chipmunk
(2011/07/07)
Rod Wenderlich, Ray Strougo

商品詳細を見る
関連記事
スポンサーサイト

PageTop

コメント


管理者にだけ表示を許可する
 

上記広告は1ヶ月以上更新のないブログに表示されています。新しい記事を書くことで広告を消せます。