やりたいこと
spriteをボタンとして扱いたい。やり方
SKSpriteNodeはUIButton的な機能は持ってないので、touchBegan()の中でtouch箇所がボタン用スプライトの位置かを判定し、処理をすることになる。ちょっとめんどくせえ。
スプライトにはあらかじめ任意のnameを付けておけば複数のボタンに対処できる。
Swift4版
以下はボタン用スプライトをタッチしたらParticleを表示するもの。
ボタンにはあらかじめ"fireButton"というnameが設定されている。
//fireButtonがタッチされたらparticle処理して終了
if let touch = touches.first as UITouch? {
let location = touch.location(in: self)
//本とかだと.firstでやるように書かれてるが、途中から反応しなくなることがあるので、
//.lastにしたほうがいい。原因は不明。これで支障ないのでこれでいい。
if self.nodes(at: location).last?.name == "fireButton" {
//パーティクル
let particleSpark = SKEmitterNode(fileNamed: "SparkParticle.sks")
particleSpark.position = CGPoint(x: 0, y: 0)
particleSpark.numParticlesToEmit = 400
self.scene?.addChild(particleSpark)
return
}
}
注意点
Particleをいっぱい表示させてたところ、途中からボタンが反応しなくなった。
参考書などでは
if self.nodes(at: location).first?.name == "fireButton" { }
となってたのだが、どうやら.firstの中身がParticleになってしまい、nameが付いていないのではじかれてしまったのだ。これは.last?にすることで回避できたが、なぜ途中から変わっちゃうんだろう? Particleって勝手に消えてくれるはずだよね? 画面見てもわからないが、不可視要素としてボタンに引っかかってるんだろうか?
Swift2.1版(古いけど参考までに残しとく)
Spriteがタッチされたら何か反応示す場合、Spriteに名前を付けておけば、addChildしてある親SceneのtouchBeganメソッドから、nodeAtPointメソッドでタッチされたノードを得ることができる。
そしてそれの.nameを調べればどのSpriteがタッチされたか判断できる。
以下は、「powerGauge」という名前をつけたSpriteがタッチされたら、バカみたいなメッセージをprintlnするというもの。
touchedNode?.nameをprintltすると「Optional("powerGauge")」というメッセージがコンソールに出るが、if文で判定する際は「powerGauge」だけでいい。
//タッチ検出
override func touchesBegan(touches: Set<NSObject>, withEvent event: UIEvent) {
let touch = touches.first as! UITouch //Swift1.2から.firstに
let location = touch.locationInNode(self)
let str = selectSpriteForTouch(location)
println("タッチ開始 \(str)")
}
override func touchesEnded(touches: Set<NSObject>, withEvent event: UIEvent) {
let touch = touches.first as! UITouch //Swift1.2から.firstに
let location = touch.locationInNode(self)
let str = selectSpriteForTouch(location)
println("タッチ終了 \(str)")
}
override func touchesMoved(touches: Set<NSObject>, withEvent event: UIEvent) {
let touch = touches.first as! UITouch
let location = touch.locationInNode(self)
if let touchedNode = self.nodeAtPoint(location) as? SKSpriteNode {
touchedNode.position = location
}
}
//タッチしたSpriteNodeのnameを得る
func selectSpriteForTouch(location:CGPoint) -> String {
let touchedNode = self.nodeAtPoint(location) as? SKSpriteNode
println("タッチされたSprite名: \(touchedNode?.name)")
let str:String = (touchedNode?.name ?? "にる")
if touchedNode?.name == "powerGauge" {
println("パワーゲージだよ~~~ん")
}
return str
}
touchesMoved中の
if let toucheNode = self.nodeAtPoint(location) as? SKSpriteNode {
toucheNode.position = location
}
は、Swift独特の書き方で、右辺の値がnilじゃなかったらtouchedNodeに値を代入して { }内の処理を行うというもの。
値がnilだったらif文の { }が飛ばされるので、nilによる例外エラーとかが起きない仕組みだ。
selectSpriteForTouch中の
let str:String = (touchedNode?.name ?? "にる")
は、Swiftが原則的にnilを変数に入れられないため、touchedNode.nameがnilだった場合は「にる」をstrに入れよというデフォルト値の設定。
optional関係はまだ不慣れなため、もっといい書き方があると思うけど。
Spriteのカスタムクラスを作った場合でも、いちいちdelegateとか使わなくてもタッチされたSpriteを特定できるので、コードが簡単になる。
(delegate使ったほうが楽な場合もあると思うけどね)
0 件のコメント:
コメントを投稿