碰撞位掩码是如何工作的?斯威夫特/雪碧套件
Posted
技术标签:
【中文标题】碰撞位掩码是如何工作的?斯威夫特/雪碧套件【英文标题】:How does collisionBitMask work? Swift/SpriteKit 【发布时间】:2015-09-15 13:27:49 【问题描述】:据我所知,Physics 物体的默认设置是在它们相互碰撞时相互反弹,直到您将它们的 collisionBitMask 设置为相等的数字。
但是,由于我相信碰撞位掩码,我在完成看起来应该非常简单的事情时遇到了一个巨大的问题。
let RedBallCategory : UInt32 = 0x1 << 1
let GreenBallCategory: UInt32 = 0x1 << 2
let RedBarCategory : UInt32 = 0x1 << 3
let GreenBarCategory : UInt32 = 0x1 << 4
let WallCategory : UInt32 = 0x1 << 5
greenBall.physicsBody?.categoryBitMask = GreenBallCategory
greenBall.physicsBody?.contactTestBitMask = RedBarCategory
greenBall.physicsBody?.collisionBitMask = GreenHealthCategory
redBall.physicsBody?.categoryBitMask = RedBallCategory
redBall.physicsBody?.contactTestBitMask = GreenBarCategory
redBall.physicsBody?.collisionBitMask = RedHealthCategory
let borderBody = SKPhysicsBody(edgeLoopFromRect: self.frame)
self.physicsBody = borderBody
self.physicsBody?.friction = 0
borderBody.contactTestBitMask = RedBallCategory | GreenBallCategory
borderBody.categoryBitMask = WallCategory
所以这里我有我的 2 个球和我的边框。我可以得到我想要的碰撞检测,但是当我添加边框体的类别位掩码时,它允许球穿过和离开屏幕,这是我不想要的。
我还希望球相互反弹,但只有当我注释掉其中一个球的 categoryBitMask 时,它们才会反弹。否则它们会互相穿过。
这对我来说完全没有意义,因为这些项目中的每一个都有不同的碰撞位掩码。有时我也有这样的情况,将所有数字设置为 5 将允许所有内容相互通过,但将其全部设置为 6 将允许所有内容相互碰撞。
碰撞位掩码究竟是如何工作的,是否有适当的方法来管理大量交叉碰撞规则?
【问题讨论】:
【参考方案1】:您无法获得所需的行为,因为您没有正确设置类别、接触和碰撞位掩码。这是一个关于如何设置它的示例:
greenBall.physicsBody?.categoryBitMask = GreenBallCategory //Category is GreenBall
greenBall.physicsBody?.contactTestBitMask = RedBarCategory | WallCategory //Contact will be detected when GreenBall make a contact with RedBar or a Wall (assuming that redBar's masks are already properly set)
greenBall.physicsBody?.collisionBitMask = GreenBallCategory | RedBallCategory | WallCategory //Collision will occur when GreenBall hits GreenBall, RedBall or hits a Wall
redBall.physicsBody?.categoryBitMask = RedBallCategory //Category is RedBall
redBall.physicsBody?.contactTestBitMask = GreenBarCategory | GreenBallCategory | WallCategory //Contact will be detected when RedBall make a contact with GreenBar , GreenBall or a Wall
redBall.physicsBody?.collisionBitMask = RedBallCategory | GreenBallCategory | WallCategory //Collision will occur when RedBall meets RedBall, GreenBall or hits a Wall
let borderBody = SKPhysicsBody(edgeLoopFromRect: self.frame)
self.physicsBody = borderBody
self.physicsBody?.friction = 0
borderBody.contactTestBitMask = RedBallCategory | GreenBallCategory //Contact will be detected when red or green ball hit the wall
borderBody.categoryBitMask = WallCategory
borderBody.collisionBitMask = RedBallCategory | GreenBallCategory // Collisions between RedBall GreenBall and a Wall will be detected
我建议您阅读有关 categoryBitMask 的文档,这是一个定义物理体所属类别的掩码:
场景中的每个物理体最多可以分配给 32 个不同的 类别,每个对应于位掩码中的一个位。你定义 游戏中使用的掩码值。与 collisionBitMask 和 contactTestBitMask 属性,您定义哪个 物理实体相互交互以及何时通知您的游戏 这些互动。
contactTestBitMask - 一个掩码,定义哪些类别的物体会导致与当前物理物体的交叉通知。
当两个 body 共享同一个空间时,每个 body 的类别掩码为 通过执行逻辑测试对另一个身体的接触面罩 与操作。如果任一比较结果为非零值,则 SKPhysicsContact 对象被创建并传递给物理世界的 代表。为获得最佳性能,仅在触点掩码中设置位 您感兴趣的互动。
collisionBitmask - 定义哪些类别的物理体可以与此物理体发生碰撞的掩码。
当两个物理体相互接触时,可能会发生碰撞。 将此主体的碰撞掩码与其他主体的类别进行比较 通过执行逻辑与运算来屏蔽。如果结果是非零 值,这个物体会受到碰撞的影响。每个身体独立 选择是否要被对方影响。为了 例如,您可以使用它来避免碰撞计算 对身体的速度进行微不足道的变化。
所以基本上,要设置所有这些,您应该问自己以下问题:
好的,我有一个绿色球,一个红色球,以及场景中的墙壁对象。我希望在哪些物体之间发生碰撞,或者何时注册联系人?我想要一个绿色和一个红色的球相互碰撞并撞到墙上。不是问题。我将首先正确设置类别,然后我将设置这样的碰撞位掩码:
greenBall.collisionBitMask = GreenBallCategory | RedBallCategory | WallCategory; //greenBall will collide with greenBall, redBall and a wall
redBall.collisionBitMask = GreenBallCategory | RedBallCategory | WallCategory
wall.collisionBitMask = GreenBall | RedBall
现在,我想检测何时发生某些接触(在didBeginContact
: 方法中)...但我不想收到有关所有可能接触的通知,而是仅收到有关球之间接触的通知(接触球和墙之间将被忽略)。所以让我们设置contactTestBitMasks
来实现:
greenBall.contactTestBitMask = GreenBallCategory | RedBallCategory;
redBall.contactTestBitMask = GreenBallCategory | RedBallCategory;
就是这样。重要的是当你不使用接触检测时,你不应该设置contactTestBitMask
。这是因为性能原因。如果不需要碰撞检测,只对检测接触感兴趣,可以设置collisionBitMask = 0
。
重要:
确保您已设置物理世界的联系人代表以便使用didBeginContact
和didEndContact
方法:
self.physicsWorld.contactDelegate = self; //where self is a current scene
希望这会有所帮助。
【讨论】:
惊人的答案,非常感谢您花时间写下所有这些。它运行良好。 “问问自己这个”部分肯定澄清了我的困惑。非常感谢,非常感谢! 如果你有超过 32 个呢? @Abcdefg 如何在 didEnd 函数中检测到碰撞结束? 非常棒的答案——非常感谢!现在在这个话题上挣扎了几天。你的“问你自己”部分是我所见过的最好的解释。【参考方案2】:只是想在这里添加一些东西,如果接触或碰撞无法正常工作,您需要确保在应用 bitMask 之前先分配physicsBody 形状。
位掩码无效示例:
SKSpriteNode *bird = [SKSpriteNode spriteNodeWithImageNamed:@"bird1.png"];
bird.name = @"bird";
bird.physicsBody.categoryBitMask = birdCategory;
bird.physicsBody.contactTestBitMask = wallCategory | scoreCategory;
bird.physicsBody = [SKPhysicsBody bodyWithCircleOfRadius:bird.size.width/2.7];
bird.position = CGPointMake(_mySize.width/3.0, 2*_mySize.height/3.0);
[self addChild:bird];
还有一个工作:
SKSpriteNode *bird = [SKSpriteNode spriteNodeWithImageNamed:@"bird1.png"];
bird.name = @"bird";
bird.physicsBody = [SKPhysicsBody bodyWithCircleOfRadius:bird.size.width/2.7];
bird.physicsBody.categoryBitMask = birdCategory;
bird.physicsBody.contactTestBitMask = wallCategory | scoreCategory;
bird.position = CGPointMake(_mySize.width/3.0, 2*_mySize.height/3.0);
[self addChild:bird];
无论如何可能只是一个新手错误,但我会在这里分享,因为这是导致我无法正常工作的原因。
【讨论】:
以上是关于碰撞位掩码是如何工作的?斯威夫特/雪碧套件的主要内容,如果未能解决你的问题,请参考以下文章
使用固定的SKPhysicsJoint将平台检测命中框作为子项附加到玩家精灵更改玩家的碰撞和检测位掩码