微信公众号搜"智元新知"关注
微信扫一扫可直接关注哦!

实例介绍Cocos2d-x中Box2D物理引擎:HelloBox2D

我们通过一个实例介绍一下,在Cocos2d-x 3.x中使用Box2D物理引擎的开发过程,熟悉这些API的使用。这个实例运行后的场景如图所示,当场景启动后,玩家可以触摸点击屏幕,每次触摸时候,就会在触摸点生成一个新的精灵,精灵的运行自由落体运动。




HelloBox2D实例
使用Box2D引擎进行开发过程,如图12-15所示。下面我们就按照这个步骤介绍一下代码部分。首先看一下看HelloWorldScene.h文件,它的代码如下:
[html] view plain copy
  1. #ifndef__HELLOWORLD_SCENE_H__
  2. #define__HELLOWORLD_SCENE_H__
  3. #include"cocos2d.h"
  4. #include"Box2D/Box2D.h"①
  5. #definePTM_RATIO32②
  6. classHelloWorld:publiccocos2d::Layer
  7. {
  8. b2World*world;③
  9. public:
  10. staticcocos2d::Scene*createScene();
  11. virtualboolinit();
  12. virtualvoidupdate(floatdt);④
  13. virtualboolonTouchBegan(cocos2d::Touch*touch,cocos2d::Event*event);⑤
  14. CREATE_FUNC(HelloWorld);
  15. voidinitPhysics();⑥
  16. voidaddNewSpriteAtPosition(cocos2d::Vec2p);⑦
  17. };
  18. #endif//__HELLOWORLD_SCENE_H__


上述第①行代码#include "Box2D/Box2D.h"是引入使用Box2D引擎需要头文件。第②行代码#define PTM_RATIO 32是定义宏PTM_RATIO,PTM_RATIO是屏幕上多少像素为1米,32表示屏幕上32像素表示1米,在Box2D中单位使用MKS公制系统,即:长度单位采用米,质量单位采用千克,时间单位采用秒。
代码第③行world是声明物理世界b2World成员变量。第④行代码是游戏循环函数。第⑤行代码是触摸点击响应函数。第⑥行代码是声明初始化物理引擎函数initPhysics。第⑦行是声明addNewSpriteAtPosition函数,是在触摸点创建一个精灵对象。
HelloWorldScene.cpp中HelloWorld::init()函数代码如下:
copy
    boolHelloWorld::init()
  1. {
  2. if(!Layer::init())
  3. returnfalse;
  4. }
  5. SizevisibleSize=Director::getInstance()->getVisibleSize();
  6. Vec2origin=Director::getInstance()->getVisibleOrigin();
  7. //初始化物理引擎
  8. this->initPhysics();①
  9. setTouchEnabled(true);
  10. //设置为单点触摸
  11. setTouchMode(Touch::dispatchMode::ONE_BY_ONE);
  12. //开始游戏循环
  13. scheduleUpdate();②
  14. returntrue;
  15. }

上述代码第①行调用initPhysics()函数初始化物理引擎。第②行代码scheduleUpdate()是开始游戏循环,一旦开启游戏循环就会回调HelloWorld::update(float dt)函数
HelloWorldScene.cpp中初始化物理引擎HelloWorld::initPhysics()函数代码如下:
copy
    voidHelloWorld::initPhysics()
  1. Sizes=Director::getInstance()- //重力参数
  2. b2Vec2gravity;①
  3. gravity.Set(0.0f,-10.0f);②
  4. //创建世界
  5. world=newb2World(gravity);③
  6. //允许物体是否休眠
  7. world->SetAllowSleeping(true);④
  8. //开启连续物理测试
  9. >SetContinuousPhysics(true);⑤
  10. //地面物体定义
  11. b2BodyDefgroundBodyDef;⑥
  12. //左下角
  13. groundBodyDef.position.Set(0,0);⑦
  14. //创建地面物体
  15. b2Body*groundBody=world->CreateBody(&groundBodyDef);⑧
  16. //定义一个有边的形状
  17. b2EdgeShapegroundBox;⑨
  18. //底部
  19. groundBox.Set(b2Vec2(0,0),b2Vec2(s.width/PTM_RATIO,0));⑩
  20. //使用夹具固定形状到物体上
  21. groundBody->CreateFixture(&groundBox,0);⑪
  22. //顶部
  23. b2Vec2(s.width/PTM_RATIO,s.height/PTM_RATIO));
  24. //左边
  25. //右边
  26. groundBox.Set(b2Vec2(s.width/PTM_RATIO,0));
  27. 代码第①行b2Vec2 gravity是声明重力变量,b2Vec2是一个二维矢量,它的两个属性为浮点数x和y,表示在x轴和y轴方向的矢量。第②行代码gravity.Set(0.0f,-10.0f)是设置矢量值,其中(0.0f,-10.0f)表示只有重力作用物体,-10.0f表示沿着y轴向下。
    第③行代码world = new b2World(gravity)是创建物理世界b2World对象,这里采用了new创建物理世界对象,在C++中new关键字分配内存,释放内存是delete关键字。World是成员变量,需要自己释放成员变量一般是在析构函数中释放,代码如下:
    HelloWorld::~HelloWorld()
    {
    CC_SAFE_DELETE(world);
    }
    其中CC_SAFE_DELETE(world)是安全释放world变量,CC_SAFE_DELETE宏代表安全释放内存。
    第④行代码world->SetAllowSleeping(true)是允许物体睡眠与否,如果允许休眠,可以提高物理世界中物体的处理效率,只有在发生碰撞时才唤醒该对象。
    第⑤行代码world->SetContinuousPhysics(true)是开启连续物理测试[ 开启连续物理测试,这是因为计算机只能把一段连续的时间分成许多离散的时间点,再对每个时间点之间的行为进行演算,如果时间点的分割不够细致,速度较快的两个物体碰撞时就可能会产生“穿透”现象,开启连续物理将启用特殊的算法来避免该现象。]。
    第⑥行代码是声明形状定义(b2BodyDef)变量。第⑦行代码groundBodyDef.position.Set(0,0)是设置形状的位置。第⑧行代码b2Body* groundBody = world->CreateBody(&groundBodyDef)是通过形状定义变量groundBodyDef创建地面物体。
    第⑨行代码是声明一个有边形状定义b2EdgeShape变量,第⑩行代码groundBox.Set(b2Vec2(0,0))是设置有边形状的开始位置(0,0)和结束位置(s.width/PTM_RATIO,0),s.width/PTM_RATIO是将像素换算成米。第⑪行代码是使用夹具固定形状到物体上。用类似的函数定义顶部、左边和右边的物体。
    HelloWorldScene.cpp中创建精灵HelloWorld::addNewSpriteAtPosition函数代码如下:
    copy
    voidHelloWorld::addNewSpriteAtPosition(Vec2p)
  1. log("Addsprite%0.2fx%02.f",p.x,p.y);
  2. //创建物理引擎精灵对象
  3. autosprite=Sprite::create("BoxA2.png");①
  4. sprite->setPosition(Vec2(p.x,p.y));
  5. this->addChild(sprite);
  6. //物体定义
  7. b2BodyDefbodyDef;②
  8. bodyDef.type=b2_dynamicBody;③
  9. bodyDef.position.Set(p.x/PTM_RATIO,p.y/PTM_RATIO);④
  10. b2Body*body=world->CreateBody(&bodyDef);⑤
  11. body->SetUserData(sprite);⑥
  12. //定义2米见方的盒子形状
  13. b2polygonShapedynamicBox;⑦
  14. dynamicBox.SetAsBox(1,1);⑧
  15. //夹具定义
  16. b2FixtureDeffixtureDef;⑨
  17. //设置夹具的形状
  18. fixtureDef.shape=&dynamicBox;⑩
  19. //设置密度
  20. fixtureDef.density=1.0f;⑪
  21. //设置摩擦系数
  22. fixtureDef.friction=0.3f;⑫
  23. body->CreateFixture(&fixtureDef);⑬
  24. 上述代码第①行是创建精灵(Sprite)对象,精灵(Sprite)对象与物理引擎物体是没有关系,我们需要在游戏循环函数中更新。
    代码第②行是声明动态物体定义变量,代码第③行bodyDef.type = b2_dynamicBody是设置物体类型为动态物体,物体分为静态和动态物体。第④行代码是设置物体的位置,它的单位是米。第⑤行代码b2Body *body = world->CreateBody(&bodyDef)是创建物体对象。第⑥行代码body->SetUserData(sprite)是将精灵放置到物体的UserData属性中,这样便于我们从物体中获取相关联的物体。
    第⑦行代码b2polygonShape dynamicBox是声明多边形形状定义变量。第⑧行代码dynamicBox.SetAsBox(1,1)是设置多边形为矩形盒子形状,由于坐标原点在盒子的左下角,SetAsBox是设置盒子的中心为(1,1),那么这个盒子的就是2米见方的大小。
    第⑨行代码是b2FixtureDef fixtureDef是声明夹具定义变量。第⑩行代码是设置夹具的形状。第⑪行代码fixtureDef.density = 1.0f是设置形状的密度。第⑫行代码fixtureDef.friction = 0.3f是设置摩擦系数,范围是0.0~1.0之间。第⑬行代码body->CreateFixture(&fixtureDef) 是使用夹具固定形状到物体上,这样物体就有了形状。
    HelloWorldScene.cpp中游戏循环函数HelloWorld::update代码如下:
    copy
      voidHelloWorld::update(floatdt)
    1. floattimestep=0.03f;
    2. int32veLocityIterations=8;
    3. int32positionIterations=1;
    4. world->Step(timestep,veLocityIterations,positionIterations);
    5. for(b2Body*b=world->GetBodyList();b;b=b->GetNext())①
    6. if(b->GetUserData()!=nullptr){
    7. Sprite*sprite=(Sprite*)b->GetUserData();
    8. sprite->setPosition(Vec2(b->GetPosition().x*
    9. PTM_RATIO,b->GetPosition().y*PTM_RATIO));
    10. >setRotation(-1*CC_radians_TO_degrees(b->GetAngle()));
    11. }②
    12. }

    其中代码①~②这段代码可以同步物理引擎中的物体与精灵位置和状态。

    原文地址:https://www.jb51.cc/cocos2dx/346829.html

    版权声明:本文内容由互联网用户自发贡献,该文观点与技术仅代表作者本人。本站仅提供信息存储空间服务,不拥有所有权,不承担相关法律责任。如发现本站有涉嫌侵权/违法违规的内容, 请发送邮件至 dio@foxmail.com 举报,一经查实,本站将立刻删除。

    相关推荐