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();
可能是我的屌丝程序猿的冤孽直冲上天,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。