在cocos2d-x 3.0中,我们应该如何使用新版的物理引擎呢?我们将采用一个简单的例子:有一个篮球,你可以通过旋转你的手机来改变重力的方向,同时篮球碰到屏幕边界可以反弹。下面是例子的效果图:
接下来,我们将来详细讲解。
新建一个工程,名为“Box2dBall”。将HelloWorld模板里面的内容都删除掉,HelloWorldScene.h替换成下面的代码:
#ifndef __HELLOWORLD_SCENE_H__ #define __HELLOWORLD_SCENE_H__ #include "cocos2d.h" USING_NS_CC; class HelloWorld : public cocos2d::Layer { public: Sprite* _ball; PhysicsWorld* m_world; void setPhyWorld(PhysicsWorld* world){ m_world = world; }; // there's no 'id' in cpp, so we recommend returning the class instance pointer static cocos2d::Scene* createScene(); // Here's a difference. Method 'init' in cocos2d-x returns bool, instead of returning 'id' in cocos2d-iphone virtual bool init(); // implement the "static create()" method manually CREATE_FUNC(HelloWorld); }; #endif // __HELLOWORLD_SCENE_H__
#include "HelloWorldScene.h" Scene* HelloWorld::createScene() { // 'scene' is an autorelease object auto scene = Scene::createWithPhysics(); scene->getPhysicsWorld()->setDebugDrawMask(PhysicsWorld::DEBUGDRAW_ALL); // 'layer' is an autorelease object auto layer = HelloWorld::create(); layer->setPhyWorld(scene->getPhysicsWorld()); // add layer as a child to scene scene->addChild(layer); // return the scene return scene; } // on "init" you need to initialize your instance bool HelloWorld::init() { ////////////////////////////// // 1. super init first if ( !Layer::init() ) { return false; } return true; }
cocos2d-x 3.0对物理系统进行了封装,开发过程中可不再纠结与box2d和chipmunk的接口。Physics integration大大方便了物理系统的使用。
通过createWithPhysics()方法创建一个带有物理效果的Scene,然后将需要添加物理效果的层加入其中:
auto scene = Scene::createWithPhysics(); scene->getPhysicsWorld()->setDebugDrawMask(PhysicsWorld::DEBUGDRAW_ALL); auto layer = HelloWorld::create(); layer->setPhyWorld(scene->getPhysicsWorld()); scene->addChild(layer);
DebugDraw对需要使用物理系统的我们来说是个很有用的方法。它可将碰撞体的形状、关节等等全部绘制出来,方便我们观察物体及整个场景的可碰撞区域。
scene->getPhysicsWorld()->setDebugDrawMask(PhysicsWorld::DEBUGDRAW_ALL);
在HelloWorldScene.h中添加成员变量:
Sprite *_ball;
auto visibleSize = Director::getInstance()->getVisibleSize(); auto origin = Director::getInstance()->getVisibleOrigin(); // Create sprite and add it to the layer _ball = Sprite::create("Ball.jpg", Rect(0, 0, 52, 52)); _ball->setPosition(Point(400,600)); auto ballBody = PhysicsBody::createCircle(_ball->getContentSize().width / 2); _ball->setPhysicsBody(ballBody); this->addChild(_ball); auto edgeSp = Sprite::create(); auto boundBody = PhysicsBody::createEdgeBox(visibleSize, PHYSICSBODY_MATERIAL_DEFAULT, 3); edgeSp->setPosition(Point(visibleSize.width / 2, visibleSize.height / 2)); edgeSp->setPhysicsBody(boundBody); this->addChild(edgeSp); edgeSp->setTag(0); this->setAccelerometerEnabled(true);
首先,我们在屏幕中间加入一个精灵。
auto winSize = Director::getInstance()->getWinSize(); _ball = Sprite::create("Ball.jpg", Rect(0, 0, 52, 52)); _ball->setPosition(Point(400, 600)); this->addChild(_ball);
auto ballBody = PhysicsBody::createCircle(_ball->getContentSize().width / 2); _ball->setPhysicsBody(ballBody);
auto edgeSp = Sprite::create(); auto boundBody = PhysicsBody::createEdgeBox(visibleSize, PHYSICSBODY_MATERIAL_DEFAULT, 3); edgeSp->setPosition(Point(visibleSize.width / 2, visibleSize.height / 2)); edgeSp->setPhysicsBody(boundBody); this->addChild(edgeSp); edgeSp->setTag(0);
如果我们想要达到倾斜屏幕就可以让球朝着屏幕的某个方向运行的话,我们就需要添加加速计控制。
首先,在init方法里面添加如下代码:
this->setAccelerometerEnabled(true);
virtual void onAcceleration(Acceleration* acc, Event* unused_event);
void HelloWorld::onAcceleration(Acceleration* acc, Event* unused_event) { Vect gravity(-acc->y * 15, acc->x * 15); m_world->setGravity(gravity); }