66126


原因がわかる方、どなたか助けてください。。  
spaceship missile asteroidの衝突時に”Explostion.sks”を出現させていたのですが、うまく作動しません。

[code]

    import SpriteKit
    import GameplayKit
    
    class GameScene: SKScene, SKPhysicsContactDelegate {
    
    
        var spaceship:SKSpriteNode! = SKSpriteNode(imageNamed: "spaceship") 
        var button : SKSpriteNode! 
        var missile: SKSpriteNode = SKSpriteNode(imageNamed: "missile") 
    
    
        **let gameCategory : UInt32 = 0b1000
        let spaceshipCategory : UInt32 = 0b0001
        let missileCategory : UInt32 = 0b0010
        let asteroidCategory  : UInt32 = 0b0100**
    
    
    
        var timar: Timer?
    
    
        func DegreeToRadian(Degree : Double!) -> CGFloat{
            return CGFloat(Degree) / CGFloat(180.0 * M_1_PI)
        }
    
    
        override func didMove(to view: SKView) {
    
            physicsWorld.gravity = CGVector(dx: 0, dy: 0)
            physicsWorld.contactDelegate = self
    
            self.backgroundColor = UIColor.white 
    
            self.spaceship.alpha = 1 
            self.spaceship.position = CGPoint(x: view.frame.width / -2 + 100, y: view.frame.height / -2 + 100) 
            self.spaceship.size = CGSize(width: 150, height: 150) 
            self.spaceship.zRotation = DegreeToRadian(Degree: 0) 
            self.spaceship.isUserInteractionEnabled = false 
            self.spaceship.physicsBody = SKPhysicsBody(circleOfRadius: self.spaceship.frame.width * 0.1) 
            **self.spaceship.physicsBody?.categoryBitMask = gameCategory
            self.spaceship.physicsBody?.collisionBitMask = gameCategory
            self.spaceship.physicsBody?.contactTestBitMask = asteroidCategory**
            self.addChild(self.spaceship) 
    
    
            self.button = self.childNode(withName: "button") as? SKSpriteNode 
            if let button = self.button {
                button.name = "button" 
                button.alpha = 0.0 
                button.run(SKAction.fadeIn(withDuration: 2.0)) 
    
            }
    
    
    
            timar = Timer.scheduledTimer(withTimeInterval: 1.0, repeats: true, block: { _ in
                self.addasteroid()
            })
    
              }
    
    
        override func touchesBegan(_ touches: Set<UITouch>, with event: UIEvent?) {
    
            self.missile.physicsBody = SKPhysicsBody(circleOfRadius: self.missile.frame.height / 2 ) 
            **self.missile.physicsBody?.categoryBitMask = gameCategory
            self.missile.physicsBody?.collisionBitMask = gameCategory
            self.missile.physicsBody?.contactTestBitMask = asteroidCategory**
    
    
            if let touch = touches.first { 
                let locatin = touch.location(in: self) 
                    if self.atPoint(locatin).name == "button" { 
    
                       missile.position = CGPoint(x: self.spaceship.position.x , y: self.spaceship.position.y + 10 ) 
                       missile.size = CGSize(width: 75, height: 75) 
                       addChild(missile) 
    
    
                        let topButton = SKAction.moveTo(y: frame.width / 2 - self.spaceship.position.y , duration: 0.2) 
                            let remove = SKAction.removeFromParent() 
                            missile.run(SKAction.sequence([topButton, remove])) 
    
                  }
              }
          }
    
    
    
        override func touchesMoved(_ touches: Set<UITouch>, with event: UIEvent?) {
    
            let touch = touches.first 
            let buttonLocation = touch?.location(in: self)  
            switch self.atPoint(buttonLocation!).name == "button" { 
            case true:
                break
    
            default:
                let location = touches.first!.location(in: self) 
                let action = SKAction.move(to: CGPoint(x: location.x, y:location.y + 20), duration: 0.1) 
                spaceship.run(action) 
            }
    
            }
    
    
        func addasteroid() {
    
            let names = ["asteroid1","asteroid2","asteroid3"]
            let index = Int.random(in: 0...2) 
            let name = names[index] 
            let asteroid = SKSpriteNode(imageNamed: name) 
    
            let XHighest: CGFloat = self.frame.width / 2 - spaceship.size.width 
            let XLowest: CGFloat = self.frame.width / -2 + spaceship.size.width 
            let random = CGFloat.random(in: XLowest...XHighest) 
            asteroid.position = CGPoint(x: random, y: frame.width)
            asteroid.size = CGSize(width: 100, height: 100) 
    
            asteroid.physicsBody = SKPhysicsBody(circleOfRadius: asteroid.frame.width)
            **asteroid.physicsBody?.categoryBitMask = gameCategory
            asteroid.physicsBody?.collisionBitMask = gameCategory
            asteroid.physicsBody?.contactTestBitMask = spaceshipCategory | missileCategory**
    
            addChild(asteroid)
    
            let move = SKAction.moveTo(y: frame.width / -2 - 100, duration: 1.0) 
            let remove = SKAction.removeFromParent()
            asteroid.run(SKAction.sequence([move, remove]))
        }
    
            **func didBegin(_ contact: SKPhysicsContact) {
            let explotsion = SKEmitterNode(fileNamed: "Explostion.sks")
            explotsion!.position = CGPoint(x: contact.contactPoint.x, y: contact.contactPoint.y)
    
            let action1 = SKAction.wait(forDuration: 1.0)
            let action2 = SKAction.removeFromParent()
            let actionAll = SKAction.sequence([action1, action2])
    
            self .addChild(explotsion!)
                explotsion!.run(actionAll)
        }**
    }
    
    
    
[/code]


CC BY-SA 4.0
2020-04-29T13:58:10.000
66119
2020-04-29T16:35:05.937
2020-04-29T14:42:22.807
32986
39881
question
swift spritekit
Swift SpriteKit 衝突判定が動作しない


`**`〜`**`でマーキングしようとしているので、ご自分で気づいておられると思うのですが、各bitMaskの使い方、特に`categoryBitMask`の使い方が根本的に誤っています。

まず、各スプライトの種類ごとに別々のビットを割り当てる定数宣言については、特に問題ありません。

[code]

        let gameCategory : UInt32 = 0b1000
        let spaceshipCategory : UInt32 = 0b0001
        let missileCategory : UInt32 = 0b0010
        let asteroidCategory  : UInt32 = 0b0100
    
[/code]

spaceshipが下から1ビット目、missileが下から2ビット目、asteroidが下から3ビット目と、スプライトの種類ごとに異なるビットが割り当てられています。

`gameCategory`と言うのは何に使いたいのか理解できませんでしたが、おそらく不要でしょう。

そして、もうこれはSpriteKitで衝突の物理処理や接触判定を行う際の基本中の基本なんですが、これらの定数は各スプライトの`categoryBitMask`に、種類別にそのまま代入してやらないといけません。衝突処理や接触判定で何かうまくいかない点が出てきても、この部分を変更してはいけません。

[code]

            self.spaceship.physicsBody?.categoryBitMask = spaceshipCategory
    
[/code]

[code]

            self.missile.physicsBody?.categoryBitMask = missileCategory
    
[/code]

[code]

            asteroid.physicsBody?.categoryBitMask = asteroidCategory
    
[/code]

* * *

以上のように各スプライトへの`categoryBitMask`が正しく設定できていると言う大前提のもとで、`contactTestBitMask`には、接触判定を行いたい相手の`categoryBitMask`値をbitwise-
ORでつなげた値を代入してやります。

ご質問には「spaceship missile asteroidの衝突時」とだけ書かれているのですが、接触判定を行いたいのは、

  * spaceship asteroid
  * missile asteroid

の2ケースだと仮定すると、これを「接触判定を行いたい相手」と言う見方で書き換えてやると、次のようになります。

  * spaceship → asteroid
  * missile → asteroid
  * asteroid → spaceship, missile

従って、`contactTestBitMask`に設定すべき値は、以下のようになります。

[code]

            self.spaceship.physicsBody?.contactTestBitMask = asteroidCategory
    
[/code]

[code]

            self.missile.physicsBody?.contactTestBitMask = asteroidCategory
    
[/code]

[code]

            asteroid.physicsBody?.contactTestBitMask = spaceshipCategory | missileCategory
    
[/code]

(例では現在のあなたのコードと同じですが、「接触判定を行いたいのは」の仮定を現在のコードに基づいて決定したためです。仮定に誤りがあれば、上記の考え方で代入すべき値を決定し直してください。)

* * *

衝突の物理処理についてはご質問の主題ではありませんが、上記と同じ考え方で`collisionBitMask`に設定してやらないといけません。例えば、「spaceship
missile asteroidのどの種類のスプライト間でも衝突の物理処理は行う」と言うのであれば、こんな風になるでしょう。

[code]

            self.spaceship.physicsBody?.collisionBitMask = spaceshipCategory | missileCategory | asteroidCategory
    
[/code]

[code]

            self.missile.physicsBody?.collisionBitMask = spaceshipCategory | missileCategory | asteroidCategory
    
[/code]

[code]

            asteroid.physicsBody?.collisionBitMask = spaceshipCategory | missileCategory | asteroidCategory
    
[/code]

* * *

その他の細かいところまではチェックし切れていないので、所望の動作をさせるためにはまだあちこち修正が必要かもしれませんが、各bitMaskの設定については、上記の原則・考え方を外さないようにすれば、うまくいくようになると思います。


CC BY-SA 4.0
2020-04-29T16:35:05.937
66126
2020-04-29T16:35:05.937
13972
66119
answer