出处:https://www.evernote.com/shard/s262/sh/bf561bda-0458-4502-835b-903846f81d68/68e6634bddec74c5a2d5f8dd839eba0a
本例子使用的是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
已被调谐使用米,千克和秒来作单位,所以你可以用米来考虑长度。然而,
改变单位系统是可能的。
cocos2dx box2d使用(一),布布扣,bubuko.com