您的位置:首页 > 移动开发 > Cocos引擎

cocos2dx box2d使用(一)

2015-02-04 13:49 204 查看
本例子使用的是cocos2d-x 3.0版本

首先创建一个cocos2d的c++工程,这里就不多做说明了!本例子的项目名称是MyGame

其次,在MyGame的工程设置里Build Settings下,把CC_ENABLE_CHIPMUNK_INTEGRATION=1改为CC_ENABLE_BOX2D_INTEGRATION=1,同样把项目所引入的cocos2d的工程里改一下,但cocos2d的工程修改的地方有点特别!





如上图的工程,非target!

到此,box2d的环境已经设定好了!

现在工程已经创建完成了,环境也设定好了,下代码工程:





创建一个layer,用于放置所有的box2d对像和项目的精灵

其中的头文件如下:

//

// Box2dTest.h

// MyGame

//

// Created by Poche on 5/17/14.

//

//

#ifndef __MyGame__Box2dTest__

#define __MyGame__Box2dTest__

#include "cocos2d.h"

#include "Box2D/Box2D.h"

class Box2dTest : public cocos2d::Layer {

public:

Box2dTest();

virtual ~Box2dTest();

CREATE_FUNC(Box2dTest);

/**

*@brief初始化box2d测试layer,box2d世界是独立于cocos的scene的

*

*@Modified by poche at 2014-05-18 18:00:17

*

*@return是否初始化成功

**/

bool init();

/**

*@brief初始化box2d世界

*

*@Modified by poche at 2014-05-18 18:01:43

**/

void initWorld();

private:

b2World *m_world; ///
box2d世界

/// layer上的点击加调

CC_SYNTHESIZE_RETAIN(cocos2d::EventListenerTouchAllAtOnce*, m_touchListener,_touchListener);

public:

/**

*@brief添加精灵到指定坐标

*

*@Modified by poche at 2014-05-18 18:02:44

*@param point 坐标

**/

void AddSprite(cocos2d::Point point);

/**

*@brief每帧检查box2d物体并且更新cocos的精灵的状态(位置等)

*

*@Modified by poche at 2014-05-18 18:03:25

*@param dt 时间间隔

**/

void update(float dt);

/**

*@brief添加点击回调事件

*

*@Modified by poche at 2014-05-18 18:04:39

**/

void addLayerTouchListener();

/**

*@brief点击结束后的加调方法

*

*@Modified by poche at 2014-05-18 18:04:56

*@param touches 点击集合

*@param event 事件类型

**/

void touchesEnd(const std::vector<cocos2d::Touch*>
touches, cocos2d::Event *event);

virtual void onExit();

};

#endif /* defined(__MyGame__Box2dTest__) */

下面看一下.cpp的代码:

//

// Box2dTest.cpp

// MyGame

//

// Created by Poche on 5/17/14.

//

//

#include "Box2dTest.h"

USING_NS_CC;

/// 在box2d里,其用到的单位是现实中的单位,米等

/// 所以在游戏里,我们需要作出转换

/// 在cocos2d里,每32个像素就相当box2d里的一米

#define PTM_RATIO 32

const int tagSprite
= 1;

Box2dTest::Box2dTest()

: m_touchListener(NULL)

{

}

Box2dTest::~Box2dTest() {

CC_SAFE_RELEASE(m_touchListener);

/// 记得移除对像,要不然会泄露

delete m_world;

m_world = NULL;

}

bool Box2dTest::init()
{

/// 添加点击响应

addLayerTouchListener();

/// 初始化世界

initWorld();

return true;

}

void Box2dTest::initWorld()
{

auto size = Director::getInstance()->getWinSize();

/// 设置box2d世界重力方向

b2Vec2 gravity(0.0f,
-10.0f);

bool doSleep = true;

/// 生成box2d世界

m_world = new b2World(gravity);

/// 是否允许睡眠

m_world->SetAllowSleeping(doSleep);

m_world->SetContinuousPhysics(true);

/// 地表物体定义

b2BodyDef groundBodyDef;

/// 通过地表物体定义生成地表物体

b2Body* groundBody = m_world->CreateBody(&groundBodyDef);

/// 形状

b2PolygonShape groundBox;

/// 作为box形态布局

/// 第一个参数 物体的宽

/// 第二个参数 物体的高

/// 第三个参数 物体的位置

/// 第四个参数 物体中角度

/// 墙底

groundBox.SetAsBox(size.width / PTM_RATIO, 0, b2Vec2(0, 0), 0);

/// 把已经生成的物体放入世界中

/// 第一个参数 要放入的物体

/// 第二个参数 物体的质量

groundBody->CreateFixture(&groundBox, 0);

/// 墙顶

groundBox.SetAsBox(size.width / PTM_RATIO, 0, b2Vec2(0,
size.height / PTM_RATIO), 0);

groundBody->CreateFixture(&groundBox, 0);

/// 左墙

groundBox.SetAsBox(0,
size.height / PTM_RATIO, b2Vec2(0, 0), 0);

groundBody->CreateFixture(&groundBox, 0);

/// 左墙

groundBox.SetAsBox(0,
size.height / PTM_RATIO, b2Vec2(size.width / PTM_RATIO, 0), 0);

groundBody->CreateFixture(&groundBox, 0);

/// cocos2d里的精灵

auto brick = SpriteBatchNode::create("CloseNormal.png");

addChild(brick, 2, tagSprite);

/// 每帧对cocos2d的精灵更新

schedule(schedule_selector(Box2dTest::update));

}

void Box2dTest::AddSprite(cocos2d::Point point)
{

auto batch = (SpriteBatchNode*)getChildByTag(tagSprite);

auto sprite = Sprite::createWithTexture(batch->getTexture(), Rect(0,0,32,32));

batch->addChild(sprite);

sprite->setPosition(Point(point.x,
point.y));

/// 创建动态物体

/// 物体定义

b2BodyDef bodyDef;

/// 物体为动态物体

bodyDef.type = b2_dynamicBody;

/// 物体的位置

bodyDef.position.Set(point.x / PTM_RATIO,
point.y/ PTM_RATIO);

/// 将已经生成的精灵捆绑到物体上

bodyDef.userData = sprite;

/// 创建物体

b2Body * body = m_world->CreateBody(&bodyDef);

b2PolygonShape dynamicBox;

dynamicBox.SetAsBox(0.5f, 0.5f);

b2FixtureDef fixtureDef;

fixtureDef.shape = &dynamicBox;

/// 设置摩擦系数

fixtureDef.friction = 0.3f;

/// 设置密度

fixtureDef.density = 1.0;

body->CreateFixture(&fixtureDef);

}

void Box2dTest::update(float dt)
{

int velocityIterations = 8;

int positionIterations = 1;

//每次游戏循环你都应该调用b2World::Step

m_world->Step(dt,
velocityIterations, positionIterations);

for(b2Body*
b = m_world->GetBodyList();
b; b = b->GetNext())

{

if(b->GetUserData()
!= NULL)

{

/// 更新cocos2d对像

auto sprite = (Sprite*)b->GetUserData();

sprite->setPosition(Point(b->GetPosition().x * PTM_RATIO,
b->GetPosition().y * PTM_RATIO));

sprite->setRotation( -1 * CC_RADIANS_TO_DEGREES(b->GetAngle())
);

}

}

}

void Box2dTest::addLayerTouchListener()
{

set_touchListener(EventListenerTouchAllAtOnce::create());

get_touchListener()->onTouchesEnded = CC_CALLBACK_2(Box2dTest::touchesEnd, this);

_eventDispatcher->addEventListenerWithSceneGraphPriority(get_touchListener(), this);

}

void Box2dTest::onExit()
{

Layer::onExit();

unschedule(schedule_selector(Box2dTest::update));

_eventDispatcher->removeEventListener(get_touchListener());

}

void Box2dTest::touchesEnd(const std::vector<cocos2d::Touch *>
touches, cocos2d::Event *event)
{

for (auto&
touch : touches)

{

auto location = touch->getLocationInView();

location = Director::getInstance()->convertToGL(location);

AddSprite(location);

}

}

解释:

在这里要说说box2d中的单位,由于box2d中使用的是米作为长度单位。但在编程中,我们使用的图片都是使用像素作为基本单位。
凡是要向世界对象中添加物体的,都需要将像素单位转化为米单位。凡是要将世界对象中的物体显示在屏幕上时,要将物体的米单位转化为像素单位,在cocos2d里,大多用到的32个像素为一米,能否改就不得而知了!

SetAsBox 函数接收了半个宽度和半个高度,这样的话,地面盒就是 100 个单位宽(x 轴)以及 20 个单位高(y 轴)。Box2D 已被调谐使用米,千克和秒来作单位,所以你可以用米来考虑长度。然而, 改变单位系统是可能的。
内容来自用户分享和网络整理,不保证内容的准确性,如有侵权内容,可联系管理员处理 点击这里给我发消息
标签: