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;
}
效果图:
![](https://img-blog.csdn.net/20150817211820267?watermark/2/text/aHR0cDovL2Jsb2cuY3Nkbi5uZXQv/font/5a6L5L2T/fontsize/400/fill/I0JBQkFCMA==/dissolve/70/gravity/Center)
这里是源代码,由于文件过于庞大,只上传代码部分,复制覆盖项目即可,运行时,在AppDelegate.cpp文件中修改运用的场景即可,两个例子实现的功能一致。
auto box2dscene = HelloBox2d::createBox2dScene();
auto newBox2dscene = HelloNewBox2d::createNewBox2dScene();
// run
director->runWithScene(newBox2dscene);下载地址:http://download.csdn.net/detail/u013707014/9016823
HelloBox2d.cpp:
关于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:
相关文章推荐
- 使用C++实现JNI接口需要注意的事项
- 关于指针的一些事情
- c++ primer 第五版 笔记前言
- share_ptr的几个注意点
- Lua中调用C++函数示例
- Lua教程(一):在C++中嵌入Lua脚本
- Lua教程(二):C++和Lua相互传递数据示例
- C++联合体转换成C#结构的实现方法
- C++编写简单的打靶游戏
- C++ 自定义控件的移植问题
- C++变位词问题分析
- C/C++数据对齐详细解析
- C++基于栈实现铁轨问题
- C++中引用的使用总结
- 使用Lua来扩展C++程序的方法
- C++中调用Lua函数实例
- Lua和C++的通信流程代码实例
- C与C++之间相互调用实例方法讲解
- C++ Custom Control控件向父窗体发送对应的消息
- C++中拷贝构造函数的应用详解