SpriteKitでチェックボックスを実装する

こないだの続き。
チェックボックスを実装してみたのでメモ。

着信があったときのシミュレーションをしようと思ったけど、
お友達がいないのでテスト出来ないです、こんにちは!

こないだは、ボタンっぽい挙動を実装した訳ですが、
今回はチェックボックスということで、
タッチしたらチェックが入ったり、消えたりするアレを実装してみる。
ボタンはSKLabelNodeを使って、frameプロパティを膨らませて、
タッチした位置がその中に含まれるかチェックしたけど、
この辺りの処理はほとんど同じ。

その代わりやらなくちゃいけないことは、
ラベル以外にもチェックする枠、及びレ点の表示を切り替えること。

で、結果的にこんな感じになった。

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

@interface FOOCheckBox : SKSpriteNode

+(instancetype)checkBoxWithTexture:(SKTexture *)texture andText:(NSString *)text;

@property (nonatomic, assign, setter = setChecked:) BOOL checked;

@end

// FOOCheckBox.m
#import "FOOCheckBox.h"

static const float kBetweenMargin = 2.0f;
static NSString *kNodeNameCheckedOff = @"checked.off";
static NSString *kNodeNameCheckedOn = @"checked.on";

@implementation FOOCheckBox

+(instancetype)checkBoxWithTexture:(SKTexture *)texture andText:(NSString *)text
{
    SKTexture *textureOff = [SKTexture textureWithRect:CGRectMake(6/8.0, 3/8.0, 1/8.0, 1/8.0)
                                             inTexture:texture];
    SKSpriteNode *spriteOff = [SKSpriteNode spriteNodeWithTexture:textureOff];
    spriteOff.name = kNodeNameCheckedOff;
    
    SKTexture *textureOn = [SKTexture textureWithRect:CGRectMake(7/8.0, 3/8.0, 1/8.0, 1/8.0)
                                            inTexture:texture];
    SKSpriteNode *spriteOn = [SKSpriteNode spriteNodeWithTexture:textureOn];
    spriteOn.name = kNodeNameCheckedOn;
    
    SKLabelNode *myLabel = [SKLabelNode labelNodeWithFontNamed:@"Menlo Regular"];
    myLabel.text = text;
    myLabel.horizontalAlignmentMode = SKLabelHorizontalAlignmentModeLeft;
    myLabel.verticalAlignmentMode = SKLabelVerticalAlignmentModeCenter;
    myLabel.fontColor = [SKColor blackColor];
    myLabel.fontSize = 14.0f;
    
    const float w = textureOn.size.width + kBetweenMargin + myLabel.frame.size.width;
    const float h = textureOn.size.height;
    
    FOOCheckBox *checkBox = [FOOCheckBox spriteNodeWithColor:[UIColor clearColor]
                                                        size:CGSizeMake(w, h)];

    spriteOff.position = CGPointMake( (w * -.5f) + (textureOff.size.width * .5f), .0f );
    [checkBox addChild:spriteOff];
    spriteOn.position = CGPointMake( (w * -.5f) + (textureOn.size.width * .5f), .0f );
    [checkBox addChild:spriteOn];
    myLabel.position = CGPointMake( (w * -.5f) + kBetweenMargin + textureOn.size.width, .0f );
    [checkBox addChild:myLabel];

    return checkBox;
}

-(void)setChecked:(BOOL)checked
{
    _checked = checked;

    [self childNodeWithName:kNodeNameCheckedOff].alpha = ( _checked ) ? .0f : 1.0f;
    [self childNodeWithName:kNodeNameCheckedOn].alpha = ( _checked ) ? 1.0f : .0f;
}

@end

フォントサイズは、チェックボックスの枠に合わせるので、
あんまし良くないけどコードに書いてある通り。
で、生成後にcheckedプロパティを初期化することを前提にしている。
checkBoxWithTextureで初期化した方が良かったかな。。。
あとは、タッチされたかどうかをframeプロパティを使って判定する。

用途としては、あまりたくさんUIを並べたりしないことを前提に、
BGMやSoundEffectのOn/Offを設定するのに使う。

あと、テクスチャを引数で受け取る必要もないと思う。
なんなら、チェック状態がOnとOffの画像を用意して、
checkBoxWithTextureで読み込んでも良いかも知れない。
ちなみに、タッチの判定に使う範囲は、
CGRectInsetを使ってframeプロパティを8pxほど膨らませてる。

今作ってるアプリに関して言うと、十分に要求を満たしている。

追記 2014/04/30
hiddenプロパティを使えば表示/非表示が切り替えれるので、
こっちを使うのが良いですね。

おしまい。

Leave a Comment