cocos2d-x 3.x 物理碰撞机制

近期又弄了物理引擎。写一下吧,以下有在其它博客学习到的知识。加上自己的理解,总结下。

cocos2d-x 3.X 中全新的封装的物理引擎给了开发人员最大的便捷,你不用再繁琐与各种物理引擎的细节,全然的封装让开发人员能够更快更好的将物理引擎的机制加入到自己的游戏中,简化的设计是从2.0到3.X的一个质的飞跃。


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中

  1. class PhysicsLayer : public cocos2d::Layer  
  2. {  
  3.     ...  
  4.     // add following codes设置层中的物理世界  
  5.     void setPhyWorld(PhysicsWorld* world){m_world = world;}  
  6.    
  7.     private:  
  8.         PhysicsWorld* m_world;  
  9.     ...  
  10. }  
PhysicsLayer.cpp中的createScene()方法中加入以下代码:

  1. Scene* PhysicsLayer::createScene()  
  2. {  
  3.     ...  
  4.     // add following codes  
  5.     auto scene = Scene::createWithPhysics();  
  6.     scene->getPhysicsWorld()->setDebugDrawMask(PhysicsWorld::DEBUGDRAW_ALL);//调试  
  7.    
  8.     auto layer = HelloWorld::create();  
  9.     layer->setPhyWorld(scene->getPhysicsWorld());//将创建的物理世界传递到子层中  
  10.     scene->addChild(layer);
  11.     return scene;  
  12. }  

Scene类有一个新的static工厂方法createWithPhysics()创建一个带物理世界的场景。能够通过getPhysicsWorld()来获取PhysicsWorld的实例。

上述代码中凝视为调试的代码在调试中很实用,它会显示游戏中物体所带有的物理边界,便于观察碰撞中的细节等。

同一时候一个场景中仅仅能有一个物理世界,全部属于这个场景的子层都共享这一个物理世界。所以在子层中用到物理世界时都会有这个定义的函数

  1. void setPhyWorld(PhysicsWorld* world){m_world = world;}  
进而来设置子层中的物理世界。

PhysicsWorld拥有默认的重力设置,Vector(0.0f,-98.0f),当然你也能够任意设置你想要的重力加速度。setGravity(Vect(0.0f,-200.0f)),设置重力加速度为20米每二次方秒。

创建物理边界

以下的代码创建一个物理边界,事实上就是做外面的边界框
  1. Size visibleSize = Director::getInstance()->getVisibleSize();  
  2. auto body = PhysicsBody::createEdgeBox(visibleSize, PHYSICSBODY_MATERIAL_DEFAULT, 3);//设要加入到节点中的物理body  ,这个Box是不受碰撞检測的!!!

  3. auto edgeNode = Node::create();  
  4. edgeNode->setPosition(Point(visibleSize.width/2,visibleSize.height/2));  
  5. edgeNode->setPhysicsBody(body);//将物理body增加到创建的节点中  
  6. scene->addChild(edgeNode);场景中加入创建的物理节点  
PhysicsWorld有非常多工厂方法。如createEdgeBox创建一个矩形的边框,參数:
1、矩形区域,设置作为VisibleSize
2、可选參数,物理材料,默觉得PHYSICSBODY_MATERIAL_DEFAULT。
3、可选參数,边框大小,默觉得1.

创建受重力影响的精灵

以下的代码创建一个受重力影响的精灵,3.0中的创建精灵代码也大大简化
  1. void HelloWorld::addNewSpriteAtPosition(Point p)  
  2. {  
  3.     auto sprite = Sprite::create("circle.png");//创建精灵  
  4.     sprite->setTag(1);//设置精灵的便签值  
  5.     auto body = PhysicsBody::createCircle(sprite->getContentSize().width / 2);//创建一个附加在精灵身体上的圆形物理body  
  6.     sprite->setPhysicsBody(body);//将创建的body加到精灵身上  
  7.     sprite->setPosition(p);  
  8.     this->addChild(sprite);//加入精灵  
  9. }  

以下讲一下真正的重点所在——物理碰撞检測

上次做《NotOneLess》项目的时候用到了物理引擎。事实上物理引擎的碰撞检測就是 对 三个掩码属性值的设置,来来回回就是设置值得问题,搞懂了这个。物理碰撞学会了80%了
看懂这个吧:点击打开链接 http://www.tuicool.com/articles/nAZbuy
以下代码注冊碰撞响应事件和回调函数
  1. auto contactListener = EventListenerPhysicsContact::create();  
  2. contactListener->onContactBegin = CC_CALLBACK_1(HelloWorld::onContactBegin, this);  
  3. _eventDispatcher->addEventListenerWithSceneGraphPriority(contactListener, this);  
每一次碰撞检測事件是有EventListenerPhysicsContact来进行监听的。监听到碰撞事件时,会回调响应事件onContactBegin()来进行碰撞事件的处理。_eventDispatcher是事件派发器,由它管理全部的注冊事件。
EventListenerPhysicsContact是碰撞检測中的一种。也能够运用以下的来进行碰撞事件的注冊EventListenerPhysicsContactWithBodies,EventListenerPhysicsContactWithShapes,EventListenerPhysicsContactWithGroup来进行你感兴趣的bodys,shape和group事件监听。
在上面说了这么多的东西,最重要的东西就是以下的。没有以下的东西,碰撞事件根本不起作用,这就是我第一次运用碰撞时遇到的问题。也就是设置物理接触相关的位掩码值,默认的接触事件不会被接受,须要设置一定的掩码值来使接触事件响应。
接触掩码值有三个值。各自是:
1、CategoryBitmask,默认值为0xFFFFFFFF
2、ContactTestBitmask,默认值为 0x00000000
3、CollisionBitmask。默认值为0xFFFFFFFF
这三个掩码值都有相应的set/get方法来设置和获取。
这三个掩码值由逻辑与来进行操作測试。


一个body的CategoryBitmask和还有一个body的ContactTestBitmask的逻辑与的结果不等于0时。接触事件将被发出,否则不发送。

一个body的CategoryBitmask和还有一个body的CollisionBitmask的逻辑与结果不等于0时,他们将碰撞,否则不碰撞

默认情况下的body属性会进行物理碰撞。但不会发送碰撞检測的信号,也就不会响应碰撞回调函数。这个能够看下默认情况下的掩码值的逻辑与
  1. CategoryBitmask = 0xFFFFFFFF;  
  2. ContactTestBitmask = 0x00000000;  
  3. CategoryBitmask & ContactTestBitmask = 0,所以不会发送碰撞信号  
  4.   
  5. CollisionBitmask = 0xFFFFFFFF;  
  6.   
  7. CategoryBitmask & CollisionBitmask = 0xFFFFFFFF  
  8. 所以物体会碰撞,可是不会响应碰撞回调函数。  
上面介绍的掩码值是碰撞检測回调中最重要的,没有上面的掩码值。全部的碰撞回调函数都不会发生。
EventListenerPhysicsContact有四个接触回调函数:
1、onContactBegin,在接触開始时被调用,仅调用一次,通过放回true或者false来决定两个物体是否有碰撞。

同一时候能够使用PhysicsContact::setData()来设置接触操作的用户数据。

当返回false时。onContactPreSolve和onContactPostSolve将不会被调用,可是onContactSeperate将被调用一次。

2、onContactPreSlove ,会在每一次被调用。通过放回true或者false来决定两个物体是否有碰撞,相同能够用ignore()来跳过兴许的onContactPreSolve和onContactPostSolve回调函数。(默认返回true)
3、onContactPostSolve,在两个物体碰撞反应中的每一个步骤中被处理调用。能够在里面做一些兴许的接触操作。如销毁body
4、onContactSeperate。在两个物体分开时被调用,在每次接触时仅仅调用一次,和onContactBegin配对使用。
上述中最重要的就是碰撞检測事件的解说,这是游戏中用到碰撞常常要用到的。
好了。这篇解说了游戏中的物理碰撞机制。

posted @ 2016-04-05 11:59  mengfanrong  阅读(1106)  评论(0编辑  收藏  举报