読者です 読者をやめる 読者になる 読者になる

SpriteKit用のButtonコンポーネント作ってみた

iOS ゲームプログラミング SpriteKit

先日のポストで、SpriteKitのハマりどころについて取り上げましたが、 それに対応するためのコンポーネント作ってみたので、シェア。

なぜ作ったか

というのが主な理由です。

ViewControllerのタッチ関連メソッドがエラいことになるのを避けるため

SpriteKitではタッチイベントのハンドリングを

といった方法で行うようですが、そうするとNodeが増える度にSKSceneのタッチ関連メソッドが膨らんでしまい、 また、ソースコードもdryではなくなってしまいます。
そういった問題を回避するため、コンポーネントを作ってみました。

マルチプラットフォーム対応を容易にするため

ボタンをUIButtonで実装することもできますが、その場合、 UIKitベースのiOS/tvOSと、そうではないOS Xに対応する際に、 ViewControllerの実装が複雑になってしまうため、コンポーネントを作成し、 プラットフォームごとの差分をコンポーネントで吸収しようと考え、作りました。

実装

今回、作ったSpriteKit用のButtonコンポーネントは、以下のような実装になっています。
SKScenetouchesBeganでイベントのハンドリングを行うのではなく、
ButtonNodeでイベントを受け取り、SKSceneへの伝達はClosure経由で行うようにしています。

import SpriteKit

class ButtonNode: SKLabelNode {

    var didTapButtonClosure: (() -> Void)?
    
    override init() {
        super.init()
        userInteractionEnabled = true
    }
    override init(fontNamed fontName: String?) {
        super.init(fontNamed: fontName)
    }
    required init?(coder aDecoder: NSCoder) {
        fatalError("init(coder:) has not been implemented")
    }

    //MARK: - UIResponder

    override func touchesBegan(touches: Set, withEvent event: UIEvent?) {
        setHighlighted(true)
    }
    override func touchesCancelled(touches: Set?, withEvent event: UIEvent?) {
        setHighlighted(false)
    }
    override func touchesEnded(touches: Set, withEvent event: UIEvent?) {
        setHighlighted(false)

        didTapButtonClosure?()
    }

    //MARK: - private

    private func setHighlighted(highlighted: Bool) {
        removeAllActions()
        let alpha: CGFloat = highlighted ? 0.5 : 0
        let color: UIColor = UIColor(white: 1.0, alpha: alpha)
        let highlightAction: SKAction = SKAction.customActionWithDuration(0.24) { (node, elapsedTime) -> Void in
            self.fontColor = color
        }
        runAction(highlightAction)
    }
}

OS X対応は?

マルチプラットフォーム対応する際に、OS Xでは、そのあたりどうするのかなーと思い、 DemoBotsを見てみたところ、UIKitのtouchesBeganに相当する、 mouseDownなどのメソッドを使用していました。

サンプルプロジェクト