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

cocos2d-x 3.2 物理世界PhysicsWorld

2014-07-02 16:26 169 查看
cocos2d-x-3.2alpha0的物理世界。

hello  大家好,小弟这厢有礼了,我又来写博客了,cocos2d-x果然越来越人性话了。

看一看创建物理世界:

//创建一个物理场景

auto scene =Scene::createWithPhysics(); 

//设置物理世界的重力

scene->getPhysicsWorld()->setGravity(Vect(0,-(Director::getInstance()->getVisibleSize().height/3)));

//边界盒

auto edge=PhysicsBody::createEdgeBox(visibleSize);

对照一下cocos2d-x 2.2.3的Box2D

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);
groundBody->SetType(b2_staticBody);

b2EdgeShape groundBox;      //定义地面盒形状

//2个点确定一条线,以下分别设置了屏幕的4个边
// bottom
groundBox.Set(b2Vec2(0, 0), b2Vec2(480/PTM_RATIO, 0));
groundBody->CreateFixture(&groundBox,0);

// top
groundBox.Set(b2Vec2(0 ,320/PTM_RATIO), b2Vec2(480/PTM_RATIO,320/PTM_RATIO));
groundBody->CreateFixture(&groundBox,0);

// left
groundBox.Set(b2Vec2(0, 320/PTM_RATIO), b2Vec2(0 ,0));
groundBody->CreateFixture(&groundBox,0);

// right
groundBox.Set(b2Vec2(480/PTM_RATIO, 320/PTM_RATIO), b2Vec2(480/PTM_RATIO, 0));
groundBody->CreateFixture(&groundBox,0);

CCSpriteBatchNode *blocks=CCSpriteBatchNode::create("blocks.png",100);
texture=blocks->getTexture();


当然这是Box2D ,强大的box2d几乎模拟一切,不过当初写的我想杀人,明明很简单的东西完全交给我,一点不封装,蛋疼。

可能是我的屌丝程序猿的冤孽直冲上天,3.2版本那叫一个简单明了,我先把整个源码粘上来,然后再说。

#ifndef __PHYSICS_SCENE_H__
#define __PHYSICS_SCENE_H__

#include "cocos2d.h"

class PhysicsScene : public cocos2d::Layer
{
public:
// there's no 'id' in cpp, so we recommend returning the class instance pointer
static cocos2d::Scene* createScene();

// 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(PhysicsScene);

void createPhysicsSpriteWithPosition(cocos2d::Vec2 position);
};

#endif // __PHYSICS_SCENE_H__


#include "PhysicsScene.h"
#include "cocos2d.h"
USING_NS_CC;

enum MyType
{
attacker=1,
SB=2
};

Scene* PhysicsScene::createScene()
{

//很明显   创建一个物理场景
auto scene =Scene::createWithPhysics();
auto layer = PhysicsScene::create();

//显不显示物理节点的外框  调试时用
scene->getPhysicsWorld()->setDebugDrawMask(PhysicsWorld::DEBUGDRAW_ALL);

//设置物理世界的重力
scene->getPhysicsWorld()->setGravity(Vect(0,-(Director::getInstance()->getVisibleSize().height/3)));

scene->addChild(layer);

//创建一个物理碰撞的事件处理
auto physicsListen=EventListenerPhysicsContact::create();
physicsListen->onContactBegin=[](PhysicsContact& contact)->bool
{

//contact.getShapeB()->getBody()->getNode()->removeFromParent();
if(contact.getShapeA()->getBody()->getNode()!=nullptr||contact.getShapeB()->getBody()->getNode()!=nullptr)
{
if(contact.getShapeA()->getBody()->getNode()->getTag()==MyType::attacker)
{
//移除节点前先把mask设为0
contact.getShapeB()->getBody()->setContactTestBitmask(0);
contact.getShapeB()->getBody()->getNode()->removeFromParent();
//碰撞效果消失  不计算后续的碰撞
return false;
}

if (contact.getShapeB()->getBody()->getNode()->getTag()==MyType::attacker)
{
contact.getShapeA()->getBody()->setContactTestBitmask(0);
contact.getShapeA()->getBody()->getNode()->removeFromParent();
//碰撞效果消失  不计算后续的碰撞
return false;
}
}

//默认碰撞
return true;
};

//注册事件处理程序
Director::getInstance()->getEventDispatcher()->addEventListenerWithSceneGraphPriority(physicsListen,scene);

return scene;
}

bool PhysicsScene::init()
{

if ( !Layer::init() )
{
return false;
}

Size visibleSize = Director::getInstance()->getVisibleSize();
Vec2 origin = Director::getInstance()->getVisibleOrigin();

//边界盒
auto edge=PhysicsBody::createEdgeBox(visibleSize);

//是按父节点的坐标原点来的  一个偏移量
edge->setPositionOffset(visibleSize/2);

//添加边界
this->setPhysicsBody(edge);

//触摸事件处理
auto listen=EventListenerTouchOneByOne::create();
listen->onTouchBegan=[this](Touch * touch,Event * event)->bool
{
this->createPhysicsSpriteWithPosition(touch->getLocation());
return true;
};

//注册
Director::getInstance()->getEventDispatcher()->addEventListenerWithSceneGraphPriority(listen,this);

return true;
}

void PhysicsScene::createPhysicsSpriteWithPosition(cocos2d::Vec2 position)
{

//建的玩的
auto p=LayerColor::create(Color4B::BLUE,40,40);
p->ignoreAnchorPointForPosition(false);
p->setPosition(position);
auto body=PhysicsBody::createBox(CCSizeMake(40,40));

//物理节点默认就是按父节点的原点为中心点来的
p->setPhysicsBody(body);

srand(time(NULL));
p->setTag(rand()%2==0?MyType::attacker:MyType::SB);
auto label=Label::create(p->getTag()==MyType::attacker?"NB":"SB","Arial",20);
label->setPosition(20,20);
p->addChild(label);

//这句话困了我一个点
body->setContactTestBitmask(-1);
this->addChild(p);

}


其实真的很简单很方便

step 1:

//创建一个物理场景

auto scene =Scene::createWithPhysics(); 

//设置物理世界的重力

scene->getPhysicsWorld()->setGravity(Vect(0,-(Director::getInstance()->getVisibleSize().height/3)));

step  2:

创建一个边界盒,关联到一个节点上然后加到物理场景中。

step  3:

创建一个node关联一个body就是刚体,然后看他们撞的玩吧

最最最基本的就是这些,如果你想要自己处理碰撞的话那么

step 4:

//创建一个物理碰撞的事件处理

auto physicsListen=EventListenerPhysicsContact::create();

physicsListen->onContactBegin 自己写自己的处理方法,

contact.getShapeA()->getBody()->getNode();

contact.getShapeB()->getBody()->getNode();

可以得到两个碰撞的节点,(天真我以为撞人的是A,被撞的是B,但是我太天真了,尼玛复杂的物理世界,真心不知道谁是A谁是B,setTag才是王道啊)

返回值为true继续默认碰撞处理,false这次碰撞的处理到此结束。

到这里有一个天大的事情出现了,碰撞时竟然不触发我自己写的处理程序,擦有没有搞错

,耍我研究了一个小时(其实大部分时间在发呆)终于找到罪魁祸首了,

body->setContactTestBitmask(-1);

ContactTestBitmask表示“在我和谁发生碰撞通知我”,默认为值0,这是一个位mask,-1对应的是FFFFFFFF(各种11111.)全开,不管碰到什么都要通知我



既然我不能通过A,B来判断谁是谁那怎么办,setTag出马了,你自己设置,自己判断去吧,比如(猪脚/敌人,子弹/敌人,障碍/敌人   敌人各种躺枪)。

今天就这么点东西了,准备写个Flappy brid。
内容来自用户分享和网络整理,不保证内容的准确性,如有侵权内容,可联系管理员处理 点击这里给我发消息
标签:  cocos2d-x cocos2dx