cocos2d-x 3.2 物理世界PhysicsWorld

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,功能小测试)