【Swift】 SpriteKit 入門 ⑤


SpriteKitの使い方を解説します。
SpriteKit 入門 ④で敵を表示して衝突判定を実装することができました。今回は、一度に発射する弾の数を増やしてみようと思います。
(環境:Xcode12.4  Swift5.3)

repeatShootsメソッドの修正

前回はMySceneクラスのプロパティとして弾用のSKShapeNodeを用意していました。しかし特にクラスのプロパティとして宣言しておく必要もなかったため、これを削除しておきましょう。
次に、repeatShootsメソッドを修正していきます。前回は一つだけSKShapeNodeのインスタンスを作成してself.addChild(shoot)で画面に表示させていましたが、この処理をfor文を使って繰り返し実行するように変更します。また、弾の発射方向も少しずつずらすようにしましょう。以下にコードを示します。

MyScene.swift
//自機から発射する弾
    func repeatShoots(){
        for i in -1...1{
            let shoot:SKShapeNode = SKShapeNode.init(rectOf: CGSize.init(width: 30, height: 30), cornerRadius: 3)
            shoot.name = "shoot"
            shoot.physicsBody = SKPhysicsBody(rectangleOf: CGSize(width: 30, height: 30))
            shoot.physicsBody?.affectedByGravity = false
            shoot.physicsBody?.categoryBitMask = 0b0001
            shoot.physicsBody?.collisionBitMask = 0b0000
            shoot.physicsBody?.contactTestBitMask = 0b0001
            shoot.position = image.position
            shoot.fillColor = SKColor.red
            shoot.lineWidth = 3
            shoot.strokeColor = SKColor.white
            shoot.run(SKAction.repeatForever(SKAction.rotate(byAngle: CGFloat(Double.pi), duration: 1)))
            let p:CGFloat = CGFloat(i*100)
            let vector1: CGVector = CGVector(dx: p, dy: self.size.height)
            shoot.run(SKAction.sequence([SKAction.move(by: vector1, duration: 3),SKAction.removeFromParent()]))
            self.addChild(shoot)
        }
    }

衝突判定の修正

発射する弾を増やすことはできましたが、このままだと発射した瞬間の弾同士での衝突が発生してしまいます。弾同士の衝突は無視したいので、if文の条件をそうなるように修正していきます。(※現時点では敵同士での衝突は考慮していません。)

MyScene.swift
   func didBegin(_ contact: SKPhysicsContact) {
        let t1 = contact.bodyA.categoryBitMask == self.enemy?.physicsBody!.categoryBitMask
        let t2 = contact.bodyB.categoryBitMask == self.enemy?.physicsBody!.categoryBitMask
        let notEmpty = contact.bodyA.node != nil && contact.bodyB.node != nil
        if (t1 || t2) && notEmpty{
            if contact.bodyA.node!.name == "shoot" && contact.bodyB.node!.name != "shoot" {
                self.removeChildren(in: [contact.bodyA.node!,contact.bodyB.node!])
            }else if contact.bodyB.node?.name == "shoot" && contact.bodyA.node!.name != "shoot" {
                self.removeChildren(in: [contact.bodyA.node!,contact.bodyB.node!])
            }
        }
    }