Cocos2d-x 3.0 开发(九)使用Physicals代替Box2D和chipmunk

转载 2013年12月05日 10:40:20

        Cocos2d-x 3.0 开发(九)使用Physicals代替Box2D和chipmunk       

分类:            Cocos2D-X10033人阅读评论(20)收藏举报

目录(?)[+]

  1. 概述
  2. 原理分析
  3. 创建场景
  4. 创建边界
  5. 添加元素
  6. 碰撞检测
  7. 总结

1、   概述

    游戏中模拟真实的世界是个比较麻烦的事情,通常这种事情都是交给物理引擎来做。首屈一指的是Box2D了,它几乎能模拟所有的物理效果。而chipmunk则是个更轻量的引擎,能够满足简单的物理需求,比如最常用的的碰撞检测等。这些引擎在使用的过程中有个令人讨厌的地方,它们参数太多了。通常为了初始化一个简单的场景要写很多代码。在cocos2d-x 3.0版本中,出现了一个新类族——physicals。它将Box2D或者chipmunk做了一层封装,使我们的上层调用有更友好的接口。它通过宏来切换使用哪种物理引擎,目前的版本只有chipmunk的实现,Box2D的实现没有写,所以手动将宏切换的话是不行的。另外,当前版本还是有bug的,下面会提到,先看效果图吧:




2、 原理分析


    相信大家都对物理引擎的使用有所了解,篇幅有限,一些基本概念就不复述了。如果你曾经用过Box2D或者chipmunk,再使用这套封装,你只会有一种爽到爆的感觉。

    在这个版本中,物理世界的概念被加入到Scene中,即当创建一个场景时,就可以指定这个场景是否使用物理引擎。相对应的,每一个Sprite中也有body的概念。可以直接将body关联到Sprite上。Listener当然也不需要再弄一套东西来监听,只要注册到场景中就可以了。

    不知你听到这个改动有和感想,反正我是震惊了。

    接下来我们动手做一个吧。


3、创建场景


    首先,运行脚本创建一个新工程:testNewPhy,编译运行确保一切正常。

    找到 CreateScene函数,更改scene的初始化。

  1. Scene* HelloWorld::createScene() 
  2.     // 'scene' is an autorelease object 
  3.     auto scene = Scene::createWithPhysics(); 
  4.     scene->getPhysicsWorld()->setDebugDraw(true); //此句仅3.0 alpha0 有效 
  5.     scene->getPhysicsWorld()->setDebugDrawMask(PhysicsWorld::DEBUGDRAW_ALL); 
  6.  
  7.      
  8.     // 'layer' is an autorelease object 
  9.     auto layer = HelloWorld::create(); 
  10.  
  11.     // add layer as a child to scene 
  12.     scene->addChild(layer); 
  13.  
  14.     // return the scene 
  15.     return scene; 

    更改create,创建一个支持物理的世界,打开debugDraw。两行就可以搞定了。

    打开debugDrawMask,两行就可以搞定了。DrawMask参数可以选择打开绘制哪些部分比如,Joint、Shape等等。   

    接下来,我们要将这个World传到Layer中。所以我们在HelloWorld类中加入一个函数。将这个world存起来。

  1. //…… 
  2.      void setPhyWorld(PhysicsWorld* world){m_world = world;} 
  3. private
  4.     PhysicsWorld* m_world; 

    同时在creatScene创建layer完成后,将这个值设定上。

  1. // …… 
  2.    auto layer = HelloWorld::create(); 
  3.    layer->setPhyWorld(scene->getPhysicsWorld()); 
  4. / …… 


    另外,我们更改一下menuItem的响应,来控制debugDraw的绘制:


  此函数已在3.0 alpha1中失效

  1. <del>void HelloWorld::menuCloseCallback(Object* pSender) 
  2.     if(m_world->isDebugDraw()) 
  3.     { 
  4.          m_world->setDebugDraw(false); 
  5.     } 
  6.     else 
  7.     { 
  8.         m_world->setDebugDraw(true); 
  9.     } 
  10. </del> 

    使用如下函数

  1. void HelloWorld::menuCloseCallback(Object* pSender) 
  2.     if(m_world->getDebugDrawMask() != PhysicsWorld::DEBUGDRAW_NONE) 
  3.     { 
  4.          m_world->setDebugDrawMask(PhysicsWorld::DEBUGDRAW_NONE); 
  5.     } 
  6.     else 
  7.     { 
  8.         m_world->setDebugDrawMask(PhysicsWorld::DEBUGDRAW_ALL); 
  9.     } 
  10.  

   

4、创建边界

    创建了物理世界,还要有东西才行。接下来,我们着手创建一个边界。我们可以方便的使用PhysicalsBody的create方法创建自己想要的物体。

    在init中进行更改:

  1. // on "init" you need to initialize your instance 
  2. bool HelloWorld::init() 
  3.     ////////////////////////////// 
  4.     // 1. super init first 
  5.     if ( !Layer::init() ) 
  6.     { 
  7.         return false
  8.     } 
  9.      
  10.     Size visibleSize = Director::getInstance()->getVisibleSize(); 
  11.     Point origin = Director::getInstance()->getVisibleOrigin(); 
  12.  
  13.     ///////////////////////////// 
  14.     
  15.     auto edgeSp = Sprite::create(); 
  16.     auto body = PhysicsBody::createEdgeBox(visibleSize,3); //此句仅3.0 alpha0 有效 
  17.         auto body = PhysicsBody::createEdgeBox(visibleSize,PHYSICSBODY_MATERIAL_DEFAULT,3); 
  18.         edgeSp->setPosition(Point(visibleSize.width/2,visibleSize.height/2)); 
  19.         edgeSp->setPhysicsBody(body);this->addChild(edgeSp);edgeSp->setTag(0); 
  20.         return true

    其中,PHYSICSBODY_MATERIAL_DEFAULT宏表示的是创建的Body的默认材质,3是边线宽度。编译运行我们会看到场景边上有红色的边界。




5、添加元素

    我们先将点击响应搭建起来,在init中将touchEnable设置为true,重新onTouchesEnd方法:

  1. void HelloWorld::onTouchesEnded(const std::vector<Touch*>& touches, Event *event) 
  2.     for(auto touch:touches) 
  3.     { 
  4.         auto location = touch->getLocation(); 
  5.         addNewSpriteAtPosition(location); 
  6.     } 

    然后我们来实现addNewSpriteAtPosition函数。关联body与sprite从未如此简单,我们只需创建一个body,创建一个sprite然后将body设置为sprite的body即可。

  1. void HelloWorld::addNewSpriteAtPosition(Point p) 
  2. {     
  3.     auto sp = Sprite::create("1.png"); 
  4.     sp->setTag(1); 
  5.     auto body = PhysicsBody::createBox(Size(80, 40)); 
  6.     sp->setPhysicsBody(body);     
  7.     sp->setPosition(p); 
  8.     this->addChild(sp); 

    在这其中,当前版本的cocos2d-x 3.0有一个小问题。关联的时候,并未将body相应的owner设置为对应的sprite,我们需要修改sprite.cpp中的setPhysicsBody这个函数。增加最后一行。此bug已修复

  1. void Sprite::setPhysicsBody(PhysicsBody* body) 
  2.     _physicsBody = body; 
  3.     _physicsBody->retain(); 
  4.     _physicsBody->setPosition(getPosition()); 
  5.     _physicsBody->setRotation(getRotation()); 
  6.     _physicsBody->_owner = this

     编译运行,我们点击屏幕即可动态创建元素了。




6、碰撞检测

    碰撞检测的回调是在world中注册函数来实现的。首先我们在HelloWorld中声明一个变量。并重写OnEnter方法。

    碰撞检测的回调是在Scene中注册Listener来实现的。当有碰撞发生时,就会调用对应的Listener。所有的碰撞都使用EventListenerPhysicsContact类。我们可以通过重写它的onContactBegin、onContactPreSolve、onContactPostSolve、onContactSeperate方法来更改它的行为。

    下面函数已失效

  1. //声明 
  2. PhysicsContactListener m_listener; 
  3.  
  4. //实现 
  5.  
  6. void HelloWorld::onEnter() 
  7.     Layer::onEnter(); 
  8.  
  9.     m_listener.onContactBegin = [=](const PhysicsContact& contact) 
  10.     { 
  11.         auto cnt = const_cast<PhysicsContact*>(&contact); 
  12.  
  13.         auto sp = cnt->getShapeA()->getBody()->getOwner(); 
  14.         int tag = sp->getTag(); 
  15.         if(tag == 1) 
  16.         { 
  17.             Texture2D *texture = TextureCache::getInstance()->addImage("2.png"); 
  18.             sp->setTexture(texture); 
  19.         } 
  20.  
  21.         sp = cnt->getShapeB()->getBody()->getOwner(); 
  22.         tag = sp->getTag(); 
  23.         if(tag == 1) 
  24.         { 
  25.             Texture2D *texture = TextureCache::getInstance()->addImage("1.png"); 
  26.             sp->setTexture(texture); 
  27.         } 
  28.         return true
  29.     }; 
  30.     m_world->registerContactListener(&m_listener); 

    应使用:

  1. void HelloWorld::onEnter() 
  2.     Layer::onEnter(); 
  3.     auto listener = EventListenerPhysicsContact::create(); 
  4.     listener->onContactBegin = [=](EventCustom* event, const PhysicsContact& contact) 
  5.     { 
  6.         auto sp = (Sprite*)contact.getShapeA()->getBody()->getNode(); 
  7.         int tag = sp->getTag(); 
  8.         if(tag == 1) 
  9.         { 
  10.             Texture2D *texture = TextureCache::getInstance()->addImage("2.png"); 
  11.             sp->setTexture(texture); 
  12.         } 
  13.  
  14.         sp = (Sprite*)contact.getShapeB()->getBody()->getNode(); 
  15.         tag = sp->getTag(); 
  16.         if(tag == 1) 
  17.         { 
  18.             Texture2D *texture = TextureCache::getInstance()->addImage("1.png"); 
  19.             sp->setTexture(texture); 
  20.         } 
  21.         return true
  22.     };   
  23.     Director::getInstance()->getEventDispatcher()->addEventListenerWithFixedPriority(listener,10); //第二个参数是优先级,10是随意写的 


    其中,我们将listener的onContactBegin方法重写。并通过shape->body->owner的方式来取到sprite。更改它的显示。最后将listener注册到m_world中。

    编译运行,然后点击menuItem,将debugDrow关闭,即可。


7、总结

    通过创建一个支持Physicals的场景,来创建物理系统。将body创建出来,并调用sprite的setPhysicsBody来为一个sprite设定body。通过PhysicsContactListener来创建一个Listener并通过registerContactListener将其注册,来处理碰撞。

    Demo下载:http://download.csdn.net/detail/fansongy/6502401

    Demo 下载(3.0 alpha1版本):http://download.csdn.net/detail/fansongy/6652089


    本篇博客出自阿修罗道,转载请注明出处,禁止用于商业用途http://blog.csdn.net/fansongy/article/details/14142323

物理引擎比较:Box2D 对比 Chipmunk

Cocos2d 自带了两套物理引擎:Box2D 和 Chipmunk。那么我们应该选择哪一个呢? 很多情况下,这个选择取决于个人口味。很多游戏开发者对这两个物理引擎的 争论集中于它们所用的编程语言:...
  • benbenxiongyuan
  • benbenxiongyuan
  • 2014年08月29日 22:03
  • 3204

cocos2dx-3.0 中的物理引擎Box2D使用(四)

~~~~我的生活,我的点点滴滴!!
  • AC_huang
  • AC_huang
  • 2014年09月03日 00:30
  • 1479

物理引擎Box2d与Chipmunk比较

Cocos2d 自带了两套物理引擎:Box2D 和 Chipmunk。那么我们应该选择哪一个呢? 很多情况下,这个选择取决于个人口味。很多游戏开发者对这两个物理引擎的 争论集中于它们所用的编程语言:...
  • hzl877243276
  • hzl877243276
  • 2014年05月17日 10:43
  • 1043

实例介绍Cocos2d-x中Box2D物理引擎:碰撞检测

在Box2D中碰撞事件通过实现b2ContactListener类函数实现,b2ContactListener是Box2D提供的抽象类,它的抽象函数:virtual void BeginContact...
  • tonny_guan
  • tonny_guan
  • 2014年10月09日 19:08
  • 5440

【amazing cocos2d-x 3.0之十六】新物理引擎,来谈谈chipmunk和Box2d

关于物理引擎,在3.0中有了全新的Physics integration
  • Legendof1991
  • Legendof1991
  • 2014年04月11日 15:05
  • 5749

Cocos2d-x教程(17)-Box2D 物理引擎

Box2D的基本使用方法
  • u012945598
  • u012945598
  • 2014年01月03日 13:30
  • 7676

cocos2dx视频教程进阶篇--第2天--打砖块游戏-box2d物理引擎

感谢大家的鼓励和支持,今天进阶篇2奉献给大家。 不了解cocos2dx基本概念的朋友,请移步  http://blog.csdn.net/s_xing/article/details/18557631...
  • xingxiliang
  • xingxiliang
  • 2014年03月09日 11:25
  • 4267

Cocos2d-x 3.0中的新物理引擎:Chipmunk和Box2d

ZeroYang原创,首发于泰然,转载请著名出处。 概述 在游戏中模拟真实的物理世界是个比较麻烦的,通常都是交给物理引擎来做。比较知名的有Box2D了,它几乎能模拟所有的物理效果,而c...
  • qq563129582
  • qq563129582
  • 2014年05月11日 16:11
  • 872

cocos2d-x 3.0开发笔记---物理引擎封装 Physics深入学习

3.0以后最box2d和chipmunk这两个物理引擎进行了封装,使用起来非常的便利。 官方链接地址:英文版 泰然网:中文教程 offset:重心点 velocity:速度 dadampin...
  • u013340539
  • u013340539
  • 2014年03月30日 17:55
  • 6513

cocos2d-x 3.0学习-使用Physicals创建物理世界

一、创建物理世界 在cocos2d-x 3.0版本中,封装了方便模拟物理世界操作的一系列physicals类,在这之前一般是将box2d或者chipmunk集成到cocos2d-x中来。而现在,就方...
  • u013369593
  • u013369593
  • 2015年09月02日 22:29
  • 201
内容举报
返回顶部
收藏助手
不良信息举报
您举报文章:Cocos2d-x 3.0 开发(九)使用Physicals代替Box2D和chipmunk
举报原因:
原因补充:

(最多只允许输入30个字)