iOS
SpriteKit
Swift

SpriteKitで使うボタン(Swift)

More than 3 years have passed since last update.

SpriteKitを使って、アプリを作る際にUIButtonみたいなものが欲しくなったので簡単に作れる方法を検討した。


そもそも

SpriteKit初めてだったので、最初は1つのシーンファイルにSKSpriteNodeとかをパーツごとに置いていて、かつそれらにアニメーション付けて、、ステータスによって画像切替えて、、などしていたらファイルの行数が膨らみすぎて管理が難しくなってきた。

そこで、(当たり前かと思うが)パーツごとにSKNodeを継承したクラスを作成して、置きたいシーンにまとめて配置する。という方法を思いついた。


方法①


簡単な方法

わざわざ独自にクラスつくらずに、SKSpriteNode置いて、touchBegan()で判別する。

override func didMoveToView(view: SKView) {

//テクスチャアトラスからボタン作成
let button = SKSpriteNode(texture: SKTextureAtlas(named: "UIParts").textureNamed("button"))
//イメージからそのままの場合は
//let button = SKSpriteNode(imageNamed: "button.png")

button.position = CGPointMake(self.frame.width/2, self.frame.height/2)
button.zPosition = 1
button.name = "button"
self.addChild(button)
}

override func touchesBegan(touches: Set<UITouch>, withEvent event: UIEvent?) {
if let touch = touches.first as UITouch? {
let location = touch.locationInNode(self)
if self.nodeAtPoint(location).name == "button" {
print("button tapped")
}
}
}
}

zPositionが一番上にないとタッチしても反応がないので注意。


方法②


ちょっとめんどくさい方法

ボタンを押した時だけ、画像が切り替わるボタンを作成

ボタン用にクラスを1つつくる。

用意するもの


  • ボタンの画像(hoge.png)

  • ボタンをタップした後の画像(hoge_on.png)


SKNodeを継承したボタンクラス

クラスを作成するので、使用したいシーンでタップイベントを取ることができないので

デリゲートを使用してイベントをとることにした。

デリゲート関数にidつけて処理の分岐することにした。

確かUITextFieldとかもそんな感じでやってたのを真似した。

self.userInteractionEnabled = true

これないと個別につくったクラスでtouchBegan反応しないので注意

以下ソース


Button.swift

import SpriteKit

import Foundation

class Button: SKNode {
weak var keyTapDelegate: ButtonTappedDelegate!

var button:SKSpriteNode!
var buttonOver:SKSpriteNode!
var imageName: String!

internal init(name: String) {
super.init()
imageName = name

//通常
button = SKSpriteNode(texture: SKTextureAtlas(named: "UIParts").textureNamed(imageName))
//タップした状態
buttonOver = SKSpriteNode(texture: SKTextureAtlas(named: "UIParts").textureNamed(imageName+"_on"))
buttonOver.alpha = 0

//必要!
self.userInteractionEnabled = true

self.addChild(button)
self.addChild(buttonOver)
}

required init?(coder aDecoder: NSCoder) {
fatalError("init(coder:) has not been implemented")
}

override func touchesBegan(touches: Set<UITouch>, withEvent event: UIEvent?) {
//ボタンの状態を切替え
button.alpha = 0
buttonOver.alpha = 1
ButtonTapDelegate.buttonTapped(imageName)
}

override func touchesEnded(touches: Set<UITouch>, withEvent event: UIEvent?) {
//ボタンの状態を切替え
button.alpha = 1
buttonOver.alpha = 0
}
}



ボタンのタップを使用するシーンで使うためのプロトコル

名前を引数にとって、複数ある場合の処理わけをする

protocol ButtonTappedDelegate : class {

//Buttonクラスでタッチされた
func buttonTapped(name:String)
}


シーンで以上のボタンクラスを利用する

ボタンのタップイベントをデリゲート関数?から受け取って、名前別に処理をする

class Scene: SKScene, KeyTappedDelegate {

override func didMoveToView(view: SKView) {
let buttonHoge = Button(name: "hoge")
buttonHoge.buttonTapDelegate = self
buttonHoge.zPosition = 1.0
self.addChild(buttonHoge)

let buttonPiyo = Button(name: "piyo")
buttonPiyo.buttonTapDelegate = self
buttonPiyo.zPosition = 1.0
self.addChild(buttonPiyo)
}

func buttonTapped(name: String) {
switch name {
case "hoge":
print("hoge")
case "piyo":
print("piyo")
default:
print("hogepiyo")
}
}

書いたソースコードからいらない部分省略して変数名とか変えただけなので動かなかったらすみません。