Cocos2d-x之物理引擎
| 版权声明:本文为博主原创文章,未经博主允许不得转载。
在很多的游戏设计中一般都会涉及和模拟到真实的物理世界。然而游戏中模拟真实世界的物理会很复杂。使用已经写好的物理引擎会用很大的帮助和便利。 Box2D的和Chipmunk是两个著名的物理引擎,在Cocos2d-x引擎中已经很好的集成它们。在Cocos2d-x v2的开发人员需要直接使用物理引擎。 Cocos2d-x提供了一个简单的类:CCPhysicsSprite,以帮助缩小使用差距,但对于其它元素的开发者需要直接调用物理引擎的API。
在Cocos2d-x V3+ 版本事情发生了变化。Cocos2d-x V3+ 版本集成了全新的物理引擎,基于Chipmunk的核心API。开发人员不再需要关心它的物理引擎将被用于或需要直接调用物理引擎的API。
这节我们将介绍一下Box2D物理引擎:
Box2D是一个用于游戏的2D刚体仿真库。Cocos2d-x程序员可以使用它在他们的游戏使物体的运动方式,使可信的游戏世界更互动。采用Box2D来模拟真实的物理世界的过程其实就是一句话:这个过程与上帝创建世界的过程类似,上帝首先创建了世界,然后在为世界指定了边界,否则万物就会掉到世界之外的混沌里去了,最后上帝在继续的创建了万物(这是网上的一句很适合形容Box2D创建物理世界的话)。
下面就根据上面的上帝创建世界的构成来创建游戏中的物理世界:
(1)、首先创建了世界(其实就是初始化物理世界,并且设置此物理世界的一些特性)
(2)、指定物理世界的边界
(3)、创建万物(即创建动态或者静态的Body)
(4)、当我们将上面的物理世界全部创建完之后,我们发现创建的刚体并不能运动。其实是我们没有更新刚体的位置。因此我们应该写一个定时器: update来时时更新Body的信息。
(5)、然后我们在初始化场景的init()函数中,启动定时器即可。下面解释上面的部分代码:
>.SetAllowSleeping():是否允许物体睡眠,休眠状态(true),可以提高物理世界中物体的处理效率,只在发生碰撞时才唤醒该对象。
>.gravity.Set(0.0f, -10.0f)是设置矢量值,其中(0.0f, -10.0f)表示只有重力作用物体,-10.0f表示沿着y轴向下,如果在x轴方向‘-’表示沿x轴向左。
>.world->SetContinuousPhysics(true):是开启连续物理测试,[开启连续物理测试,这是因为计算机只能把一段连续的时间分成许多离散的时间点,再对每个时间点之间的行为进行演算,如果时间点的分割不够细致,速度较快的两个物体碰撞时就可能会产生“穿透”现象,开启连续物理将启用特殊的算法来避免该现象。]。
代码 1:(动态物体自由落体运动)
HelloWorld.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
{
private:
b2World* world;
public:
static cocos2d::Scene* createScene(); virtual bool init(); virtual void update(float dt);
virtual bool onTouchBegan(cocos2d::Touch* touch, cocos2d::Event* event);
// implement the "static create()" method manually
CREATE_FUNC(HelloWorld); void initPhysics();
void createland();
void addNewSprite(cocos2d::Vec2 point);
}; #endif // __HELLOWORLD_SCENE_H__ HelloWorld.cpp #include "HelloWorldScene.h" USING_NS_CC; Scene* HelloWorld::createScene()
{
// 'scene' is an autorelease object
auto scene = Scene::create(); // 'layer' is an autorelease object
auto layer = HelloWorld::create(); // add layer as a child to scene
scene->addChild(layer); // return the scene
return scene;
} // on "init" you need to initialize your instance
bool HelloWorld::init()
{
//////////////////////////////
// 1. super init first
if ( !Layer::init() )
{
return false;
} auto visibleSize = Director::getInstance()->getVisibleSize();
Vec2 origin = Director::getInstance()->getVisibleOrigin(); auto sprite = Sprite::create("HelloWorld.png");
sprite->setPosition(Vec2(visibleSize.width/2 + origin.x, visibleSize.height/2 + origin.y));
this->addChild(sprite, 0); //初始化物理引擎
this->initPhysics();
this->createland(); setTouchEnabled(true);
setTouchMode(Touch::DispatchMode::ONE_BY_ONE);
//开始游戏循环
scheduleUpdate(); return true;
} void HelloWorld::initPhysics()
{
//重力参数
b2Vec2 gravity;
gravity.Set(0.0f, -9.8f);
//创建世界
world = new b2World(gravity);
//是否允许物体休眠
world->SetAllowSleeping(true);
//开启连续的物理测试
world->SetContinuousPhysics(true);
} void HelloWorld::addNewSprite(Vec2 point)
{
//创建物理引擎的精灵对象
auto sprite = Sprite::create("CloseNormal.png");
sprite->setPosition(Vec2(point.x, point.y));
this->addChild(sprite);
//刚体定义
b2BodyDef bodyDef;
bodyDef.type = b2_dynamicBody;
bodyDef.position.Set(point.x / PTM_RATIO,
point.y / PTM_RATIO);
b2Body* body = world->CreateBody(&bodyDef);
body->SetUserData(sprite);
//定义盒子
b2PolygonShape dynamicBox;
dynamicBox.SetAsBox(0.6, 0.6);
//夹具
b2FixtureDef fixtureDef;
//设置夹具的形状
fixtureDef.shape = &dynamicBox;
//设置密度
fixtureDef.density = 1.0f;
//设置摩擦系数
fixtureDef.friction = 0.3f;
//使用夹具固定形状到物体上
body->CreateFixture(&fixtureDef);
} void HelloWorld::update(float dt)
{
world->Step(dt, 8, 1);
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(0);
}
}
} bool HelloWorld::onTouchBegan(cocos2d::Touch* touch, cocos2d::Event* event)
{
Touch *t = touch;
Vec2 point = t->getLocationInView();
point = Director::getInstance()->convertToGL(point);
this->addNewSprite(point);
return false;
} void HelloWorld::createland()
{
Size s = Director::getInstance()->getVisibleSize();
//地面物体定义
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);
}
代码 2:(动态物体上升移动)
HelloWorld.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
{
protected:
b2World* world;
cocos2d::Sprite* sprite;
b2Body* body;
public:
static cocos2d::Scene* createScene(); virtual bool init(); virtual void update(float dt);
virtual bool onTouchBegan(cocos2d::Touch* touch, cocos2d::Event* event);
// implement the "static create()" method manually
CREATE_FUNC(HelloWorld); void initPhysics();
void createLand();
void addNewSprite();
}; #endif // __HELLOWORLD_SCENE_H__ HelloWorld.cpp #include "HelloWorldScene.h"
#include "SimpleAudioEngine.h" USING_NS_CC; Scene* HelloWorld::createScene()
{
// 'scene' is an autorelease object
auto scene = Scene::create(); // 'layer' is an autorelease object
auto layer = HelloWorld::create(); // add layer as a child to scene
scene->addChild(layer); // return the scene
return scene;
} // on "init" you need to initialize your instance
bool HelloWorld::init()
{
//////////////////////////////
// 1. super init first
if ( !Layer::init() )
{
return false;
} auto visibleSize = Director::getInstance()->getVisibleSize();
Vec2 origin = Director::getInstance()->getVisibleOrigin(); auto sprite = Sprite::create("HelloWorld.png");
sprite->setPosition(Vec2(visibleSize.width/2 + origin.x, visibleSize.height/2 + origin.y));
this->addChild(sprite, 0); //初始化物理引擎
this->initPhysics();
this->createLand();
addNewSprite();
setTouchEnabled(true);
setTouchMode(Touch::DispatchMode::ONE_BY_ONE);
//开始游戏循环
scheduleUpdate(); return true;
} void HelloWorld::initPhysics()
{
//重力参数
b2Vec2 gravity;
gravity.Set(0.0f, -9.8f); //创建世界
world = new b2World(gravity); //是否允许物体休眠
world->SetAllowSleeping(true);
//开启连续的物理测试
world->SetContinuousPhysics(true);
} void HelloWorld::addNewSprite()
{
//创建物理引擎的精灵对象
sprite = Sprite::create("CloseNormal.png");
sprite->setPosition((Director::getInstance()->getVisibleSize().width / 3) * 3,
Director::getInstance()->getVisibleSize().height);
this->addChild(sprite); //刚体定义
b2BodyDef bodyDef;
bodyDef.type = b2_dynamicBody;
bodyDef.position.Set(sprite->getPosition().x / PTM_RATIO,
sprite->getPosition().y / PTM_RATIO);
body = world->CreateBody(&bodyDef);
body->SetUserData(sprite); //定义2米见方的盒子
b2PolygonShape dynamicBox;
dynamicBox.SetAsBox(0.6, 0.6); //夹具
b2FixtureDef fixtureDef;
//设置夹具的形状
fixtureDef.shape = &dynamicBox;
//设置密度
fixtureDef.density = 1.0f;
//设置摩擦系数
fixtureDef.friction = 0.3f;
//使用夹具固定形状到物体上
body->CreateFixture(&fixtureDef);
} void HelloWorld::update(float dt)
{
world->Step(dt, 8, 1);
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(0);
}
}
} bool HelloWorld::onTouchBegan(cocos2d::Touch* touch, cocos2d::Event* event)
{
//Touch *t = touch;
//Vec2 point = t->getLocationInView();
//point = Director::getInstance()->convertToGL(point);
//点击一次屏幕,小球上升5个像素点
body->SetLinearVelocity(b2Vec2(0, 5)); return false;
} void HelloWorld::createLand()
{
Size s = Director::getInstance()->getVisibleSize(); //地面物体定义
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);
}
代码 3:(漂浮物体横向移动)
HelloWorld.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
{
protected:
b2World* world;
cocos2d::Sprite* sprite;
b2Body* body;
public:
static cocos2d::Scene* createScene(); virtual bool init(); virtual void update(float dt);
virtual bool onTouchBegan(cocos2d::Touch* touch, cocos2d::Event* event);
// implement the "static create()" method manually
CREATE_FUNC(HelloWorld); void initPhysics();
void createLand();
void addNewSprite();
}; #endif // __HELLOWORLD_SCENE_H__ HelloWorld.cpp #include "HelloWorldScene.h"
#include "SimpleAudioEngine.h" USING_NS_CC; Scene* HelloWorld::createScene()
{
// 'scene' is an autorelease object
auto scene = Scene::create(); // 'layer' is an autorelease object
auto layer = HelloWorld::create(); // add layer as a child to scene
scene->addChild(layer); // return the scene
return scene;
} // on "init" you need to initialize your instance
bool HelloWorld::init()
{
//////////////////////////////
// 1. super init first
if (!Layer::init())
{
return false;
} auto visibleSize = Director::getInstance()->getVisibleSize();
auto origin = Director::getInstance()->getVisibleOrigin(); auto sprite = Sprite::create("HelloWorld.png");
sprite->setPosition(Vec2(visibleSize.width / 2 + origin.x, visibleSize.height / 2 + origin.y));
this->addChild(sprite, 0); //初始化物理引擎
this->initPhysics();
this->createLand();
addNewSprite();
setTouchEnabled(true);
setTouchMode(Touch::DispatchMode::ONE_BY_ONE);
//开始游戏循环
scheduleUpdate(); return true;
} void HelloWorld::initPhysics()
{
//重力参数
b2Vec2 gravity;
gravity.Set(0.0f, -9.8f); //创建世界
world = new b2World(gravity); //是否允许物体休眠
world->SetAllowSleeping(true);
//开启连续的物理测试
world->SetContinuousPhysics(true);
} void HelloWorld::addNewSprite()
{
float offset = -rand() % 5;
auto visibleSize = Director::getInstance()->getVisibleSize();
auto origin = Director::getInstance()->getVisibleOrigin(); Sprite* down = Sprite::create("down.png");
down->setPosition(Vec2(visibleSize.width / 2, down->getContentSize().height));
down->setScaleY(0.5);
this->addChild(down);
b2BodyDef bodyDef;
bodyDef.position = b2Vec2(down->getPosition().x / PTM_RATIO, down->getPosition().y / PTM_RATIO);
bodyDef.type = b2_kinematicBody;
bodyDef.linearVelocity = b2Vec2(-2, 0);
b2Body* body = world->CreateBody(&bodyDef);
body->SetUserData(down);
b2PolygonShape shape1;
shape1.SetAsBox(down->getContentSize().width / 2 / PTM_RATIO, down->getContentSize().height / 2 / PTM_RATIO);
b2FixtureDef fixtureDef;
fixtureDef.shape = &shape1;
fixtureDef.density = 1.0f;
fixtureDef.friction = 1.0f;
body->CreateFixture(&fixtureDef); Sprite* up = Sprite::create("up.png");
up->setPosition(Vec2(visibleSize.width / 2, visibleSize.height - up->getContentSize().height));
up->setScaleY(0.5);
this->addChild(up); b2BodyDef upbodyDef;
upbodyDef.position=b2Vec2(up->getPosition().x / PTM_RATIO, up->getPosition().y / PTM_RATIO);
upbodyDef.type = b2_kinematicBody;
upbodyDef.linearVelocity = b2Vec2(-2, 0);
b2Body* body2 = world->CreateBody(&upbodyDef);
body2->SetUserData(up);
b2PolygonShape shape2;
shape2.SetAsBox(up->getContentSize().width / 2 / PTM_RATIO, up->getContentSize().height / 2 / PTM_RATIO);
b2FixtureDef fixtureDef2;
fixtureDef2.shape = &shape2;
body2->CreateFixture(&fixtureDef2);
} void HelloWorld::update(float dt)
{
world->Step(dt, 8, 1);
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(0);
}
}
} bool HelloWorld::onTouchBegan(cocos2d::Touch* touch, cocos2d::Event* event)
{
//Touch *t = touch;
//Vec2 point = t->getLocationInView();
//point = Director::getInstance()->convertToGL(point);
//点击一次屏幕,小球上升5个像素点
//body->SetLinearVelocity(b2Vec2(-5, 5));
addNewSprite(); return false;
} void HelloWorld::createLand()
{
Size s = Director::getInstance()->getVisibleSize(); //地面物体定义
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);
}
Cocos2d-x之物理引擎的更多相关文章
- [原创]cocos2d-x研习录-第三阶 特性之物理引擎
游戏物理引擎是指在游戏中涉及物理现象的逻辑处理,它用于模拟现实世界的各种物理规律(如赛车碰撞.子弹飞行.物体掉落等),让玩家能够在游戏中有真实的体验. Cocos2D-x中支持Box2D和Chipmu ...
- [Cocos2D-x For WP8]Box2D物理引擎
物理引擎通过为刚性物体赋予真实的物理属性的方式来计算运动.旋转和碰撞反映.为每个游戏使用物理引擎并不是完全必要的—简单的“牛顿”物理(比如加速和减速)也可以在一定程度上通过编程或编写脚本来实现.然而, ...
- Cocos2d-x3.2 使用物理引擎进行碰撞检测[转]
通常在游戏简单逻辑判断和模拟真实的物理世界时,我们只需要在定时器中判断游戏中各个精灵的条件是否满足判断条件就可以了.例如,在飞机大战中,判断我方子弹和敌机是否发生碰撞一般在定时器中通过敌机所在位置的矩 ...
- 实例介绍Cocos2d-x中Box2D物理引擎:碰撞检测
在Box2D中碰撞事件通过实现b2ContactListener类函数实现,b2ContactListener是Box2D提供的抽象类,它的抽象函数:virtual void BeginContact ...
- 实例介绍Cocos2d-x中Box2D物理引擎:HelloBox2D
我们通过一个实例介绍一下,在Cocos2d-x 3.x中使用Box2D物理引擎的开发过程,熟悉这些API的使用.这个实例运行后的场景如图所示,当场景启动后,玩家可以触摸点击屏幕,每次触摸时候,就会在触 ...
- 实例介绍Cocos2d-x物理引擎:碰撞检测
碰撞检测是使用物理引擎的一个重要目的,使用物理引擎可以进行精确的碰撞检测,而且执行的效率也很高.在Cocos2d-x 3.x中使用事件派发机制管理碰撞事件,EventListenerPhysicsCo ...
- 实例介绍Cocos2d-x物理引擎:HelloPhysicsWorld
我们通过一个实例介绍一下,在Cocos2d-x 3.x中使用物理引擎的开发过程,熟悉这些API的使用.这个实例的运行后的场景,当场景启动后,玩家可以触摸点击屏幕,每次触摸时候,就会在触摸点生成一个新的 ...
- Cocos2d-x3.2总结---使用物理引擎进行碰撞检测
[转自]: http://blog.csdn.net/cbbbc/article/details/38541099 通常在游戏简单逻辑判断和模拟真实的物理世界时,我们只需要在定时器中判断游戏中各个精灵 ...
- Cocos2d-x 使用物理引擎进行碰撞检测
[转自]: http://blog.csdn.net/cbbbc/article/details/38541099 通常在游戏简单逻辑判断和模拟真实的物理世界时,我们只需要在定时器中判断游戏中各个精灵 ...
- 大约cocos2d-X 3.x使用引擎版本自带的物理引擎Physics
今天打算用BOX2D物理引擎, 我想我以前听说过一些时间cocos2d-X在3.0版本封装自己的物理引擎Physics, 听名字很霸气量, 这的确是一个比BOX2D非常多( 毕竟是基于BOX2D封装的 ...
随机推荐
- 剑指offer学习--初级c++面试题
定义一个空的类型,里面没有任何成员函数和成员变量,对该类型求sizeof,得到的结果是多少? 答案是1.空类型中的实例中不包含任何信息,本来求sizeof应该是0,但是当我们声明该类型的实例的时候,他 ...
- jquery遍历获取带checkbox表格的选中值以及遍历json数组
今天整理了一下jquery遍历的两个用法,分享给大家. 1.$().each 主要用来遍历DOM元素,获取DOM的值或样式等. 2.$.each() 主要用来遍历后台ajax返回的json数组,循环将 ...
- mod_jk是Apache服务器的一个可插入模块
mod_jk简称JK,是Apache服务器的一个可插入模块,用以为Apache或IIS服务器提供处理JSP/Servlet的能力. Apache作为一款强大的Web服务器,本身缺乏处理JSP/Serv ...
- simple_pt时遇到的问题
elf.c:30:18: fatal error: gelf.h: No such file or directory 安装libelf-dev 遇到找不到ldwarf apt-cache sear ...
- shell PATH示例
- vue,一路走来(1)--构建vue项目
2016年12月--2017年5月,接触前端框架vue,一路走来,觉得有必要把遇到的问题记录下来. 那时,vux用的是1.0的vue,然而vue2.0已经出来了,于是我结合了mint-ui一起来做项目 ...
- mongodb 索引基础
一 .索引基础: MongoDB的索引几乎与传统的关系型数据库一模一样,这其中也包括一些基本的优化技巧.下面是创建索引的命令: > db.test.ensureIndex({&quo ...
- Linux ct6.5安装rabbitmq
yum install gcc glibc-devel make ncurses-devel openssl-devel xmlto 1.Erlang安装配置 下载安装包,地址http://www.e ...
- AGC003[BCDEF]题解
2018-12-28 有点累EF明天再写叭=v= 2018-12-29 update EF B - Simplified mahjong 可以注意到 一段连续的非0序列都可以凑出 就是显然%2=0的可 ...
- C# 创建日志
public void Log(string message) { try { string logFileName = "c:\\log\\LogName" + DateTime ...