在Box2D中碰撞事件經過實現b2ContactListener類函數實現,b2ContactListener是Box2D提供的抽象類,它的抽象函數:
virtual void BeginContact(b2Contact* contact)。兩個物體開始接觸時會響應,但只調用一次。
virtual void EndContact(b2Contact* contact)。分離時響應。但只調用一次。
virtual void PreSolve(b2Contact* contact, const b2Manifold* oldManifold)。持續接觸時響應,它會被屢次調用。
virtual void PostSolve(b2Contact* contact, const b2ContactImpulse* impulse)。持續接觸時響應,調用完preSolve後調用。
下面經過將12.2.3一節的實例採用Box2D技術重構,瞭解一下Box2d物理引擎中如何檢測碰撞。
首先咱們須要在工程中添加一個新類。使用Visual Studio 2012中添加一個新類,須要分別添加C++源文件和頭文件。具體操做,如圖所示,右鍵點擊工程HelloBox2D下的Classes文件夾,在右鍵菜單中選擇,「添加」→ 「新項目」。彈出如後面的圖所示添加新項對話框,咱們在對話框中選擇文件的種類,在「名稱」中輸入文件名ContactListener,而後點擊「添加」按鈕添加文件。
html
Visual Studio 2012中添加新類安全
添加新項對話框微信
添加完成新類ContactListener,咱們還須要修改它的代碼,ContactListener.h文件代碼以下:
函數
[html] view plaincopy網站
#include "cocos2d.h" spa
#include "Box2D/Box2D.h" .net
USING_NS_CC; orm
class ContactListener : public b2ContactListener 視頻
{ htm
private:
//兩個物體開始接觸時會響應
virtual void BeginContact(b2Contact* contact);
//持續接觸時響應
virtual void PreSolve(b2Contact* contact, const b2Manifold* oldManifold);
//持續接觸時響應,調用完preSolve後調用
virtual void PostSolve(b2Contact* contact, const b2ContactImpulse* impulse);
//分離時響應
virtual void EndContact(b2Contact* contact);
};
在頭文件中須要引入cocos2d.h和Box2D/Box2D.h頭文件,不然會有編譯錯誤。ContactListener採用共有繼承b2ContactListener。
ContactListener.cpp文件代碼以下:
#include "ContactListener.h"
void ContactListener::BeginContact(b2Contact* contact) ①
{
log("BeginContact");
b2Body* bodyA = contact->GetFixtureA()->GetBody(); ②
b2Body* bodyB = contact->GetFixtureB()->GetBody(); ③
auto spriteA = (Sprite*)bodyA->GetUserData(); ④
auto spriteB = (Sprite*)bodyB->GetUserData(); ⑤
if (spriteA != nullptr && spriteB != nullptr) ⑥
{
spriteA->setColor(Color3B::YELLOW);
spriteB->setColor(Color3B::YELLOW);
}
}
void ContactListener::EndContact(b2Contact* contact) ⑦
{
log("EndContact");
b2Body* bodyA = contact->GetFixtureA()->GetBody();
b2Body* bodyB = contact->GetFixtureB()->GetBody();
auto spriteA = (Sprite*)bodyA->GetUserData();
auto spriteB = (Sprite*)bodyB->GetUserData();
if (spriteA != nullptr && spriteB != nullptr)
{
spriteA->setColor(Color3B::WHITE);
spriteB->setColor(Color3B::WHITE);
}
}
void ContactListener::PreSolve(b2Contact* contact, const b2Manifold* oldManifold) ⑧
{
log("PreSolve");
}
void ContactListener::PostSolve(b2Contact* contact, const b2ContactImpulse* impulse) ⑨
{
log("PostSolve");
}
上述代碼第①行是實現碰撞事件BeginContact函數,第②代碼和第③行代碼是得到接觸雙方物體對象。第④代碼和第⑤行代碼是從物體對象的UserData屬性中肯定精靈對象,UserData屬性能夠放置任何對象,這裏咱們可以經過bodyA->GetUserData()語句取得精靈,那是由於在定義物體的時候經過body->SetUserData(sprite)語句,將精靈放入到物體的UserData屬性。第⑥行代碼是判斷兩個精靈是否存在。
代碼第⑦行是實現碰撞事件EndContact函數,函數的實現與BeginContact函數相似。第⑧和第⑨行代碼是實現碰撞事件PreSolve和PostSolve函數,這兩個函數一般用的很少。
咱們還須要在要監聽事件的層中,添加相關碰撞檢測代碼。在HelloWorld.h的代碼以下:
[html] view plaincopy
#ifndef __HELLOWORLD_SCENE_H__
#define __HELLOWORLD_SCENE_H__
#include "cocos2d.h"
#include "Box2D/Box2D.h"
#include "ContactListener.h" ①
#define PTM_RATIO 32
class HelloWorld : public cocos2d::Layer
{
b2World* world;
ContactListener* contactListener; ②
public:
~HelloWorld();
static cocos2d::Scene* createScene();
virtual bool init();
virtual void update(float dt);
virtual bool onTouchBegan(cocos2d::Touch* touch, cocos2d::Event* event);
CREATE_FUNC(HelloWorld);
void initPhysics();
void addNewSpriteAtPosition(cocos2d::Vec2 p);
};
#endif // __HELLOWORLD_SCENE_H__
上述代碼第①行是引入頭文件ContactListener.h。第②行代碼是聲明ContactListener類型的成員變量contactListener。
咱們還須要修改HelloWorld.cpp中的HelloWorld::initPhysics()代碼以下:
[html] view plaincopy
void HelloWorld::initPhysics()
{
… …
contactListener = new ContactListener();
world->SetContactListener(contactListener);
… …
}
函數中的contactListener = new ContactListener()語句是建立ContactListener對象,採用了new關鍵字分配內存,建立成員變量contactListener,須要本身釋放contactListener對象。這些釋放過程是在析構函數中進行,它的析構函數代碼以下:
HelloWorld::~HelloWorld()
{
CC_SAFE_DELETE(world);
CC_SAFE_DELETE(contactListener);
}
使用CC_SAFE_DELETE(contactListener)安全釋放contactListener成員變量的內存。
更多內容請關注國內第一本Cocos2d-x 3.2版本圖書《Cocos2d-x實戰:C++卷》
本書交流討論網站:http://www.cocoagame.net
更多精彩視頻課程請關注智捷課堂Cocos課程:http://v.51work6.com
歡迎加入Cocos2d-x技術討論羣:257760386
歡迎關注智捷iOS課堂微信公共平臺