物理集成
加入版本: 3.0alpha1
介绍
在游戏开发中人工地去模拟模拟一个物理世界是悲催的,所以一般由物理引擎来搞定这种问题。我们知道,Box2D就是模拟物理效果的,还有一个轻量的Chipmunk。在Cocos2d-x 2.0中,游戏直接使用物理引擎,而Cocos2d-x则提供一个简单的CCPhysicsSprite。CCPhysicsSprite负责物理引擎与CCSprite之间关系,但其它的物理元素却没有连接到cocos2d-x,这种方式迫使开发人员需要调用Chipmunk或者Box2D的APIs来解决这些问题。所以对于游戏开发人员来说直接使用物理引擎是繁琐的,得记大量的API参数。
不过在Cocos2d-x 3.0中就大有不同了,物理集成将Chipmunk和Box2D合成起来。开发人员不需要关心调用哪些API来对应哪个引擎。
物理引擎与Cocos2d-x的集成:
- 物理世界集成到Scene,你可以在创建场景的时候就指定是否使用物理引擎
- 节点有自己的身体属性,也就是说Sprite有自己的身体属性
- Cocos2d-x 3.0封装了物理引擎的Body(PhysicsBody), Shape(PhysicsShape), Contact(PhysicsContact), Joint(PhysicsJoint)和World(PhysicsWorld),这将使物理的引擎使用更加便利
- 更加简单的碰撞检测监听-EventListenerPhysicsContact。
创建使用物理引擎的游戏项目
创建3.0的项目可以直接使用/tools/project-creator下的create_project.py。
创建项目默认使用Chipmunk作为物理引擎,你也可以改成Box2D,其实它也不会有很大的不同。
在android中使用Box2D,你必须将 yourprojectName/proj.android/jni/Application.mk 作下面的改动:
DCC_ENABLE_CHIPMUNK_INTEGRATION=1改成:
DCC_ENABLE_BOX2D_INTEGRATION=1还有在项目设置的宏预处理器将
CC_ENABLE_CHIPMUNK_INTEGRATION=1改成:
CC_ENABLE_BOX2D_INTEGRATION=1Debug和Release两种都要改,如下图所示:
创建一个物理世界的场景
下面的代码创建一个物理世界的场景。
在PhysicsLayer.h添加下面代码:
class PhysicsLayer : public cocos2d::Layer { ... // add following codes void setPhyWorld(PhysicsWorld* world){m_world = world;} private: PhysicsWorld* m_world; ... }在PhysicsLayer.cpp的createScene方法中添加下面代码:
Scene* 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类有一个静态的工厂方法-createWithPhysics()来创建场景和物理世界。你可以通过调用Scene的getPhysicsWorld()方法来获取物理世界的实例。
PhysicsWorld有一个对于调试物理引擎很有用的方法,setDebugDrawMask(),它可以使图形,连接和碰撞等可见。不过发布游戏时可得记得把调试模式关闭掉。
你可以使用setPhyWorld()将PhysicsWorld传递到子层去,一个场景只有一个PhysicsWorld,所有的图层共享它一个。
创建物理边界
物理世界的一切物品都受重力影响。物理引擎提供了staticShape方法来创建不受重力影响的图形,在Cocos2d-x 2.x中,我们得记住staticShape中的所有参数。
不过在3.0中,PhysicsShape是Node的一个属性,如果你想设置PhysicsWorld的属性,你可以将一个Node实例作为参数传进来。
下面的代码创建一个物理边界:
Size visibleSize = Director::getInstance()->getVisibleSize(); auto body = PhysicsBody::createEdgeBox(visibleSize, PHYSICSBODY_MATERIAL_DEFAULT, 3); auto edgeNode = Node::create(); edgeNode->setPosition(Point(visibleSize.width/2,visibleSize.height/2)); edgeNode->setPhysicsBody(body); scene->addChild(edgeNode);
PhysicsWorld有许多诸如createEdgeBox(创建矩形边界)的工厂方法,它们的参数都是:
- 矩形边界,默认为可见的大小;
- 可选参数-Texture,默认为PHYSICSBODY_MATERIAL_DEFAULT;
- 可选参数迟框尺寸,默认为1。
代码中创建完边界后就创建一个Node,然后将屏幕的中点设置为该Node的位置,最后将Node添加到场景中。
Cocos2d-x 3.0中Node的addChild方法能处理物理身体,它将自动将Node的身体添加到场景的PhysicsWorld中。
PhysicsBody的项目方法可以创建相关的PhysicsBody和自动根据body大小的PhysicsShape,以往通常是直接通过物理引擎创建一个body,不过,3.0的物理集成已经简化了流程,我们不需要再写一大堆的代码了。
创建一个受重力影响的Sprite
Cocos2d-x 3.0中创建受重力影响的Sprite是极其容易的:
void HelloWorld::addNewSpriteAtPosition(Point p) { auto sprite = Sprite::create("circle.png"); sprite->setTag(1); auto body = PhysicsBody::createCircle(sprite->getContentSize().width / 2); sprite->setPhysicsBody(body); sprite->setPosition(p); this->addChild(sprite); }首先创建一个sprite,然后通过PhysicsBody::createCircle创建一个圆体与sprite关联就行了。
碰撞检测
Cocos2d-x重构了事件分发,所有的事件都由事件发送器来管理。所以现在的物理引擎的碰撞事件也由事件发送器来管理。
下面代码注册了一个碰撞开始的回调函数:
auto contactListener = EventListenerPhysicsContact::create(); contactListener->onContactBegin = CC_CALLBACK_2(HelloWorld::onContactBegin, this); _eventDispatcher->addEventListenerWithSceneGraphPriority(contactListener, this);所有的碰撞检测事件都被EventListenerPhysicsContact监听着。创建一个实例,然后设置它的回调方法conContactBegin。CC_CALLBACK_2是C++ 11的回调指针转换方法。因为onContactBegin方法有两个参数,所以我们用CC_CALLBACK_2来转换它们。
_eventDispatcher是基类Node的一个成员,它可以在初始化图层时使用。
Demo
你可以从这里获得这篇文章里的Demo
Demo是基于cocos2d-x 3.0alpha1的,将它复制到你的cocos2d-x-3.0alpha1/projects里去,没有projects文件夹的话就自己创建一个哈。
原文地址:这里