はじめに
SpriteKit でのボタン表示について3パターン思いついたので紹介します。
- UIButton を使う
- SKNode で毎回設置する
- SKNode のサブクラスを作る
UIButton を使う
まず1つ目が SKView
に UIButton
を置く方法です。
実装はこんな感じ。
1 2 3 4 5 6 7 8 9 10 11 12 13 14 |
final class HogeScne: SKScene { override func didMove(to view: SKView) { let button = UIButton(frame: .init(origin: .zero, size: .init(width: 100, height: 40)), primaryAction: .init(handler: { _ in print("ボタン押下") })) var config = UIButton.Configuration.filled() config.title = "ほげ" button.configuration = config button.center = view.center view.addSubview(button) } } |
見た目はこんな感じです。
注意点としては SKView
上に置ので複数 Scene
を使うときにめんどくさそうということです。あと座標系が UIKit になるので注意(原点は左上)。
SKNode で毎回設置する
2つ目は単純に Node でボタンを設置する方法です。
実装はこんな感じ。
1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19 20 21 22 23 24 25 26 27 28 29 30 31 32 33 |
final class HogeScne: SKScene { override func didMove(to view: SKView) { let button = makeButton(title: "ほげ", textColor: .white, backgroundColor: .systemRed, size: .init(width: 100, height: 40)) button.position = .init(x: frame.midX, y: frame.midY) addChild(button) } override func touchesBegan(_ touches: Set<UITouch>, with event: UIEvent?) { guard let touch = touches.first else { return } if atPoint(touch.location(in: self)).name == "ほげ" { print("ボタンタップ!!!") } } private func makeButton(title: String, textColor: UIColor, backgroundColor: UIColor, size: CGSize) -> SKNode { let node = SKShapeNode(rectOf: size, cornerRadius: 5) node.fillColor = backgroundColor node.name = title let label = SKLabelNode(text: title) label.color = textColor label.verticalAlignmentMode = .center label.position = .zero label.name = title node.addChild(label) return node } } |
見た目はこんな感じです。
SKShapeNode
と SKLabelNode
でボタンを作り、 touchesBegan
で SKNode.name
の判定によりどのボタンが押下されたか判定しています。
デメリットとしては複数ボタンがある場合に touchesBegan
の処理が複雑になることです。
SKNode のサブクラスを作る
3つ目が SKNode
のサブクラスを作る方法です。
実装はこんな感じ。
1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19 20 21 22 23 24 25 26 27 28 29 30 31 32 33 34 35 36 37 38 39 40 41 42 43 44 45 46 |
final class HogeScne: SKScene { override func didMove(to view: SKView) { let button = ButtonNode(title: "ボタン", textColor: .white, backgroundColor: .systemRed, size: .init(width: 100, height: 40)) { _ in print("ボタン押下") } button.position = .init(x: frame.midX, y: frame.midY) addChild(button) } } final class ButtonNode: SKNode { /// ButtonNode自体のsizeは(0, 0)になるのでここでボタンサイズを保持 private(set) var buttonSize: CGSize private let action: ((ButtonNode) -> Void) init(title: String, textColor: UIColor, backgroundColor: UIColor, size: CGSize, action: @escaping ((ButtonNode) -> Void)) { self.buttonSize = size self.action = action super.init() let node = SKShapeNode(rectOf: size, cornerRadius: 5) node.fillColor = backgroundColor node.name = title let label = SKLabelNode(text: title) label.color = textColor label.verticalAlignmentMode = .center label.position = .zero label.name = title node.addChild(label) addChild(node) self.isUserInteractionEnabled = true } required init?(coder aDecoder: NSCoder) { fatalError("init(coder:) has not been implemented") } override func touchesBegan(_ touches: Set<UITouch>, with event: UIEvent?) { action(self) } } |
見た目は2つ目の方法と同じですがクロージャを使うことで複数ボタンを置いても touchesBegan
が太らないのがいいところです。
おまけ
SKNode
のサブクラスを作る方法でもう少し手を加えてやるとボタン押下時にハイライトっぽいことができます。
実装はこんな感じ。
1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19 20 21 22 23 24 25 26 27 28 29 30 31 32 33 34 35 36 37 38 39 40 41 42 43 |
final class ButtonNode: SKNode { private(set) var buttonSize: CGSize private let action: ((ButtonNode) -> Void) private var highlightNode: SKShapeNode // これ追加 init(title: String, textColor: UIColor, backgroundColor: UIColor, size: CGSize, action: @escaping ((ButtonNode) -> Void)) { self.buttonSize = size self.action = action self.highlightNode = SKShapeNode(rectOf: size, cornerRadius: 5) super.init() let node = SKShapeNode(rectOf: size, cornerRadius: 5) node.fillColor = backgroundColor node.name = title let label = SKLabelNode(text: title) label.color = textColor label.verticalAlignmentMode = .center label.position = .zero label.name = title node.addChild(label) addChild(node) self.highlightNode.fillColor = .systemGray.withAlphaComponent(0.3) self.highlightNode.strokeColor = .clear self.highlightNode.isHidden = true addChild(self.highlightNode) self.isUserInteractionEnabled = true } required init?(coder aDecoder: NSCoder) { fatalError("init(coder:) has not been implemented") } override func touchesBegan(_ touches: Set<UITouch>, with event: UIEvent?) { highlightNode.isHidden = false action(self) } override func touchesEnded(_ touches: Set<UITouch>, with event: UIEvent?) { highlightNode.isHidden = true } } |
見た目はこんな感じです。
SKNodeでボタンぽいのできた✌️ pic.twitter.com/VZ203QXJsH
— am10 (@am103141592) July 31, 2022
おわりに
SpriteKit でボタンを表示する方法を紹介しましたがそもそも SpriteKit でボタンをあまり使わないかもですね。
なにかアクションを実行したいときは単純に画面タップで実行することがもしかしたら多いかもしれません。
コメント