「Sprite Kitでブロック崩し」を書きました

iOS Advent Calendar 2013 - Qiita [キータ]に出来心で投稿してみました。

iOS - Sprite Kitでブロック崩し - Qiita [キータ]

こんな感じのブロック崩しを作るhello, worldものです。

お時間のある方は目を通してくみてください。

「この記事を読めば、とりあえずSprite Kitをはじめられる」みたいな記事にしたくて、 このサイトのチュートリアルに書いたことをコンパクトにまとめようと思ったんですが、 結局かなり長文になってしまいました。 なかなか難しいですね…。

あと、英訳もしようと思ったんですが全然間に合いませんでした。 気が向いたらまた手を加えます。

ただ、

)

の画像はわりと自信作です。 Sprite Kitの登場人物が、なんとなく把握いただけるのではないでしょうか。

さて、次からはまたRPGの製作に戻ります。 (年内リリースが絶望的になってきましたが…)

コメント

チャプター

章とサブタイトルを表示して次のシーンへ進むだけの単純なもの。

設定ファイルでは表示内容とnextを指定。

chapter_1.json

{
    "type" : "chapter",
    "title" : {
        "en" : "CHAPTER 1",
        "ja" : "第一章"
    },
    "subtitle" : {
        "en" : "THE MANIPULATOR & THE SUBSERVIENT",
        "ja" : "利用する者されるもの者"
    },
    "next" : "story_opening"
}

これを画面に表示して、一定時間まった後次のシーンを読み込む。

SJChapterScene.m

- (void)createSceneContents {
    
    SKLabelNode *titleLabel1 = [SKLabelNode labelNodeWithFontNamed:FONT_NORMAL];
    titleLabel1.text = self.sceneData[@"title"][[SJUtilities lang]];
    titleLabel1.fontSize = 28.0f;
    titleLabel1.position = CGPointMake(CGRectGetMidX(self.frame), CGRectGetMidY(self.frame) + MARGIN);
    titleLabel1.verticalAlignmentMode =SKLabelVerticalAlignmentModeBottom;
    [self addChild:titleLabel1];
    
    SKLabelNode *titleLabel2 = [SKLabelNode labelNodeWithFontNamed:titleLabel1.fontName];
    titleLabel2.text = self.sceneData[@"subtitle"][[SJUtilities lang]];;
    titleLabel2.position = CGPointMake(CGRectGetMidX(self.frame), CGRectGetMidY(self.frame) - MARGIN);
    titleLabel2.fontSize = 20.0f;
    titleLabel2.verticalAlignmentMode =SKLabelVerticalAlignmentModeTop;
    [self addChild:titleLabel2];
    
    self.nextScene = self.sceneData[@"next"];
    [self performSelector:@selector(loadNextScene) withObject:nil afterDelay:DELAY];
}

できました。


秀逸なサブタイトル

以上。

ソースコード: sj-prototype-apps/SJRolePlaying at master · tnantoka/sj-prototype-apps

コメント

宝箱を開ける

画面上のキャラクターを別のキャラクターに入れ替えます。
なくても何とかなりそうですが、宝箱を開ける演出とかしたいので一応用意しておきます。

まずは設定。

「これじゃ!」とメッセージを表示した後、replaceイベントでc2というキャラクターをc3に入れ替え。
その後またメッセージを表示。

という内容です。

story_prompt.json

{
    "type" : "story",
    "map" : "map_shop",
    "events" : {
        "c1" : {
            "type" : "message",
            "message" : {
                "en" : "Here you are!",
                "ja" : "これじゃ!"
            },
            "next" : "c1a"
        },
        "c1a" : {
            "type" : "replace",
            "from" : "c2",
            "to" : "c3",
            "next" : "c1b"
        },
        "c1b" : {
            "type" : "message",
            "message" : {
                "en" : "Take good care of it.",
                "ja" : "お主の分身じゃ。大切にするんじゃぞ。"
            },
            "next" : "story_replace"
        }
    }
}

キャラクターの入れ替えは、SJMapNodeにメソッドを追加して対応。

- (void)replaceCharacterNodeFrom:(NSString *)fromName to:(NSString *)toName {
    
    SKNode *fromNode = [self childNodeWithName:fromName];
    SKNode *toNode = [self newCharacterNode:toName];
    
    toNode.position = fromNode.position;
    
    [fromNode removeFromParent];
    [self addChild:toNode];
}

それをSJStorySceneから呼び出します。

- (void)processEvent:(NSString *)name {
    
    /* 省略 */

    } else if ([event[@"type"] isEqualToString:@"replace"]) {
        [[self mapNode] replaceCharacterNodeFrom:event[@"from"] to:event[@"to"]];
        [self processEvent:event[@"next"]];
    }
}

完成。


モシャス

いい感じです。

ソースコード: sj-prototype-apps/SJRolePlaying at master · tnantoka/sj-prototype-apps

コメント

主人公の名前を入力

これも昔からお馴染み、「君の名前は?」イベント。
顔見知りなのに名前を知らない不思議。

Confirmと同じくUIAlertViewで済ませます。

まずは設定ファイル。

story_prompt.json

{
    "type" : "story",
    "map" : "map_shop",
    "events" : {
        "c1" : {
            "type" : "message",
            "message" : {
                "en" : "Hi,",
                "ja" : "やあ。"
            },
            "next" : "c1c"
        },
        "c1c" : {
            "type" : "prompt",
            "message" : {
                "en" : "What is your name?",
                "ja" : "君の名前は?"
            },
            "key" : "username",
            "next" : "c1a"
        },
        "c1a" : {
            "type" : "message",
            "message" : {
                "en" : "<username>...OK, Welcome <username>!",
                "ja" : "<username>か、いい名前だ。よろしく、<username>!"
            },
            "next" : "story_prompt"
        }
    }
}

まずは、「やぁ」とメッセージを表示。
その後テキスト入力用のアラートを表示して、入力内容をkeyに指定されているusernameをキーにNSUserDefaultに保存します。
そして、保存された内容を使ってメッセージを表示します。

アラート表示は以下のような実装。

SJStroyScene.m

- (void)processEvent:(NSString *)name {
    
    /* 省略 */

    } else if ([event[@"type"] isEqualToString:@"prompt"]) {
        
        NSString *message = event[@"message"][[SJUtilities lang]];
        
        __weak UIAlertView *alertView = [UIAlertView alertViewWithTitle:nil message:message];
        alertView.alertViewStyle = UIAlertViewStylePlainTextInput;
        [alertView addButtonWithTitle:NSLocalizedString(@"OK", nil) handler:^{
            NSString *text = [alertView textFieldAtIndex:0].text;
            NSString *key = event[@"key"];
            [[NSUserDefaults standardUserDefaults] setObject:text forKey:key];
            [self processEvent:event[@"next"]];
        }];
        [alertView show];
        
    }

}

メッセージ内にある<username>は以下の処理で置換されます。

- (NSString *)replaceKeys:(NSString *)message {
 
    NSMutableString *replaced = message.mutableCopy;
    NSError *error = nil;
    NSRegularExpression *regexp = [NSRegularExpression regularExpressionWithPattern:@"<([^>]+)>" options:0 error:&error];
    if (error) {
        NSLog(@"%@", error.localizedDescription);
    }
    
    NSMutableArray *keys = @[].mutableCopy;
    [regexp enumerateMatchesInString:message options:0 range:NSMakeRange(0, message.length) usingBlock:^(NSTextCheckingResult *result, NSMatchingFlags flags, BOOL *stop) {
        NSString *key = [message substringWithRange:[result rangeAtIndex:1]];
        [keys addObject:key];
    }];
    
    for (NSString *key in keys) {
        [replaced replaceOccurrencesOfString:[NSString stringWithFormat:@"<%@>", key] withString:[[NSUserDefaults standardUserDefaults] stringForKey:key] options:0 range:NSMakeRange(0, replaced.length)];
    }
    
    return replaced;
}

動作確認してみます。

入力。


黒歴史になりがち

表示。


馴れ馴れしい

できました。

ソースコード: sj-prototype-apps/SJRolePlaying at master · tnantoka/sj-prototype-apps

コメント

はい・いいえの確認

昔ながらのお使いゲーでお馴染み、はい・いいえの確認。
はいと言うまで前に進ませてくれません。

専用のNodeを作ってもいいのですが、今回は手抜きでUIAlertViewで済ませます。

設定ファイルは以下のとおりです。

story_confirm.json

{
    "type" : "story",
    "map" : "map_shop",
    "events" : {
        "c1" : {
            "type" : "confirm",
            "message" : {
                "en" : "OK?",
                "ja" : "やってくれるな?"
            },
            "yes" : "c1y",
            "no" : "c1n"
        },
        "c1y" : {
            "type" : "message",
            "message" : {
                "en" : "Thank you!",
                "ja" : "おぉ、やってくれるか!では頼んだぞ。"
            },
            "next" : "story_confirm"
        },
        "c1n" : {
            "type" : "message",
            "message" : {
                "en" : "…",
                "ja" : "…。"
            },
        }
    }
}

Yesをタップされるとc1yNoをタップされるとc1nに進むようにします。1

SJStroyScene.m

- (void)processEvent:(NSString *)name {
    
    NSDictionary *event = self.sceneData[@"events"][name];

    if (event) {
        [[self playerNode] removeAllActions];
    }

    if ([event[@"type"] isEqualToString:@"message"]) {
        _state = SJStorySceneStateMessage;
        [self messageNode].message = event[@"message"][[SJUtilities lang]];
        [self messageNode].hidden = NO;
        self.nextScene = event[@"next"];
        
    } else if ([event[@"type"] isEqualToString:@"confirm"]) {
        
        NSString *message = event[@"message"][[SJUtilities lang]];
        
        UIAlertView *alertView = [UIAlertView alertViewWithTitle:nil message:message];
        [alertView addButtonWithTitle:NSLocalizedString(@"Yes", nil) handler:^{
            [self processEvent:event[@"yes"]];
        }];
        [alertView addButtonWithTitle:NSLocalizedString(@"No", nil) handler:^{
            [self processEvent:event[@"no"]];
        }];
        [alertView show];
        
    }
    
}

できました。


はいと言うまで許さない

次はテキスト入力を、これもUIAlertViewを使って実装予定。

ソースコード: sj-prototype-apps/SJRolePlaying at master · tnantoka/sj-prototype-apps

  1. BlocksKitを使用しています。 

コメント

SpriteKitではじめる2Dゲームプログラミング Swift対応 (Smart Game Developer)