实习小白::(转) Cocos2d-x 3.0 开发(九)使用Physicals代替Box2D和chipmunk

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的初始化。

[cpp] view plaincopyprint?

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

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

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

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

[cpp] view plaincopyprint?

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

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

[cpp] view plaincopyprint?

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

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

此函数已在3.0 alpha1中失效

[cpp] view plaincopyprint?

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


应使用如下函数

[cpp] view plaincopyprint?

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

4、创建边界

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

在init中进行更改:

[cpp] view plaincopyprint?

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

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

5、添加元素

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

[cpp] view plaincopyprint?

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

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

[cpp] view plaincopyprint?

  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);
  9. }

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

[cpp] view plaincopyprint?

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

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

6、碰撞检测

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

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

下面函数已失效

[cpp] view plaincopyprint?

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

应使用:

[cpp] view plaincopyprint?

  1. void HelloWorld::onEnter()
  2. {
  3. Layer::onEnter();
  4. auto listener = EventListenerPhysicsContact::create();
  5. listener->onContactBegin = [=](EventCustom* event, const PhysicsContact& contact)
  6. {
  7. auto sp = (Sprite*)contact.getShapeA()->getBody()->getNode();
  8. int tag = sp->getTag();
  9. if(tag == 1)
  10. {
  11. Texture2D *texture = TextureCache::getInstance()->addImage("2.png");
  12. sp->setTexture(texture);
  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是随意写的
  24. }

其中,我们将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

时间: 2024-11-25 06:42:23

实习小白::(转) Cocos2d-x 3.0 开发(九)使用Physicals代替Box2D和chipmunk的相关文章

实习小白::(转) Cocos2d-x 3.0 开发(十五)使用UILayout布局,制作对话界面

1.概述 上一篇我们在编辑器中设计了一个静态的UIScrollView,而通常我们都需要在程序中动态增加信息.插入元素的位置怎么确定?在3.0中UILayout已经实现了基本的布局,一起来看看吧: 2.编辑界面 打开CocoStudio的UIEditor 编辑一个界面,创建一个ScrollView和两个Button.因为ScrollView继承自UILayout,这里我们采用它.不太能搞定的童鞋可参考:Cocos2d-x 3.0 开发(十四)使用UIScrollView 实现大小不同物品拖动展示

实习小白::(转) Cocos2d-x 3.0开发(十三)使用CocoStudio编辑帧事件并关联到程序

1.概述 帧事件也是新加入的功能.这篇中我们将看到如何使用它.我们将上篇中制作的动画稍加修改.有图为证: 2.用途与原理 首先介绍一下帧事件.正如其名:一个与帧相关联的事件. 为什么要这么做呢?首先没人想做一大堆碎动画,然后一点一点拼着播放吧.另外,有时候流程与事件控制最好关联到帧.比如一个攻击动作,有出刀和收刀两部 分.伤害自然是在刀所触到敌人时候产生的.做成两个动画比较麻烦,程序要管理大量的动画,而且美工也会很郁闷:不但给你们切图,还要给你们切动画.如果用 固定时间来做,也是会有问题.比如机

实习小白::(转) Cocos2d-x 3.0 开发(七)在程序中处理cocoStudio导出动画

1.概述 使用cocoStudio可以方便的制作动画,接下来的工作就是在我们的程序中使用制作的动画.这篇中,我将使用程序将两个动画连接起来.有图有真相: 2.制作动画 承接上一篇,我们再制作一个动画.制作动画的方法与之前没有差别,不太熟悉的同学可以看:Cocos2d-x 3.0开发(六)使用cocoStudio创建一个骨骼动画.在“动作列表”中右击,“添加动画”然后编辑就成. 我们新制作的动画的结束点,要与上一篇中制作动画的开始点重合,这样在连接的时候,画面就不会跳动. 制作好后我们将动画导出.

Yii Framework2.0开发教程(8)输入验证

validate() 方法,在幕后为执行验证操作.先看一个简单的例子,例子的代码在<Yii Framework2.0开发教程(2)使用表单Form>. 类ZhyoulunController中函数actionEntry() ,其中有一句$model->validate(),就是来判断输入的名字和电子邮件是否正确. 修改models/EntryForm.php <?php namespace app\models; use yii\base\Model; class EntryFor

高屋建瓴 cocos2d-x-3.0架构设计 Cocos2d (v.3.0) rendering pipeline roadmap(原文)

Cocos2d (v.3.0) rendering pipeline roadmap Why (the vision) The way currently Cocos2d does rendering is good but it is beginning to feel somehow antiquate and moreover it doesn't actually leverage modern multi core CPUs so popular nowadays on most mo

ASP.NET Core 1.0 开发记录

参考页面: http://www.yuanjiaocheng.net/ASPNET-CORE/first.html http://www.yuanjiaocheng.net/ASPNET-CORE/asp-net-core-overview.html http://www.yuanjiaocheng.net/ASPNET-CORE/asp.net-core-environment.html http://www.yuanjiaocheng.net/ASPNET-CORE/newproject.h

学习时用的软件最新 开发环境为Visual Studio 2010,数据库为SQLServer2005,使用.net 4.0开发。 超市管理系统

一.源码特点 1.采用典型的三层架构进行开发.模板分离,支持生成静态 伪静态..购物车.登陆验证.div+css.js等技术二.功能介绍 1.本源码是一个超市在线购物商城源码,该网上商城是给超市便利店等零售批发实体店定制的网上商城,主要针对周边配送,后台可定义配送范围,可在线支付和货到付款! 2.用户注册,需要填写正确手机号码 获得验证码输入正确才能注册成功,保证用户信息的准确性,真实性.其它在线购物商城的常规功能,该系统都有,非常适合学习或二次开发使用,欢迎下载三.菜单功能       前台页

android5.0开发必备版本和JDK环境配置

android5.0开发必备版本: JDK-1.8-x64; NDK-10-x64; ADT-5.0&4.0-x64; 谷歌代理: https://wen.lu/?gfe_rd=cr&ei=Ir7YU5XsOK3J8ge_24GgBQ&gws_rd=cr 也可用FQ软件:goagent,或FQ浏览器 goagent: https://github.com/goagent/goagent 配置地址:http://www.woshipm.com/it/13644.html JDK配置(

个人知识管理系统Version1.0开发记录(08)

切入点 前面,我们已经搭建好了web端的一种基本结构,需要进一步定位的主要问题有三点: 1.界面的选择和确定,用extjs做的初步样式,进一步改动为jqueryUI/html,再进一步改变为HTML5等.我们思考一种用户思维,只要有一个地方让用户不喜欢,用户就会全盘否定该款软件:所以,软件界面一定要简单.精致.能引起用户的兴趣.符合用户习惯和用户思维. 2.框架的选择和确定,struts2,hibernate/mybatis,spring等,在编写知识体核心功能模块前,需要完成选择和改写. 3.