SpriteKitとボタンの実装

検索するといくつか出てくるんだけど、
個人的にはこんな感じでイイかなぁーって思ってる。

そもそも、どんな用途を想定するのか?

  • タイトル画面からゲーム画面への遷移
  • 次のステージ(ゲーム画面)への遷移
  • チェックボックスの実装

自分の場合は、これらを想定している。
3つ目のチェックボックスだけど、要はトグルできるボタンのこと。
BGMのOn/Offとか、SE(効果音)のOn/Offに使いたい。

どうやって実装するか?

現時点では、こんな感じ。

1.) SKLabelNodeを継承する

// MyButton.h
#import <SpriteKit/SpriteKit.h>

@interface MyButton : SKLabelNode

@property (nonatomic, assign) SKAction *touchAction;

@end

// MyButton.m
#import "MyButton.h"

@implementation MyButton

-(instancetype)initWithFontNamed:(NSString *)fontName
{
    if ( self = [super initWithFontNamed:fontName] ) {
        _touchAction = nil; // touchesBegan/touchesEndedで発火させるアクション
        self.userInteractionEnabled = YES;
    }

    return self;
}

-(void)touchesBegan:(NSSet *)touches withEvent:(UIEvent *)event
{
    /* タッチに反応させたければここ */
}

-(void)touchesEnded:(NSSet *)touches withEvent:(UIEvent *)event
{
    /* ボタンっぽく振る舞いたい場合は、指を離した位置をチェックする */
    UITouch *touch = [touches anyObject];
    CGPoint location = [touch locationInNode:self];
    CGPoint locationInParent = [self convertPoint:location toNode:self.parent];

    if ( CGRectContainsPoint(rect, locationInParent) ) {
        NSLog( @"Touch: x, y = %.1f, %.1f, Clicked!!!", location.x, location.y );
    }
    else {
        NSLog( @"Touch: x, y = %.1f, %.1f", location.x, location.y );
    }
}

@end

ポイントは、userInteractionEnabledYESを代入するところ。
これをしないと、touchesBeganが呼ばれないと同時に、
親NodeのtouchesBeganが呼ばれてしまう。

これは、こちらを参考にさせて頂きました。
タップされたらSKActionを実行するSKLabelNodeを作ってみた – TATYUSA’S NOTE

2.) SKSceneのtouchesBeganで処理する

そもそも、タイトル画面からゲーム画面に遷移するだけだったら、
どの位置がタップされても良いので、
それなら、touchesBeganで処理しても構わない気がする。
ただし、やはりラベルの領域でのみ反応したいとか、
タイトル画面にBGMのOn/Offを付けたいとかあると思う。
その場合は、1.)で紹介したCGRectContainsPointを使って判断すれば良いと思う。

おまけ

あと、個人的にラベルの範囲だけじゃなくて、
タッチに反応する領域を、もう少し増やしたいと思ってるんだけど、
これはどうやって実装したらいいだろう?
2.)の方法であれば、CGRectContainsPointを行う前に、
引数の領域(CGRect)を膨らませることが考えられる。
もう一つは、SKLabelNodeSKSpriteNodeに追加してとかかなー。

チェックボックスについては、そのうちということで。

おしまい。

4 Responses to “SpriteKitとボタンの実装”

  1. 素直にやるとnodeのframeプロパティにサイズを大きくしたCGRectをつっこめばいいじゃないですかねー
    node.frame = CGRectInset(frame, -2, -2);
    くらいの感じで。
    OSX/Cocoaのラベルだとそんなんですね

  2. あ、そっか。SKLabelNodeのframeプロパティを広げて、
    それを使って、spriteNodeWithColorして、addChildすればいんですね。
    あと、領域を変更する関数を探す手間が省けました、ありがとうございます!

  3. OSXのAppKitだとhitTestをオーバーライドして
    frame内のマウス当たり判定は好きにできるんですけど
    その辺はどうなんでしょうねえ(あんまりまじめにSpriteKitの説明書読んでなし)

  4. SKLabelNodeに関していうと、hitTestは無さそうですね。
    textプロパティ変更でframeプロパティが更新されるので、
    その辺を使うような気がします。

    ラベルのみをボタンとして使う場合は、判定領域を少し膨らませたい訳ですが、
    それならボタンの画像を用意すべきでは?って言われると、その通りでもあります。。。

Leave a Comment