- cocos2d-x 3.2 物理碰撞機制
-
cocos2d-x 3.0+ 中全新的封裝的物理引擎給了開發者最大的便捷,你不用再繁瑣與各種物理引擎的細節,完全的封裝讓開發者可以更快更好的將物理引擎的機制添加到自己的遊戲中,簡化的設計是從2.0到3.0+的一個質的飛躍。下面同樣以一個小demo來展示一下物理引擎的運用,同時說一下我在運用物理引擎中遇到的一些小小的問題。
cocos2d-x 3.0+中的物理屬性:
1、物理世界被集成到場景中,當你創建一個場景,你可以直接創建基於物理世界或者不使用物理世界的場景。
2、Node擁有它自己的body屬性。(sprite也是node)‘
3、cocos2d-x 3.0 已經封裝了物理屬性Body(PhysicsBody),Shape(PhysicsShape),Contact(PhysicsContact),Joint(PhysicsJoint)和World(PhysicsWorld),更加方便使用。
4、方便的使用listener-EventListenerPhysicsContact進行碰撞檢測。
當然,封裝好的物理引擎可以簡化開發難度,如果有能力的話也可以直接使用Box2D和Chipmunk的原生的物理引擎進行開發,這樣難度會有所提升。
下面的代碼創建一個帶物理世界的場景,並傳遞到場景中的層上。
PhysicsLayer.h中
12345678910class
PhysicsLayer :
public
cocos2d::Layer
{
...
// add following codes設置層中的物理世界
void
setPhyWorld(PhysicsWorld* world){m_world = world;}
private
:
PhysicsWorld* m_world;
...
}
123456789101112Scene* PhysicsLayer::createScene()
{
...
// add following codes
auto scene = Scene::createWithPhysics();
scene->getPhysicsWorld()->setDebugDrawMask(PhysicsWorld::DEBUGDRAW_ALL);
//調試
auto layer = HelloWorld::create();
layer->setPhyWorld(scene->getPhysicsWorld());
//將創建的物理世界傳遞到子層中
...
return
scene;
}
Scene類有一個新的static工廠方法createWithPhysics()創建一個帶物理世界的場景。可以通過getPhysicsWorld()來獲取PhysicsWorld的實例。
上述代碼中註釋爲調試的代碼在調試中非常有用,它會顯示遊戲中物體所帶有的物理邊界,便於觀察碰撞中的細節等。
同時一個場景中只能有一個物理世界,所有屬於這個場景的子層都共享這一個物理世界,所以在子層中用到物理世界時都會有這個定義的函數
1void
setPhyWorld(PhysicsWorld* world){m_world = world;}
PhysicsWorld擁有默認的重力設置,Vector(0.0f,-98.0f),當然你也可以隨意設置你想要的重力加速度,setGravity(Vect(0.0f,-200.0f)),設置重力加速度爲20米每二次方秒。
創建物理邊界
下面的代碼創建一個物理邊界123456Size visibleSize = Director::getInstance()->getVisibleSize();
auto body = PhysicsBody::createEdgeBox(visibleSize, PHYSICSBODY_MATERIAL_DEFAULT,
3
);
//設置要添加到節點中的物理body
auto edgeNode = Node::create();
edgeNode->setPosition(Point(visibleSize.width/
2
,visibleSize.height/
2
));
edgeNode->setPhysicsBody(body);
//將物理body加入到創建的節點中
scene->addChild(edgeNode);場景中添加創建的物理節點
創建受重力影響的精靈
下面的代碼創建一個受重力影響的精靈,3.0中的創建精靈代碼也大大簡化123456789void
HelloWorld::addNewSpriteAtPosition(Point p)
{
auto sprite = Sprite::create(
"circle.png"
);
//創建精靈
sprite->setTag(
1
);
//設置精靈的便籤值
auto body = PhysicsBody::createCircle(sprite->getContentSize().width /
2
);
//創建一個附加在精靈身體上的圓形物理body
sprite->setPhysicsBody(body);
//將創建的body加到精靈身上
sprite->setPosition(p);
this
->addChild(sprite);
//添加精靈
}
下面講一下真正的重點所在——物理碰撞檢測
談到物理碰撞檢測,真是感慨良多,在第一次運用碰撞檢測時,遇到各種問題,最大的問題就是註冊完物理碰撞響應時間,寫好碰撞響應函數後,居然沒反應,找各種論壇貼,各種google,最後都沒有解決問題,最後還是在官網找到的解決方法,下面先介紹下如何設置碰撞檢測。 前面的博客講過了3.0中的事件分發機制,所以物理引擎的碰撞事件也不例外,統一的都有事件派發器來管理。 下面代碼註冊碰撞響應事件和回調函數123auto contactListener = EventListenerPhysicsContact::create();
contactListener->onContactBegin = CC_CALLBACK_1(HelloWorld::onContactBegin,
this
);
_eventDispatcher->addEventListenerWithSceneGraphPriority(contactListener,
this
);
一個body的CategoryBitmask和另一個body的ContactTestBitmask的邏輯與的結果不等於0時,接觸事件將被髮出,否則不發送。
一個body的CategoryBitmask和另一個body的CollisionBitmask的邏輯與結果不等於0時,他們將碰撞,否則不碰撞
默認情況下的body屬性會進行物理碰撞,但不會發送碰撞檢測的信號,也就不會響應碰撞回調函數,這個可以看下默認情況下的掩碼值的邏輯與12345678CategoryBitmask =
0xFFFFFFFF
;
ContactTestBitmask =
0x00000000
;
CategoryBitmask & ContactTestBitmask =
0
,所以不會發送碰撞信號
CollisionBitmask =
0xFFFFFFFF
;
CategoryBitmask & CollisionBitmask =
0xFFFFFFFF
所以物體會碰撞,但是不會響應碰撞回調函數。
。