zoukankan      html  css  js  c++  java
  • 实例介绍Cocos2d-x中Box2D物理引擎:HelloBox2D

    我们通过一个实例介绍一下。在Cocos2d-x 3.x中使用Box2D物理引擎的开发过程,熟悉这些API的使用。

    这个实例执行后的场景如图所看到的,当场景启动后,玩家能够触摸点击屏幕,每次触摸时候。就会在触摸点生成一个新的精灵,精灵的执行自由落体运动。


      



    HelloBox2D实例
    使用Box2D引擎进行开发过程,如图12-15所看到的。以下我们就依照这个步骤介绍一下代码部分。首先看一下看HelloWorldScene.h文件。它的代码例如以下:
    #ifndef __HELLOWORLD_SCENE_H__
    #define __HELLOWORLD_SCENE_H__
    
    
    #include "cocos2d.h"
    #include "Box2D/Box2D.h"												①
    
    
    #define PTM_RATIO 32													②
    
    
    class HelloWorld : public cocos2d::Layer
    {
    	b2World* world;														③
    
    
    public:
        static cocos2d::Scene* createScene();
        virtual bool init();  
    
    
    	virtual void update(float dt);												④
    	virtual bool onTouchBegan(cocos2d::Touch* touch, cocos2d::Event* event); 			⑤
    
    
        CREATE_FUNC(HelloWorld);
    	
    	void initPhysics();														⑥
    	void addNewSpriteAtPosition(cocos2d::Vec2 p);								⑦
    
    
    };
    
    
    #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()函数代码例如以下:

    bool HelloWorld::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;
    }


    上述代码第①行调用initPhysics()函数初始化物理引擎。第②行代码scheduleUpdate()是開始游戏循环,一旦开启游戏循环就会回调HelloWorld::update(float dt)函数。
    HelloWorldScene.cpp中初始化物理引擎HelloWorld::initPhysics()函数代码例如以下:
    void HelloWorld::initPhysics()
    {
    	Size s = Director::getInstance()->getVisibleSize();
    	
    	//重力參数
    	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);									
    
    
    }


    代码第①行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++中newkeyword分配内存,释放内存是deletekeyword。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), b2Vec2(s.width/PTM_RATIO,0))是设置有边形状的開始位置(0,0)和结束位置(s.width/PTM_RATIO,0)。s.width/PTM_RATIO是将像素换算成米。第⑪行代码是使用夹具固定形状到物体上。

    用相似的函数定义顶部、左边和右边的物体。
    HelloWorldScene.cpp中创建精灵HelloWorld::addNewSpriteAtPosition函数代码例如以下:

    void HelloWorld::addNewSpriteAtPosition(Vec2 p)
    {    
    	log("Add sprite %0.2f x %02.f",p.x,p.y);
    
    
    	//创建物理引擎精灵对象
    	auto sprite = Sprite::create("BoxA2.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(1, 1);											⑧
    
    
    	// 夹具定义
    	b2FixtureDef fixtureDef;												⑨
    	//设置夹具的形状
    	fixtureDef.shape = &dynamicBox;											⑩
    	//设置密度
    	fixtureDef.density = 1.0f;												⑪
    	//设置摩擦系数
    	fixtureDef.friction = 0.3f;												⑫
    	//使用夹具固定形状到物体上	
    	body->CreateFixture(&fixtureDef);										⑬
    
    
    }


    上述代码第①行是创建精灵(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代码例如以下:

    void HelloWorld::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()) );
    		}
    	}																			②
    }


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



    很多其它内容请关注最新Cocos图书《Cocos2d-x实战 C++卷》
    本书交流讨论站点:http://www.cocoagame.net
    很多其它精彩视频课程请关注智捷课堂Cocos课程:http://v.51work6.com
    欢迎增加Cocos2d-x技术讨论群:257760386


    《Cocos2d-x实战 C++卷》现已上线,各大商店均已开售:

    京东:http://item.jd.com/11584534.html

    亚马逊:http://www.amazon.cn/Cocos2d-x%E5%AE%9E%E6%88%98-C-%E5%8D%B7-%E5%85%B3%E4%B8%9C%E5%8D%87/dp/B00PTYWTLU

    当当:http://product.dangdang.com/23606265.html

    互动出版网:http://product.china-pub.com/3770734

    《Cocos2d-x实战 C++卷》源代码及样章下载地址:

    源代码下载地址:http://51work6.com/forum.php?mod=viewthread&tid=1155&extra=page%3D1 

    样章下载地址:http://51work6.com/forum.php?mod=viewthread&tid=1157&extra=page%3D1

    欢迎关注智捷iOS课堂微信公共平台

  • 相关阅读:
    Java实现 LeetCode 450 删除二叉搜索树中的节点
    PHP mysqli_field_count() 函数
    PHP mysqli_fetch_row() 函数
    PHP mysqli_fetch_object() 函数
    PHP mysqli_fetch_lengths() 函数
    PHP mysqli_fetch_fields() 函数
    linux修改IP地址
    树莓派玩耍笔记2 -- 我的板子是正品么?(解答一些小问题)
    在一台server上部署多个Tomcat
    第十八篇:融汇贯通--谈USB Video Class驱动
  • 原文地址:https://www.cnblogs.com/brucemengbm/p/7253912.html
Copyright © 2011-2022 走看看