[iOS 8] SpriteKit でミニゲームをつくる #14 物理エンジン ジョイント

2014.09.18

この記事は公開されてから1年以上経過しています。情報が古い可能性がありますので、ご注意ください。

物理エンジン ジョイント

今回は、ペンギンが隣り合わせになったら、手をつなぐ処理を作ります。
コードは前回からの続きです。

まず、ペンギンを生成するときに、手の領域のノードを追加します。今回は、動かしたときに見分けやすいように白くしています。

    func addPenguinBlock() -> SKSpriteNode! {
        
        ....................
        ....................
        ....................
        
        // 手を追加する。
        let handRight = SKSpriteNode(color: UIColor(white: 1, alpha: 0.5) , size: CGSizeMake(40, 40))
        handRight.position = CGPointMake(-46, 0)
        handRight.name = "hand"
        handRight.zPosition = 1
        penguin.addChild(handRight)
        
        let handLeft = SKSpriteNode(color: UIColor(white: 1, alpha: 0.5) , size: CGSizeMake(40, 40))
        handLeft.position = CGPointMake(46, 0)
        handLeft.name = "hand"
        handLeft.zPosition = 1
        penguin.addChild(handLeft)
        
        // ペンギンをレイヤーに追加する。
        isLandLayer?.addChild(penguin)
        return penguin
    }


次に、フレームごとの物理演算の後に呼ばれる didSimulatePhysics メソッドで、手が他のペンギンの手と重なっているかどうかを判別して、重なっている手(接続可能な手)がある場合は星印を追加して、手を削除します。

    override func didSimulatePhysics() {
        let isLandLayer = childNodeWithName("scrollLayer")?.childNodeWithName("isLandLayer")
        
        for child in isLandLayer!.children {
            jointHand(child as SKNode)
        }
    }
    
    func jointHand(penguin:SKNode) {
        for child in penguin.children {
            let penguinHand:SKNode = child as SKNode
            let penguinHandPoint:CGPoint = penguin.convertPoint(penguinHand.position, toNode: self)
            
            // 接続可能な手を取得する。
            let jointHand = jointHandFromHand(penguinHand, penguinHandPoint:penguinHandPoint)
            
            // 接続する手がある場合は接続する。
            if jointHand != nil {
                addJoint(penguinHand, jointHand: jointHand)
            }
        }
    }
    
    func jointHandFromHand(penguinHand:SKNode, penguinHandPoint:CGPoint) ->SKNode! {
        var jointHand:SKNode!
        var nodes = nodesAtPoint(penguinHandPoint)
        for node in nodes {
            let childNode:SKNode! = node as? SKNode
            if childNode != nil {
                if penguinHand.parent != childNode.parent {
                    if childNode.name? == "hand" {
                        jointHand = childNode
                        break
                    }
                }
            }
        }
        return jointHand
    }
    
    func addJoint(penguinHand:SKNode, jointHand:SKNode)
    {
        let penguinHandPoint:CGPoint = penguinHand.parent!.convertPoint(penguinHand.position, toNode: self)
        let jointHandPoint:CGPoint = jointHand.parent!.convertPoint(jointHand.position, toNode: self)
        
        // 2点の中点を取得する。
        let jointPoint:CGPoint  = CGPointMake((penguinHandPoint.x + jointHandPoint.x) / 2.0,
            (penguinHandPoint.y + jointHandPoint.y) / 2.0)
        
        // 中点でジョイントする。
        let jointPin = SKPhysicsJointPin
            .jointWithBodyA(penguinHand.parent!.physicsBody,
            bodyB: jointHand.parent!.physicsBody,
            anchor: jointPoint)
        
        physicsWorld.addJoint(jointPin)
        
        // ジョイントの星印を追加する。
        var joint:SKSpriteNode = SKSpriteNode(texture:atlas.textureNamed("link"))
        joint.position = convertPoint(jointPoint, toNode: penguinHand.parent!)
        joint.xScale = 0.0
        joint.yScale = 0.0
        joint.zPosition = penguinHand.parent!.zPosition + 1
        penguinHand.parent!.addChild(joint)
        
        joint.runAction(SKAction.scaleTo(1.0, duration: 0.2))
        
        // 接続したら手を削除する。
        jointHand.removeFromParent()
        penguinHand.removeFromParent()
    }

手を接続しているところでは、SKPhysicsJointPin を使っています。

では、動かしてみます。

stack_penguin_14_01

白い四角の部分が手の領域で、星印のところが手をつないでいるところです。
いまさらだけど、ペンギンって「手」じゃなくて「翼」だったかな?まあいいか。。
動きを見たい方は、ぜひ「つみペンギン」をダウンロードしてみてください。

次回へ続く。ではでは。

完成品はこちら。つみペンギン
つみペンギン stack_penguin_qrcode

姉妹品はこちら。ペンギン陸上-スプリント-
ペンギン陸上-スプリント- athlete_penguin_sprint_qrcode