collisionBitMask 是如何工作的? Swift/SpriteKit

How does collisionBitMask work? Swift/SpriteKit

据我所知,物理物体的默认设置是当它们相互碰撞时相互反弹,直到您将它们的 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 个球和我的边界 body。我可以获得我想要的碰撞检测,但是当我添加边框 body 的类别位掩码时,它允许球穿过屏幕和离开屏幕,这是我不想要的。

我也想让球相互反弹,但只有当我注释掉球的一个类别 BitMasks 时,它们才会反弹。否则他们会互相穿过。

这对我来说完全没有意义,因为这些项目中的每一个都有不同的碰撞位掩码。有时我也有这样的情况,将所有数字设置为 5 将允许所有内容相互通过,但将其全部设置为 6 将允许所有内容相互碰撞。

碰撞位掩码究竟是如何工作的,是否有适当的方法来管理大量交叉碰撞规则?

您无法获得所需的行为,因为您没有正确设置类别、接触和碰撞位掩码。这是一个关于如何设置它的例子:

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 的文档,它是一个定义物理体所属类别的掩码:

Every physics body in a scene can be assigned to up to 32 different categories, each corresponding to a bit in the bit mask. You define the mask values used in your game. In conjunction with the collisionBitMask and contactTestBitMask properties, you define which physics bodies interact with each other and when your game is notified of these interactions.

contactTestBitMask - 定义哪些类别的物体会导致与当前物理物体相交通知的掩码。

When two bodies share the same space, each body’s category mask is tested against the other body’s contact mask by performing a logical AND operation. If either comparison results in a nonzero value, an SKPhysicsContact object is created and passed to the physics world’s delegate. For best performance, only set bits in the contacts mask for interactions you are interested in.

collisionBitmask - 定义物理物体类别可以与该物理物体碰撞的遮罩。

When two physics bodies contact each other, a collision may occur. This body’s collision mask is compared to the other body’s category mask by performing a logical AND operation. If the result is a nonzero value, this body is affected by the collision. Each body independently chooses whether it wants to be affected by the other body. For example, you might use this to avoid collision calculations that would make negligible changes to a body’s velocity.

所以基本上,要设置所有这些,您应该问自己这样的问题:

好的,我在场景中有一个绿球、一个红球和墙壁对象。我希望在哪些物体之间发生碰撞,或者我想何时注册接触?我想要一个绿色和一个红色的球相互碰撞并撞到墙上。没问题。我将首先正确设置类别,然后我将像这样设置冲突位掩码:

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.

重要:

确保你已经设置了物理世界的联系代表以便使用didBeginContactdidEndContact方法:

self.physicsWorld.contactDelegate = self; //where self is a current scene

希望对您有所帮助。

只是想在这里补充一点,如果接触或碰撞无法正常工作,您需要确保在应用位掩码之前先分配物理体形状。

位掩码不起作用的示例:

        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];

无论如何可能只是一个新手错误,但我会在这里分享,因为这是导致我无法正常工作的原因。