iOS 8で追加されたSprite Kitの新機能をつまみ食い

iOS 8ではSpriteKitにかなり変更が加えられました。

概要はWhat’s New in iOS: iOS 8.0に、 詳細はSpriteKit Changesにまとめられています。
日本語だと、iOS 8 for Developers - Apple Developerに少しだけ記述があります。

※ ちなみに、iOS 7.1での変更点はiOS 7.0 to iOS 7.1 API Differencesにあり、ほんの少しだけです。

今回は、3D関連や物理エンジン、アニメーション関連など多数のアップデートがあり、Nodeの種類も増えました。

また、XcodeのGUIでシーンのコンテンツも編集できるようになりました。
Gameテンプレートを利用してプロジェクトを作成すると、sksファイルが用意されていてGUIでそのまま編集可能になっています。)

正直な所、変更点が多すぎて全て追えていないのですが、気になったものをいくつか触ってみました。

SKFieldNode

Fieldは「場」といったところでしょうか。 バネや放射状の物理効果を与えることができるようです。

かなりいろいろなことができるようで、まだ把握しきれていません。 ひとまず箱の周りを円がバネっぽく動くサンプルを作りました。


SKFieldNode

SKLightNode

光を追加するノードです。ドラクエの松明的な表現が簡単にできそうでありがたいです。 サンプルでは画面右上に置いています。

箱は光を受けているのがわかると思います。円は光の影響を受けていません。 (SKSpriteNodelightCategoryBitMaskが設定できため。どうやらSKSpriteNodeにしか適用できないようです。)


SKFieldNode

SKView#showsPhysics

Nodeに設定したSKPhysicsBodyを枠線で表示してくれる機能です。 iOS 7.1で追加されていたようです。知りませんでした。 これでようやく他の物理エンジンと同じように、物理体を目で確認しながらデバッグできるようになります。
色がかなり見づらいのが気になりますが…。


showsPhysics

今回はここまで。ソースコードはこちらです。
sj-posts-apps/iOS8Features at master · tnantoka/sj-posts-apps

他の作業をする中で新機能を触ることがあれば、また追記します。

コメント

iOS向けミニゲームをリリース&ソースコードを公開しました

以前は初作品としてRPGを作ろうとしていたんですが、
いきなり規模が大きすぎたのもあり断念してしまいました。

今回はとにかくストアにリリースすることを目標に、小さなゲームを作ってみました。

おそらく最後のObjective-Cアプリになると思います。
次からはSwiftで書く予定。


Tetloop

某パズルゲームの棒を主人公(?)にしたゲームです。
ひたすらブロックを消していくだけの単純なものです。

トイレや電車での暇つぶしにでもどうぞ。

ソースコードは以下に公開しています。

tnantoka/teloop

特別なことは何もしていませんが、実際にストアに並んでいるアプリのソースなので、参考になる点があるかもしれません。
※ 音楽やフォントなどの素材は取り除いていますのでご了承ください。

楽をするために、ゲーム画面とオープニング画面以外はUIKitで実装しています。
(ボタンの処理や設定画面の作成をSprite Kitでやると手間のため)

需要があれば解説記事とかも書きたいと思いますので、
ここなんでこんなことしてんの?とかあればお気軽にどうぞ。

それでは、よろしくお願いします。

コメント

「Sprite Kit iPhone 2Dゲームプログラミング」を読みました

現時点で日本語唯一のSprite Kit本を読んでみました。

Sprite Kit iPhone 2Dゲームプログラミング

以下の3つのサンプルゲームの作り方が入った実践的な内容になっており、この1冊を読めばカジュアルゲームをリリースできるところまでいけると思います。

  • シューティングゲーム(落ちてくる隕石をミサイルで迎撃)
  • レースゲーム(他の車にぶつからないように走る)
  • アクションゲーム(襲ってくるゾンビを忍者が手裏剣で倒す)

個人的に最もためになったのは、

  • 第4章のパーティクルの実践的な使い方
  • 第5章のゲーム全体のフローの設計

の2つの内容でした。

パーティクルは、本サイトも含め「Xcodeでsksファイルを作って、それをSKEmitterNodeに読み込めばほら簡単」という説明で終わっているものが多いんですが、この本ではロケットの噴射に見せかける例を使って、実践的なカスタマイズが紹介されています。

フロー設計については、UIKitと組み合わせるのか、全部Sprite Kitで作るのか、それぞれのメリット・デメリットなどがわかりやすく解説されています。

というわけで、オススメの1冊です。

コメント

更新再開

長らく更新できていなかった本サイトですが、 iOS 8時代に突入するこのタイミングで心機一転して、 またぼちぼち投稿していこうと思いますので、よろしくお願いします。

コメント

エンディング

所謂スタッフロール。

設定ファイルで表示する内容を指定します。
(Xcodeのインデントがなんか変で見づらい…)

roll_ending.json

{
    "type" : "roll",
    "roll" : [
              {
              "text" : "Prototype Quest",
              "size" : 24.0
              },
              {
              "text" : "Staff",
              "size" : 20.0
              },
              {
              "text" : "tnantoka",
              "size" : 20.0
              },
              {
              "text" : "Special Thanks",
              "size" : 24.0
              },
              {
              "text" : "Browser Quest",
              "size" : 20.0
              },
              {
              "text" : "mosamosa font",
              "size" : 20.0
              },
              {
              "text" : "Fin",
              "size" : 28.0
              }
              ],
    "speed" : 4.0,
    "next" : "title"
}

これを下から上へスクロールさせながら表示して、 終わったらnextで指定されているタイトル画面に遷移させます。

SJRollScene.m

- (void)createSceneContents {

    _labelNodes = @[].mutableCopy;
    
    for (NSDictionary *label in self.sceneData[@"roll"]) {
        SKLabelNode *labelNode = [SKLabelNode labelNodeWithFontNamed:FONT_NORMAL];
        labelNode.text = label[@"text"];
        labelNode.fontSize = [label[@"size"] floatValue];
        [_labelNodes addObject:labelNode];
    }
    
    [self performSelector:@selector(showNextLabelNode) withObject:nil afterDelay:DELAY];
    
}

- (void)showNextLabelNode {
    
    SKLabelNode *labelNode = _labelNodes.firstObject;
    labelNode.position = CGPointMake(CGRectGetMidX(self.frame), 0);
    [self addChild:labelNode];

    CGFloat y;
    CGFloat duration;
    if (_labelNodes.count > 1) {
        y = CGRectGetHeight(self.frame) + CGRectGetHeight(labelNode.frame);
        duration = [self.sceneData[@"speed"] floatValue];
    } else {
        y = CGRectGetMidY(self.frame) + CGRectGetMidY(labelNode.frame);
        duration = [self.sceneData[@"speed"] floatValue] / 2.0f;
    }

    SKAction *moveX = [SKAction moveByX:0 y:y duration:duration];
    SKAction *run = [SKAction runBlock:^{
        if (_labelNodes.count > 1) {
            [_currentLabelNode removeFromParent];
            [_labelNodes removeObjectAtIndex:0];
            [self showNextLabelNode];
        } else {
            self.nextScene = self.sceneData[@"next"];
            [self performSelector:@selector(loadNextScene) withObject:nil afterDelay:DELAY];
            return;
        }
    }];
    SKAction *sequence = [SKAction sequence:@[moveX, run]];
    [labelNode runAction:sequence];

    _currentLabelNode = labelNode;
}

ラベルの移動はSKActionで実施。
移動と次のラベルを表示するアクションをそれぞれ用意して、sequenceにまとめてラベルに適用しています。

できました。


やっぱり最後はFin

だいぶ必要そうな画面はそろってきました。
そろそろ戦闘などのメイン部分に手を出したいと思います。

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

コメント

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