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

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

2015-08-17 21:04 579 查看
这里讲两个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 pointer
static Scene* createNewBox2dScene();

// Here's a difference. Method 'init' in cocos2d-x returns bool, instead of returning 'id' in cocos2d-iphone
virtual bool init();

// implement the "static create()" method manually
CREATE_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/1024

Scene* 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.05f

float 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 pointer
static Scene* createBox2dScene();

// Here's a difference. Method 'init' in cocos2d-x returns bool, instead of returning 'id' in cocos2d-iphone
virtual bool init();

// implement the "static create()" method manually
CREATE_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 32

Scene* 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->Creat
4000
eFixture(&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();

// run
director->runWithScene(newBox2dscene);下载地址:http://download.csdn.net/detail/u013707014/9016823

HelloBox2d.cpp:
内容来自用户分享和网络整理,不保证内容的准确性,如有侵权内容,可联系管理员处理 点击这里给我发消息