码迷,mamicode.com
首页 > 其他好文 > 详细

Box2D详解2 碰撞筛选

时间:2014-05-21 16:43:06      阅读:350      评论:0      收藏:0      [点我收藏+]

标签:box2d   cocos2d学习   游戏引擎   

Box2D详解2 碰撞筛选

DioysosLai 2014-5-20

相信玩过游戏的人都知道,己方英雄释放的技能只能对敌方英雄有伤害,而不能伤害到己方英雄(要是能伤害到自己人,那不是坑爹啊!)在一些小游戏中,如果涉及到这些设置,一方面我们可以自己进行碰撞过滤,另一方面,如果我们使用到了Box2D,那么,我们就可以使用Box2D自带的碰撞过滤(Collision filtering),通过三个标志位实现碰撞过滤:

类别标志位(categoryBits)、遮罩标志位(maskBits)、分组索引(groupIndex)。

 

类别标志位和遮罩标志位解释:

所谓类别标志位,就是指明对象类型,即告诉别人“我是谁”。所谓遮罩标志位,就是致命碰撞对象,即告诉别人“我想和谁发生碰撞”。

例如《猫抓老鼠》类型游戏,猫的类型就是“猫”,遮罩标志位就是“猫|老鼠”。老鼠类型是“老鼠”,其遮罩标志位就是“猫|老鼠”。这样,猫和老鼠可以互相发生碰撞。但,有一点要指明就是,二者的碰撞必须是“你情我愿”。如果猫的遮罩标志位是“猫|老鼠”,即猫想和老鼠碰撞,但如果老鼠的遮罩标志位是“老鼠”(注意:这里没有“猫”),即老鼠不想和猫发生碰撞,那么老鼠和猫最终结果是不能发生碰撞的。

    具体来说,我们可以用一段代码来表示这种“你情我愿”的关系:

bool collide = (filterCat.maskBits & filterMouse.categoryBits) != 0 &&
          (filterCat.categoryBits & filterMouse.maskBits) != 0;

在默认情况下,类别标志位值为0x0001,遮罩标志位默认值为0xFFFF,即默认,我们创建的任何对象,都是“I am the god, I can collision with everything!”。如果,所以对象我们都没改变其类别标志位和遮罩标志位,那么,所有对象默认都是可以互相碰撞的。

 

如何设置类别标志位和遮罩标志位:

每一个标志位是一个16位的整数,因此我们可以设置16种不同的碰撞类型。具体方法,可以先设置我们要设置物理世界对象类型:

enum CABOX2DMASK 
	{
		BOX2D_MASK_WORD		= 0X0001,	///< 世界
		BOX2D_MASK_BALL		= 0x0002,	///< 球
		BOX2D_MASK_BASKET	= 0x0004,	///< 球框
		…			= 0x0008,	///< …	
		…
		…
	};

然后,我们在初始化我们世界对象时,可以更根据要求来设置对象的类别标志位和遮罩标志位。

例如如下代码:

// Create ball body and shape 创建球的body
b2Body *body;

b2BodyDef ballBodyDef;
ballBodyDef.type = b2_dynamicBody;	///< 指定body的类型为dynamic body。默认值是static body,那意味着那个body不能被移动也不会参与仿真。
ballBodyDef.position.Set(BALLPOSITION[m_baBall[i].size].x/PTM_RATIO, BALLPOSITION[m_baBall[i].size].y/PTM_RATIO);
ballBodyDef.userData = m_baBall[i].ball;		///< 设置body的user data属性为篮球精灵。可以设置任何东西,但是,你设置成精灵会很方便,特别是当两个body碰撞的时候,你可以通过这个参数把精灵对象取出来,然后做一些逻辑处理。
body = m_world->CreateBody(&ballBodyDef);

b2CircleShape circle;
circle.m_radius = m_baBall[i].ball->getWidth()/2.0f/PTM_RATIO;

b2FixtureDef ballShapeDef;
ballShapeDef.shape = &circle;
<strong>ballShapeDef.filter.categoryBits<span style="white-space:pre">	</span>= BOX2D_MASK_BALL;
ballShapeDef.filter.maskBits<span style="white-space:pre">		</span>= BOX2D_MASK_WORD | BOX2D_MASK_BALL ;</strong>
ballShapeDef.density = 1.0f;		///< 单位体积的质量(密度)。因此,一个对象的密度越大,那么它就有更多的质量,当然就会越难以移动. 
ballShapeDef.friction = 0.2f;		///< 就是摩擦力。它的范围是0-1.0, 0意味着没有摩擦,1代表最大摩擦,几乎移不动的摩擦。	
ballShapeDef.restitution = 0.5f;		///< 回复力。它的范围也是0到1.0. 0意味着对象碰撞之后不会反弹,1意味着是完全弹性碰撞,会以同样的速度反弹。
body->CreateFixture(&ballShapeDef);

这里我们设置我们的对象为“我是一个BOX2D_MASK_BALL”, 我可以和“BOX2D_MASK_WORD| BOX2D_MASK_BALL ”发生碰撞。

 

如何动态改变类别标志位和遮罩标志位:

在很多情况下,我们的世界对象达到某个条件时,我们要改变其类别标志位和遮罩标志位。那么,我们要首先获取这个世界对象的内容,然后在该别其值。具体方法,可以参考如下:

for (b2Body *b = m_world->GetBodyList(); b; )
{
	///遍历world对象里面的所有body,然后看body的user data属性是否为空,如果不为空,就可以强制转换成精灵对象。接下来,就可以根据body的位置来更新精灵的位置了。
	if (b->GetUserData() != NULL)
	{
		b2Body* b2node = b;
		b = b2node->GetNext();
		boxSprite* ballData = (boxSprite*)b2node->GetUserData();
		if (ballData->getDead())	///< 改变对象类别、遮罩标志位
		{
<strong>			b2Fixture* fixture = b2node->GetFixtureList();
			b2Filter filter = fixture->GetFilterData();
			//change whatever you need to, eg.
			filter.categoryBits	= BOX2D_MASK_BASKET;
			filter.maskBits		= BOX2D_MASK_WORD | BOX2D_MASK_BASKET ;
			fixture->SetFilterData(filter);	
</strong>			ballData->setDead(false);	
		}
		
		ballData->setPosition(ccp(b2node->GetPosition().x*PTM_RATIO, 
			b2node->GetPosition().y*PTM_RATIO));
		ballData->setRotation(-1*CC_RADIANS_TO_DEGREES(b2node->GetAngle()));
	}
	else
	{
		b = b->GetNext();
	}
}

 

具体,类别标志位和遮罩标志位的功能,就差不多是这样了。

分组索引:

分组索引优先于类别和遮罩标志位,具体作用如下:

-定制器如果有分组索引为零,那么使用分类/遮罩规则 
-如果两个分组索引的值不为零并且不相同,那么使用分类/遮罩规则 
-如果两个分组索引的值相同,并且为正数,则产生碰撞 
-如果两个分组索引的值相同,并且为负数,则不产生碰撞

我们设置对象时,对象的分组索引默认为0。

 

好的,Box2D的碰撞过滤,就差不多是这样的。希望对大家有点用处。下面是我的qq:906391500,欢迎大家一起交流,一起成长。







Box2D详解2 碰撞筛选,布布扣,bubuko.com

Box2D详解2 碰撞筛选

标签:box2d   cocos2d学习   游戏引擎   

原文地址:http://blog.csdn.net/dionysos_lai/article/details/26374517

(0)
(0)
   
举报
评论 一句话评论(0
登录后才能评论!
© 2014 mamicode.com 版权所有  联系我们:gaon5@hotmail.com
迷上了代码!