cocos2d 作爲遊戲引擎,提供了基本的模擬現實物理世界中的一些屬性,比如物體有摩擦力,重力,加速度,角速度等等
這裏簡單介紹一下cocos2dx 物理世界裏面的碰撞檢測
啓用physicsWorld
Scene* HelloWorld::createScene()
{
// 'scene' is an autorelease object
//auto scene = Scene::create();
// 創建帶物理特性的場景
auto scene = Scene::createWithPhysics();
scene->getPhysicsWorld()->setGravity(Vec2(0, 0));// 設置重力,是x,y 方向合成的,比如 x=0,y=-980,則是豎直向下的
//scene->getPhysicsWorld()->setAutoStep(false);//這個是爲了避免物體間接觸,不定時的發生跳動的情況,但是有些電腦上不加也不會出現問題
//scene->getPhysicsWorld()->setDebugDrawMask(PhysicsWorld::DEBUGDRAW_ALL);// 這個是爲了方便開發時調試,將所有body的邊框顯示出來
// 'layer' is an autorelease object
auto layer = HelloWorld::create();
// add layer as a child to scene
scene->addChild(layer);
// return the scene
return scene;
}
如何給基本的sprite 加上物理屬性
通過.setPhysicsBody() 方法給sprite 增加一個body,所有的物理屬性都體現在這個body裏面
示例代碼:
以下代碼演示了給bigPlane 對象設置上密度爲1,彈力系數爲0,摩擦係數爲0的物理屬性
#define PHYSICS_MATERIAL2 PhysicsMaterial(1,0,0)// 這裏是定義了全局的物理材質對象,三個參數依次代表 密度,彈力系數,摩擦係數
auto bigPlane = rootNode->getChildByName("bigEnemy");
auto bigBody = PhysicsBody::createBox(bigPlane->getContentSize(), PHYSICS_MATERIAL2);
bigPlane->setPhysicsBody(bigBody);
body 的類型: 一般使用 Box就夠了,因爲這個形狀在關閉
setDebugDrawMask(PhysicsWorld::DEBUGDRAW_ALL) 之後是肉眼看不見的
PhysicsShape:物理形狀的基類
PhysicsShapeCircle:實心的圓形,無法用它實現一個空心圓
PhysicsShapePolygon:實心且外凸的多邊形
PhysicsShapeBox:矩形,它是一種特殊的外凸多邊形
PhysicsShapeEdgeSegment:表示一種線段.
PhysicsShapeEdgePolygon:空心多邊形,由多個線段構成的多邊形邊緣。
PhysicsShapeEdgeBox:空心矩形,由四個線段組成的矩形邊緣
PhysicsShapeEdgeChain: 鍊形,它可以有效的把許多邊緣連接起來
physicsBody 的常用方法:
- [1] .setDynamic(bool) :設置body是否可以移動,如果是false,就是固定在某一個位置
- [2 ] .setContactTestBitMask(int):設置接觸掩碼 // 默認值爲 0
- [3 ] .setCollisonBitMask(int); 設置碰撞掩碼// 默認值爲 0xffffffff,
- [4 ] .setCategoryBitMask(int):設置分類掩碼,定義該body所屬分類// 默認值同上
是否允許穿透
**場景:**物體A與物體B 相撞,如果想讓A能夠穿過B
則需要滿足條件:
bodyA 的 的CollisonBitMask 與bodyB的CategoryBitMask 按位與結果爲0,則表示A可以穿過B
否則不能穿過
示例代碼:
// 允許小敵機穿過大敵機
smallBody->setCollisionBitmask(1);// 二進制也就是 001
bigBody->setCategoryBitmask(2);// 二進制也就是 010 ,位與結果爲0,表示可以穿過
注意: 這不是對稱的 ,如果A能穿過B 並不能代表B也能穿過A
B能否穿過A,則取決於B的碰撞掩碼與A的分類掩碼位與是否爲0來決定
監聽接觸事件發生
場景:
- 當物體A與物體B 剛發生接觸,觸發一個事件處理(Begin)
- 當物體A與物體B 接觸在一起時,觸發一個事件處理(pre-solve)
- 當物體A與物體B接觸,並且碰撞已經被處理(post-solve)
- 兩個物體剛剛脫離接觸,觸發一個事件處理(separate)
上訴四種情形,cocos 的 EventListenerPhysicsContact 類已經考慮到了,我們需要做的則是
將A 和B 的對應的body 的 接觸掩碼(ContactTestBitMask) 設置一下,如果按位與爲結果不爲0則A.B 物體接觸時,會觸發這個監聽器,執行相關的處理
示例代碼:
smallBody->setContactTestBitmask(1);
heroBody->setContactTestBitmask(3);
// 註冊監聽事件
EventListenerPhysicsContact * hitListener = EventListenerPhysicsContact::create();
hitListener->onContactBegin = [=](PhysicsContact & contact) {
// 通過contact 獲取發生接觸的兩個node
auto nodeA = contact.getShapeA()->getBody()->getNode();
auto nodeB = contact.getShapeB()->getBody()->getNode();
if (nodeA && nodeB) {
auto node = nodeA;
if (nodeB->getTag() == 40) {
node = nodeB;
}
node->getPhysicsBody()->setVelocity(Vec2(0, 0));
// doSth,比如增加爆炸效果
}
return true;
};
Director::getInstance()->getEventDispatcher()
->addEventListenerWithSceneGraphPriority(hitListener, this);
注意:
- 碰撞檢測這裏的掩碼都是設置自己的接觸掩碼
- tag 要設置到sprite 對象上,而不是body上
奉上個小demo:
實現飛機下落,撞上主角飛機發生爆炸,並且從屏幕消失