1. 程式人生 > >Cocos2d-x 3.0中 物理碰撞檢測中onContactBegin回調函數不響應問題

Cocos2d-x 3.0中 物理碰撞檢測中onContactBegin回調函數不響應問題

track 後來 which compare mar details egl def trac

好吧,事實上這篇也是暫時冒出來的,近期朋友要做個物理遊戲,曾經做物理還是用box2d,呃。確實要花些功夫才幹搞懂當中的精髓,可是聽講這套引擎又一次封裝了一次。要easy非常多,所以就簡單嘗試了一下,感覺確實要簡單不少,只是在這當中還是遇到了些問題,首先就來說說onContactBegin這個回調函數響應問題。


先說說情況。簡單做了一個打磚塊的遊戲。前面一切都非常順利,僅僅是做到碰撞檢測的時候,發現回調函數弄死都不調用。開始我以為函數寫錯了,後來查了api。testCpp都沒有錯,在3.0的api中。沒有關於PhysicsBody。PhysicsWorld這些類的說明。所以大家想查移步到3.2的api中吧。


onContactBegin函數的參數就一個,

bool onContactBegin(PhysicsContact& contact)。這和3.0beta版本號又有些不同,曾經是2個,所以在加入事件監聽的時候,不要寫錯,like this。

auto contactListener = EventListenerPhysicsContact::create();
contactListener->onContactBegin = CC_CALLBACK_1(HelloWorld::onContactBegin, this);
_eventDispatcher->addEventListenerWithSceneGraphPriority(contactListener, this);

回調函數是在當兩個物體有接觸的時候就會響應一次,裏面的參數從名字中也能看出來,Contact接觸,自然會涉及到兩個物體。


好了。以下該到重點了,為啥這個onContactBegin函數不響應呢?問題出在三個掩碼值上,這裏推薦一下看下這篇博文。

或者打開引擎的源碼,能夠在CCPhysicsShape這個頭文件中看下這段代碼,

/**
     * A mask that defines which categories this physics body belongs to.
     * Every physics body in a scene can be assigned to up to 32 different categories, each corresponding to a bit in the bit mask. You define the mask values used in your game. In conjunction with the collisionBitMask and contactTestBitMask properties, you define which physics bodies interact with each other and when your game is notified of these interactions.
     * The default value is 0xFFFFFFFF (all bits set).
     */
    inline void setCategoryBitmask(int bitmask) { _categoryBitmask = bitmask; }
    inline int getCategoryBitmask() const { return _categoryBitmask; }
    
/**
     * A mask that defines which categories of bodies cause intersection notifications with this physics body.
     * When two bodies share the same space, each body’s category mask is tested against the other body’s contact mask by performing a logical AND operation. If either comparison results in a non-zero value, an PhysicsContact object is created and passed to the physics world’s delegate. For best performance, only set bits in the contacts mask for interactions you are interested in.
     * The default value is 0x00000000 (all bits cleared).
     */
    inline void setContactTestBitmask(int bitmask) { _contactTestBitmask = bitmask; }
    inline int getContactTestBitmask() const { return _contactTestBitmask; }
   
 /**
     * A mask that defines which categories of physics bodies can collide with this physics body.
     * When two physics bodies contact each other, a collision may occur. This body’s collision mask is compared to the other body’s category mask by performing a logical AND operation. If the result is a non-zero value, then this body is affected by the collision. Each body independently chooses whether it wants to be affected by the other body. For example, you might use this to avoid collision calculations that would make negligible changes to a body’s velocity.
     * The default value is 0xFFFFFFFF (all bits set).
     */
    inline void setCollisionBitmask(int bitmask) { _collisionBitmask = bitmask; }
    inline int getCollisionBitmask() const { return _collisionBitmask; }

說白了。兩個物體間,能不能碰撞,能不能發送接觸事件信息,關鍵就看這個三個參數值。

總結來說:

一個body的CategoryBitmask和還有一個body的ContactTestBitmask的邏輯與的結果不等於0時,接觸事件將被發出,否則不發送。
一個body的CategoryBitmask和還有一個body的CollisionBitmask的邏輯與結果不等於0時,會碰撞,否則不碰撞。


這三個參數都有自己的默認值。採用16位表示,

CategoryBitmask, 默認值為 0xFFFFFFFF
ContactTestBitmask, 默認值為 0x00000000
CollisionBitmask, 默認值為 0xFFFFFFFF


大家能夠簡單的算一下,假設對這個計算不了解,能夠查查看哈,或者掏出你電腦上的計算器也能夠哇。

依照前面的總結來說,假設我們創建的body都採用默認值的話。那麽

CategoryBitmask & ContactTestBitmask = 0
CategoryBitmask & CollisionBitmask = -1


這樣看來,情況就清楚了,假設採用默認的數值。碰撞是能夠檢測的。可是碰撞事件是不會發出的,so我們的onContactBegin就被屏蔽了,那麽當然不會做事情。

所以假設想我們的兩個物體即發生碰撞又能夠檢測到。那麽非常easy,不讓它們&的值不等於0就ok了。所以能夠將兩個須要碰撞的物體的這個三個掩碼值都設置成1,

m_ball->getPhysicsBody()->setCategoryBitmask(0x01);  
m_ball->getPhysicsBody()->setContactTestBitmask(0x01); 
m_ball->getPhysicsBody()->setCollisionBitmask(0x01);
block->getPhysicsBody()->setCategoryBitmask(0x01);
block->getPhysicsBody()->setContactTestBitmask(0x01);
block->getPhysicsBody()->setCollisionBitmask(0x01);


這樣它們之間怎麽按位與的結果都是1。就能夠有對應了。

bool HelloWorld::onContactBegin(PhysicsContact& contact)
{
	auto sp1 = (Sprite*)contact.getShapeA()->getBody()->getNode();
	auto sp2 = (Sprite*)contact.getShapeB()->getBody()->getNode();

	if (sp1->getTag() == 1)
		sp1->removeFromParentAndCleanup(true);
	if (sp2->getTag() == 1)
		sp2->removeFromParentAndCleanup(true);

	return true;
}

前面說了接觸是肯定有兩個物體的,所以打磚塊的邏輯在這裏就是推斷下,當中一個的tag。假設是我們的磚塊。說明碰到了。那麽我們移除就ok了。

效果就是這樣了。


技術分享

Cocos2d-x 3.0中 物理碰撞檢測中onContactBegin回調函數不響應問題