Cocos2d-x学习笔记(十二)—— Box2d物理引擎(未完)

来源:互联网 发布:黄鹤tv武汉网络电视 编辑:程序博客网 时间:2024/06/11 00:44

这里讲两个Box2d物理引擎的例子,一个新的cocos2d3.x版本,另一个是旧的2.x版。

关于box2d的基础知识,这里不再详述,详细参考:http://blog.csdn.net/u013707014/article/details/47685273

新版本:

HelloNewBox2d.h:

#ifndef __HELLONEWBOX2D_H__#define __HELLONEWBOX2D_H__#include "cocos2d.h"#include "Box2D\Box2D.h"using namespace cocos2d;class HelloNewBox2d : public Layer{private:CCTexture2D* _spriteTexture;public:HelloNewBox2d();~HelloNewBox2d();// there's no 'id' in cpp, so we recommend returning the class instance pointerstatic Scene* createNewBox2dScene();// Here's a difference. Method 'init' in cocos2d-x returns bool, instead of returning 'id' in cocos2d-iphonevirtual bool init();// implement the "static create()" method manuallyCREATE_FUNC(HelloNewBox2d);// 初始化物理引擎设置void initSprite();virtual bool onTouchBegan(cocos2d::Touch* touch, cocos2d::Event* event);void onAcceleration(Acceleration* acc, Event* event);// 在指定位置添加精灵void addNewSpriteAtPosition(Vec2 p);};#endif // __HELLOWORLD_SCENE_H__


HelloNewBox2d.cpp:

#include "HelloNewBox2d.h"USING_NS_CC;#define SCENERATIO 480/1024Scene* HelloNewBox2d::createNewBox2dScene(){auto box2dScene = Scene::create();// 初始化物理引擎box2dScene->initWithPhysics(); auto box2dLayer = HelloNewBox2d::create();box2dScene->addChild(box2dLayer);return box2dScene;}HelloNewBox2d::HelloNewBox2d() :_spriteTexture(NULL){}HelloNewBox2d::~HelloNewBox2d(){// 关闭重力感应Device::setAccelerometerEnabled(false);}bool HelloNewBox2d::init(){if (!Layer::init()){return false;}// 初始化物理引擎  this->initSprite();setTouchEnabled(true);return true;}void HelloNewBox2d::initSprite(){// 获取精灵纹理缓存_spriteTexture = Sprite::create("blocks.png")->getTexture();// 设置添加多点触控监听auto touchListener = EventListenerTouchOneByOne::create();touchListener->onTouchBegan = CC_CALLBACK_2(HelloNewBox2d::onTouchBegan, this);_eventDispatcher->addEventListenerWithSceneGraphPriority(touchListener, this);// 打开设备重力感应Device::setAccelerometerEnabled(true);// 设置重力感应监听auto accListener = EventListenerAcceleration::create(CC_CALLBACK_2(HelloNewBox2d::onAcceleration, this));_eventDispatcher->addEventListenerWithSceneGraphPriority(accListener, this);// 获得OpenGL可见区域的矩形(一般大小为窗口屏幕的大小)Rect s_visibleRect = Director::getInstance()->getOpenGLView()->getVisibleRect();// 可见区域的中心点(窗口屏幕中心点)Vec2 vec = Vec2(s_visibleRect.origin.x + s_visibleRect.size.width / 2,s_visibleRect.origin.y + s_visibleRect.size.height / 2);// 创建节点auto node = Node::create();// 设置刚体,且为边框属性node->setPhysicsBody(PhysicsBody::createEdgeBox(s_visibleRect.size));node->setPosition(vec);this->addChild(node);}void HelloNewBox2d::addNewSpriteAtPosition(Vec2 p){// 产生0和1的随机数int idx = CCRANDOM_0_1() > .5f ? 0 : 1;int idy = CCRANDOM_0_1() > .5f ? 0 : 1;// 从缓存中获取精灵,并设置添加刚体(考虑屏幕适应性问题)auto sp = Sprite::createWithTexture(_spriteTexture,Rect(idx*32.0f*SCENERATIO, idy*32.0f*SCENERATIO, 32.0f*SCENERATIO, 32.0f*SCENERATIO));sp->setPhysicsBody(PhysicsBody::createBox(Size(32.0f*SCENERATIO, 32.0f*SCENERATIO)));this->addChild(sp);sp->setPosition(p);}bool HelloNewBox2d::onTouchBegan(Touch* touch, Event* event){auto location = touch->getLocation();// 添加新的精灵addNewSpriteAtPosition(location);return true;}void HelloNewBox2d::onAcceleration(Acceleration* acc, Event* event){static float prevX = 0, prevY = 0;#define kFilterFactor 0.05ffloat accelX = (float)acc->x * kFilterFactor + (1 - kFilterFactor)*prevX;float accelY = (float)acc->y * kFilterFactor + (1 - kFilterFactor)*prevY;prevX = accelX;prevY = accelY;auto v = Vec2(accelX, accelY);v = v * 200;// 设置物理世界的重力this->getScene()->getPhysicsWorld()->setGravity(v);}



旧版本:

HelloBox2d.h:

#ifndef __HELLOBOX2D_H__#define __HELLOBOX2D_H__#include "cocos2d.h"#include "Box2D\Box2D.h"using namespace cocos2d;class HelloBox2d : public Layer{private:// 世界,可看做游戏世界b2World* _world;CCTexture2D* _spriteTexture;public:HelloBox2d();~HelloBox2d();// there's no 'id' in cpp, so we recommend returning the class instance pointerstatic Scene* createBox2dScene();// Here's a difference. Method 'init' in cocos2d-x returns bool, instead of returning 'id' in cocos2d-iphonevirtual bool init();// implement the "static create()" method manuallyCREATE_FUNC(HelloBox2d);void setSpriteTexture();// 初始化物理引擎设置void initPhysics();// 根据传入的数值进行更新virtual void update(float dt);virtual bool onTouchBegan(cocos2d::Touch* touch, cocos2d::Event* event);// 在指定位置添加精灵void addNewSpriteAtPosition(cocos2d::Vec2 p);};#endif // __HELLOWORLD_SCENE_H__

HelloBox2d.cpp:

#include "HelloBox2d.h"USING_NS_CC;#define PTM_RATIO 32Scene* HelloBox2d::createBox2dScene(){auto box2dScene = Scene::create();auto box2dLayer = HelloBox2d::create();box2dScene->addChild(box2dLayer);return box2dScene;}HelloBox2d::HelloBox2d():_world(NULL){}HelloBox2d::~HelloBox2d(){CC_SAFE_DELETE(_world);}bool HelloBox2d::init(){if (!Layer::init()){return false;}Size visibleSize = Director::getInstance()->getVisibleSize();Vec2 origin = Director::getInstance()->getVisibleOrigin();// 初始化物理引擎,并创建世界边界this->initPhysics();setTouchEnabled(true);// 设置为单点触摸  setTouchMode(Touch::DispatchMode::ONE_BY_ONE);// 利用时间调度器开始循环  scheduleUpdate();return true;}void HelloBox2d::initPhysics(){Size s = Director::getInstance()->getVisibleSize();// 重力参数,参数:1、水平方向,正值,重力向左;1、竖直方向,正值,重力向上b2Vec2 gravity;gravity.Set(0.0f, -10.0f);// 创建重力世界_world = new b2World(gravity);// 允许物体是否休眠_world->SetAllowSleeping(true);// 开启连续物理测试,防止物体会穿过另一个物体_world->SetContinuousPhysics(true);// 刚体,地面物体定义b2BodyDef groundBodyDef;// 左下角groundBodyDef.position.Set(0, 0);// 创建刚体,地面物体b2Body* groundBody = _world->CreateBody(&groundBodyDef);// 定义一个有边的形状,连接起来,可看做一个盒子b2EdgeShape groundBox;// 底部groundBox.Set(b2Vec2(0, 0), b2Vec2(s.width / PTM_RATIO, 0));// 使用夹具固定形状到物体上groundBody->CreateFixture(&groundBox, 0);// 顶部groundBox.Set(b2Vec2(0, s.height / PTM_RATIO), b2Vec2(s.width / PTM_RATIO, s.height / PTM_RATIO));groundBody->CreateFixture(&groundBox, 0);// 左边groundBox.Set(b2Vec2(0, s.height / PTM_RATIO), b2Vec2(0, 0));groundBody->CreateFixture(&groundBox, 0);// 右边groundBox.Set(b2Vec2(s.width / PTM_RATIO, s.height / PTM_RATIO), b2Vec2(s.width / PTM_RATIO, 0));groundBody->CreateFixture(&groundBox, 0);}void HelloBox2d::addNewSpriteAtPosition(Vec2 p){// 创建物理引擎精灵对象auto sprite = Sprite::create("blocks.png");sprite->setPosition(Vec2(p.x, p.y));this->addChild(sprite);// 物体定义b2BodyDef bodyDef;// 定义动态刚体类型bodyDef.type = b2_dynamicBody;bodyDef.position.Set(p.x / PTM_RATIO, p.y / PTM_RATIO);// 创建刚体b2Body *body = _world->CreateBody(&bodyDef);// 设置用户数据,辨别和调用创建好的刚体body->SetUserData(sprite);// 定义2米见方的盒子形状b2PolygonShape dynamicBox;dynamicBox.SetAsBox(.5f, .5f);// 夹具定义b2FixtureDef fixtureDef;//设置夹具的形状fixtureDef.shape = &dynamicBox;//设置密度fixtureDef.density = 1.0f;//设置摩擦系数fixtureDef.friction = 0.3f;//使用夹具固定形状到物体上body->CreateFixture(&fixtureDef);}void HelloBox2d::update(float dt){float timeStep = 0.03f;int32 velocityIterations = 8;int32 positionIterations = 1;// 引擎自己检查节点位置和速率,进行实时更新_world->Step(timeStep, velocityIterations, positionIterations);// 遍历世界中创建的刚体,不断更新刚体,即盒子的角度和位置for (b2Body* b = _world->GetBodyList(); b; b = b->GetNext()){if (b->GetUserData() != nullptr) {Sprite* sprite = (Sprite*)b->GetUserData();sprite->setPosition(Vec2(b->GetPosition().x *PTM_RATIO, b->GetPosition().y * PTM_RATIO));sprite->setRotation(-1 * CC_RADIANS_TO_DEGREES(b->GetAngle()));}}}bool HelloBox2d::onTouchBegan(cocos2d::Touch* touch, cocos2d::Event* event){auto loc = touch->getLocation();addNewSpriteAtPosition(loc);return true;}

效果图:



这里是源代码,由于文件过于庞大,只上传代码部分,复制覆盖项目即可,运行时,在AppDelegate.cpp文件中修改运用的场景即可,两个例子实现的功能一致。

auto box2dscene = HelloBox2d::createBox2dScene();auto newBox2dscene = HelloNewBox2d::createNewBox2dScene();// rundirector->runWithScene(newBox2dscene);
下载地址:http://download.csdn.net/detail/u013707014/9016823



HelloBox2d.cpp:
0 0