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

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

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


cocos2d-x 3.0+中的物理属性:函数

一、物理世界被集成到场景中。当你建立一个场景。你可以直接建立基于物理世界或者不使用物理世界的场景。学习

二、Node拥有它本身的body属性。ui

(sprite也是node)‘this

三、cocos2d-x 3.0 已经封装了物理属性Body(PhysicsBody),Shape(PhysicsShape),Contact(PhysicsContact),Joint(PhysicsJoint)和World(PhysicsWorld),更加方便使用。spa

四、方便的使用listener-EventListenerPhysicsContact进行碰撞检測。.net

固然,封装好的物理引擎可以简化开发难度,假设有能力的话也可以直接使用Box2D和Chipmunk的原生的物理引擎进行开发,这样难度会有所提高。设计

如下的代码建立一个带物理世界的场景,并传递到场景中的层上。调试

PhysicsLayer.h中

[cpp]  view plain copy 在CODE上查看代码片 派生到个人代码片
  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()方法中加入如下代码:

[cpp]  view plain copy 在CODE上查看代码片 派生到个人代码片
  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的实例。

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

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

[cpp]  view plain copy 在CODE上查看代码片 派生到个人代码片
  1. void setPhyWorld(PhysicsWorld* world){m_world = world;}  
进而来设置子层中的物理世界。

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

建立物理边界

如下的代码建立一个物理边界,事实上就是作外面的边界框
[cpp]  view plain copy 在CODE上查看代码片 派生到个人代码片
  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建立一个矩形的边框,參数:
一、矩形区域,设置做为VisibleSize
二、可选參数,物理材料,默以为PHYSICSBODY_MATERIAL_DEFAULT。
三、可选參数,边框大小,默以为1.

建立受重力影响的精灵

如下的代码建立一个受重力影响的精灵,3.0中的建立精灵代码也大大简化
[cpp]  view plain copy 在CODE上查看代码片 派生到个人代码片
  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
如下代码注冊碰撞响应事件和回调函数
[cpp]  view plain copy 在CODE上查看代码片 派生到个人代码片
  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事件监听。
在上面说了这么多的东西,最重要的东西就是如下的。没有如下的东西,碰撞事件根本不起做用,这就是我第一次运用碰撞时遇到的问题。也就是设置物理接触相关的位掩码值,默认的接触事件不会被接受,需要设置必定的掩码值来使接触事件响应。
接触掩码值有三个值。各自是:
一、CategoryBitmask,默认值为0xFFFFFFFF
二、ContactTestBitmask,默认值为 0x00000000
三、CollisionBitmask。默认值为0xFFFFFFFF
这三个掩码值都有相应的set/get方法来设置和获取。
这三个掩码值由逻辑与来进行操做測试。


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

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

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

同一时候可以使用PhysicsContact::setData()来设置接触操做的用户数据。

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

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