Box2D详解2 碰撞筛选

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,欢迎大家一起交流,一起成长。







  • 2
    点赞
  • 2
    收藏
    觉得还不错? 一键收藏
  • 1
    评论
Box2DCocos2D是两个游戏开发框架。Box2D是一个用于物理模拟的开源库,可以模拟刚体的运动和碰撞等物理效果。Cocos2D是一个用于2D游戏开发的跨平台框架,提供了丰富的图形渲染和用户交互功能。\[1\] 在使用Cocos2DBox2D进行游戏开发时,你可以利用Box2D来处理游戏中的物理效果,比如重力、碰撞和刚体运动等。Cocos2D提供了与Box2D的集成,使得开发者可以方便地在Cocos2D中使用Box2D的功能。你可以通过创建物理世界、添加刚体和设置碰撞检测等来实现游戏中的物理效果。\[2\] 如果你刚刚接触Cocos2DBox2D,建议你先学习Cocos2DBox2D的基础知识,然后再深入学习如何在Cocos2D中使用Box2D。你可以参考一些入门教程,比如《Cocos2D入门》和《Box2D入门》。如果你对OpenGL ES 2.0和自定义Cocos2D 2.X着色器等背景知识感到困惑,你可以查阅相关教程来获取更多的帮助。\[3\] #### 引用[.reference_title] - *1* *3* [如何使用Box2DCocos2D制作一款像Fruit Ninja一样的游戏-第1部分](https://blog.csdn.net/kaka626/article/details/9397825)[target="_blank" data-report-click={"spm":"1018.2226.3001.9630","extra":{"utm_source":"vip_chatgpt_common_search_pc_result","utm_medium":"distribute.pc_search_result.none-task-cask-2~all~insert_cask~default-1-null.142^v91^insert_down1,239^v3^insert_chatgpt"}} ] [.reference_item] - *2* [用Box2Dcocos2d-x制作弹弓类游戏](https://blog.csdn.net/qq55008307/article/details/8090839)[target="_blank" data-report-click={"spm":"1018.2226.3001.9630","extra":{"utm_source":"vip_chatgpt_common_search_pc_result","utm_medium":"distribute.pc_search_result.none-task-cask-2~all~insert_cask~default-1-null.142^v91^insert_down1,239^v3^insert_chatgpt"}} ] [.reference_item] [ .reference_list ]

“相关推荐”对你有帮助么?

  • 非常没帮助
  • 没帮助
  • 一般
  • 有帮助
  • 非常有帮助
提交
评论 1
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值