2014年12月14日

【書籍】『作りながら覚える iOSプログラミング iOS 7 対応版』沼田哲史




iOS7対応のプログラミング入門書。色々なサンプルアプリを開発しながら、iOS7 & Xcode5時代のプログラム方法を習得できる。

簡単な開発環境の説明と、公開するための章を除く7章で各章ごとに1本づつよくあるタイプのアプリを開発してそれぞれのタイプでどのように開発していけばいいかを説明している。各アプリは簡単とはいえそれなりに実用的でデザインやいくつかの独自追加機能を加えれば実際にリリース可能なのではないかと思える。

あまり前置きに時間をかけずにいきなりコードを書き始められる入門書。こういう型のアプリにはこういうクラスが必要で、そのクラスはそもそも何ができてどういうメソッドがあって……と長々と説明されると退屈して興味を失う人も多いだろう。

本書では、まずこういうアプリを作ります。じゃあプロジェクトを作って……といきなり作業に入れるので飽きる暇はない。実装も段階的に進めるので、沢山コードを入力して最後にようやく動かしてみたらエラーで動かない、なんて心配はない。ちょっと機能を追加して実行、また追加して実行、ちょっと変更して実行と進めるので作っている楽しさを味わえるし変化が目に見えるからコードの意味がわかりやすい。実際の開発にも役立つ習慣づけにいい。

GUI操作の多いIBも必要な部分のスクリーンショットがちゃんとあって再現しやすい。iOS8 & Xcode6だとレイアウト方法などが変わるのでちょっと初心者にはわかりにくかもしれないので改訂版が待たれる。

今回入力するコード、その後で説明する部分だけ取り出したコード断片、章末に完全なコードとそれぞれ背景色を変えて記述していあるのもわかりやすい点。

クラスやメソッドの説明は実際にアプリで使うものにしぼっているのでコンパクト。使っているフレームワークの詳細や他にどんなことができるかなどは後で調べればいいこと。まずはやりたい事、必要なことだけにしぼって実際に動くアプリを作るアプローチは、手っ取り早くアプリを作る体験をして動かす面白さから学ぶのに大事。

章タイトルだけだと従来からあるiOSアプリサンプルと変わらないように見えるが、実際にはiOS7らしい機能を使っていて、自然とiOS7らしいアプリが開発できている。

特にiOS7らしいとことろはSptiteKit,DynamicType,Speech,AutoLayoutなど。

サンプルコードは以下の出版元サイトからダウンロードできる。画像、サウンドリソースなどを使うとか、エラー発生時の比較用にして、コードは自分で入力しながら、覚えるのがよいと思う。
http://isbn.sbcr.jp/72045/

■目次:
第1章 開発環境を整える
第2章 カラーエディタを作る
第3章 時計アプリを作る
第4章 メモ帳アプリを作る
第5章 曲名の読み上げアプリを作る
第6章 動画ビューアを作る
第7章 メディアアートを作る
第8章 地図アプリを作る
第9章 App Storeでアプリを公開しよう

Kindle版もあります。

posted by 永遠製作所 at 17:34| 東京 ☀| Comment(0) | TrackBack(0) | iPhone/iPod touch | このブログの読者になる | 更新情報をチェックする

2014年11月30日

SpriteKitで使うマスクファイルの作り方

SpriteKitのSKCropNodeではマスクノードで指定した画像マスクで画面に表示する部分を制限することができる。そしてそのマスクはmaskNodeに登録したSKNodeであればよいように見えるが、iOS8.1ではPathで作成したマスクは有効に機能していないようで、SKSpriteNodeでしかも画像ファイルから生成したものでなければならないようだ。

ではそのSKSpriteNodeに設定する画像をどう作ればいいのか。

マスク画像はalpha値のみが関係している。SKCropNodeで設定されたマスク画像で覆われた部分のうち、マスク画像のalpha値が0でない部分が切り取られて表示される。感覚的にはalpha値が0の部分が透けて見えるように思えるがそういうことではない。むしろ逆になっている。

マスク画像のalpha値がマスクされる画像に複製されているように想像するといいでしょう。

付属ファイルは星の部分が透けて見えるようになっている。星の外側がalpha=0でこの部分に置かれた画像は見えない。


SKSpriteNode *mask;
// うまくいかない
// mask = [SKSpriteNode spriteNodeWithColor:[SKColor blackColor]
// size: CGSizeMake(100, 100)];
mask = [[SKSpriteNode alloc] initWithImageNamed:@"mask"];
mask.position = myLabel.position;
[self addChild:mask];
self.cropNode = [SKCropNode node];
self.cropNode.maskNode = mask;
self.cropNode.position = CGPointZero;

[self addChild:self.cropNode];


SKCropNodeを付けたSceneにアタッチしたSKNodeが切り取られる。

mask.png
posted by 永遠製作所 at 18:08| 東京 ☁| Comment(0) | TrackBack(0) | iPhone/iPod touch | このブログの読者になる | 更新情報をチェックする

2014年11月29日

SpriteKitの衝突判定処理でのノードの順序(改訂版)

SpriteKitでは、物理体はcontactTestBitMaskを設定しておけば衝突時に-didBeginContact:が呼ばれる。だが、bodyAとbodyBにはどちらの物理体が設定されているかは不定なので、毎回冗長な判定処理をかかないといけない。

というのを昨日書いたが、よく考えればSKPhysicsContactのメセッドにしたほうが使い回しが効くので書き換えた。英語が苦手なので名前が適切かどうかはよくわからない。


@interface SKPhysicsContact (Compare)
-(BOOL)contactsWithName:(NSString *)firstName
and:(NSString *)secondName;
- (void)orderdBodyA:(SKPhysicsBody**)bodyA
bodyB:(SKPhysicsBody**)bodyB;
@end

@implementation SKPhysicsContact (Compare)

-(BOOL)contactsWithName:(NSString *)firstName
and:(NSString *)secondName
{
if ([self.bodyA.node.name isEqualToString:firstName]) {
if ([self.bodyB.node.name isEqualToString:secondName]) {
return YES;
}
} else if ([self.bodyB.node.name isEqualToString:firstName]) {
if ([self.bodyA.node.name isEqualToString:secondName]) {
return YES;
}
}
return NO;
}

- (void)orderdBodyA:(SKPhysicsBody**)bodyA
bodyB:(SKPhysicsBody**)bodyB
{
if ( !bodyA || !bodyB ) return;
if ( self.bodyA.categoryBitMask > self.bodyB.categoryBitMask ) {
*bodyA = self.bodyA;
*bodyB = self.bodyB;
} else {
*bodyA = self.bodyB;
*bodyB = self.bodyA;
}
}

@end
posted by 永遠製作所 at 00:57| 東京 ☁| Comment(0) | TrackBack(0) | iPhone/iPod touch | このブログの読者になる | 更新情報をチェックする

2014年11月28日

SpriteKitの衝突判定処理でのノードの順序

SpriteKitでは、物理体はcontactTestBitMaskを設定しておけば衝突時に-didBeginContact:が呼ばれる。だが、bodyAとbodyBにはどちらの物理体が設定されているのだろうか?これがわからなければ毎回冗長な判定処理をかかないといけない。


if ( ([nameA isEqualToString:kEnemyName] &&
[nameB isEqualToString:kWeponName]) ||
([nameA isEqualToString:kEnemyName] &&
[nameB isEqualToString:kWeponName]) ) {
}


と思って調べたのだが、少なくともアップルの文書中で見る限り衝突時のA, Bの順序は決まっていないようだ。サンプルコードを見ても何が入るかは任意でありどちらになにが来てもいいように対応すべきという姿勢のようだ。

だが、実装者によってはA,Bの比較は固定であるノードは必ずどちらかにしかこないという前提で書かれたコードを見ることがある。どうも一定の規則に従っているようだ。ブログなどを検索したところ、先に生成されたノードが必ずA、後に生成されたノードがBとなるという記述を見つけた。本当にそうなのだろうか?そうだとしてもAPIリファレンスで明記されないかぎり「現時点での実装ではそうなる」という以上の意味はないだろう。

だが毎回両方の比較をするのは大変。考えられるのは二つ、比較用の関数を用意すること。またはある規則に従って並べ替えること。


static inline BOOL CompareEqual(SKPhysicsContact *contact,
NSString *first,NSString *second)
{
if ([contact.bodyA.node.name isEqualToString:first]) {
if ([contact.bodyB.node.name isEqualToString:second]) {
return YES;
}
} else if ([contact.bodyB.node.name isEqualToString:first]) {
if ([contact.bodyA.node.name isEqualToString:second]) {
return YES;
}
}
return NO;
}


これは前出比較を関数にしただけ。


+ (void)orderdBodies:(SKPhysicsContact *)contact
bodyA:(SKPhysicsBody**)bodyA
bodyB:(SKPhysicsBody**)bodyB
{
if ( !bodyA || !bodyB ) return;
if ( contact.bodyA.categoryBitMask > contact.bodyB.categoryBitMask ) {
*bodyA = contact.bodyA;
*bodyB = contact.bodyB;
} else {
*bodyA = contact.bodyB;
*bodyB = contact.bodyA;
}
}


これはカテゴリービットマスクでより上位のビットが1であるほうがA、そうでないほうがBになるようにして返すメソッド。これで比較は決まった順序でできる。
posted by 永遠製作所 at 01:26| 東京 ☀| Comment(0) | TrackBack(0) | iPhone/iPod touch | このブログの読者になる | 更新情報をチェックする

2014年11月27日

SpriteKitのランループ

SpriteKitでは画面描画1フレームごとに下記のランループを実行している。この周期が60fpsであれば1秒間に60回実行されるし、30fpsであれば30回実行される。

iOS7



  1. -update

  2. (Evaluate Actions)

  3. -didEvaluateAction

  4. (Simulate Physics)

  5. -didSimulatePhysics

  6. (Rendering)



かっこ()で囲んだものはフレームワーク側で実行される処理。それ以外がユーザーが書いたコードで実行されるもの。

-updateで、各ループ中で更新すべきゲームの処理を実行。-didEvaluateActionでは、SKActionで設定されたアクションが実行された後で行いたい処理を書く。例えば移動した後の判定だとか、画面外に消えた時の処理など。
-didSimulatePhysicsでは物理シミュレーション実行後の処理。衝突判定などもここで書くほうがいいだろう。

iOS7.png

iOS8



  1. -update

  2. (Evaluate Actions)

  3. -didEvaluateAction

  4. (Simulate Physics)

  5. -didSimulatePhysics

  6. (Apply Constraints)

  7. -didApplyConstraints

  8. -didFinishUpdate

  9. (Rendering)



iOS8ではiOS7の処理に加えてさらに3つの処理が追加された。

iOS8.png
posted by 永遠製作所 at 00:50| 東京 ☔| Comment(0) | TrackBack(0) | iPhone/iPod touch | このブログの読者になる | 更新情報をチェックする