web-dev-qa-db-ja.com

CollisionBitMaskはどのように機能しますか? Swift / SpriteKit

私が知る限り、Physicsボディのデフォルトは、collisionBitMaskを同じ数に設定するまで、互いにぶつかると跳ね返ることです。

しかし、私は、collisionBitmasksが原因で、非常に単純であると思われることを達成するために、大きな問題を抱えています。

    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の1つをコメントアウトしたときにのみ、跳ね返ります。そうでなければ、彼らはお互いを通過します。

これらのアイテムはそれぞれ異なる衝突ビットマスクを持っているため、これはまったく意味がありません。また、すべての数値を5に設定すると、すべてが相互に通過できるようになることもありましたが、すべてを6に設定すると、すべてが互いに衝突するようになります。

衝突ビットマスクはどのように正確に機能し、交差する多数の衝突ルールを管理する適切な方法はありますか?

21
Barkley

カテゴリ、連絡先、および衝突ビットマスクを適切に設定していないため、目的の動作を得ることができません。これが機能するように設定する方法の例を次に示します。

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 -現在の物理ボディとの交差通知を引き起こすボディのカテゴリを定義するマスク。

2つのボディが同じスペースを共有する場合、各ボディのカテゴリマスクは、論理AND演算を実行することにより、他のボディの接触マスクに対してテストされます。いずれかの比較の結果がゼロ以外の値になる場合、SKPhysicsContactオブジェクトが作成され、物理世界のデリゲートに渡されます。最高のパフォーマンスを得るには、関心のあるインタラクションの連絡先マスクのビットのみを設定してください。

collisionBitmask -物理ボディのどのカテゴリがこの物理ボディと衝突できるかを定義するマスク。

2つの物理ボディが互いに接触すると、衝突が発生する可能性があります。このボディの衝突マスクは、論理AND演算を実行することにより、他のボディのカテゴリマスクと比較されます。結果がゼロ以外の値の場合、このボディは衝突の影響を受けます。各ボディは、他のボディの影響を受けるかどうかを個別に選択します。たとえば、これを使用して、ボディの速度にほとんど変化しない衝突計算を回避できます。

したがって、基本的に、これらすべてを設定するには、次のようなことを自分に尋ねる必要があります。

さて、私はシーンに緑のボールと赤のボールと壁オブジェクトを持っています。どのボディ間で衝突を発生させたいか、または連絡先を登録したい場合?緑と赤のボールがぶつかって壁にぶつかるようにしたい。問題ない。最初にカテゴリを適切に設定してから、次のように衝突ビットマスクを設定します。

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

これが少し役に立てば幸いです。

53
Whirlwind

ここで何かを追加したいだけです。接触または衝突が適切に機能しない場合は、bitMasksを適用する前に、最初に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];

とにかく、おそらく初心者の間違いだけですが、私がここで共有したいのは、これが私の機能が適切に機能しなかった原因です。

1
GeneCode