連載
» 2015年11月12日 05時00分 公開

SwiftのSpriteKitで実装―タワーディフェンスゲームの大枠の作り方とコツiOS SDKとSwiftで始めるゲーム作成入門(2)(3/3 ページ)

[杉本裕樹,マネーフォワード]
前のページへ 1|2|3       

ゲームクリア処理

 ゲームオーバー処理ができたので、次はゲームクリア処理を書いていきます。

 本来はユーザーが自分で味方を設置するのですが、今回は最初から味方を画面上に起きます。そして敵と味方が接触したら敵が消滅してゲームクリアになるようにします。

味方を表示する

 まずは味方を画面に表示します。GameSceneを下のように書き換えてください。

class GameScene: SKScene {
    // ...略
    let char = SKSpriteNode(imageNamed: "Char")
    
    override func didMoveToView(view: SKView) {
        // ...略
       
        char.position = CGPoint(x:50, y:300)
        addChild(char)
    }
    
    // ...略
}

 以降、3行目にあるように「char」は「キャラクター」のインスタンス名であり、char型ではありませんので、注意してください。

 これで味方が画面に表示されるようになりました。

敵と味方の衝突判定――physicsBodyとphysicsWorld

 敵と味方の衝突判定を実装します。まずはGameSceneのdidMoveToViewの中身を下のように書き換えます。

class GameScene: SKScene {
// …略
 
    override func didMoveToView(view: SKView) {
        // …略
        
        physicsWorld.gravity = CGVectorMake(0, 0)
        
        char.position = CGPoint(x:250, y:300)
        char.physicsBody = SKPhysicsBody(rectangleOfSize: char.size)
        addChild(char)
        
        enemy.position = CGPoint(x:50, y:300)
        enemy.physicsBody = SKPhysicsBody(rectangleOfSize: enemy.size)
        addChild(enemy)
    }
    
// …略
}

 今回の修正は下の2つです。

  • charとenemyのphysicsBodyをセット(10・14行目)

 physicsBodyとは物理演算をするためのプロパティです。初期状態ではSKNodeとぶつかっても、すり抜けるし、衝突時に通知がされません。

 physicsBodyをセットすることで、他オブジェクトとぶつかったときに通知が来てすり抜けなくなります。

 今回は敵と味方が衝突時の通知を受け取りたいので「physicsBody」をセットしました。

  • physicsWorldのgravityにCGVectorMake(0, 0)をセット(7行目)

 gravityとはGameScene上のphysicsBodyにかかる重力です。これを0にしないとcharとenemyが下向きに落下してしまうので、0をセットしました。

衝突したときの処理を記述する――physicsWorld.contactDelegate

 charとenemyが衝突できるようになったので、次は衝突したときの処理を記述していきます。GameSceneを下のように書き換えます。

class GameScene: SKScene, SKPhysicsContactDelegate { // 今回修正部分
    override func didMoveToView(view: SKView) {
// …略
 
        physicsWorld.contactDelegate = self // 今回追加部分
        
        char.position = CGPoint(x:250, y:300)
        char.physicsBody = SKPhysicsBody(rectangleOfSize: char.size)
        char.physicsBody?.contactTestBitMask = 0x1 // 今回追加部分
        addChild(char)
        
// …略
    }
 
    func didBeginContact(contact: SKPhysicsContact) {
        state = .GameClear
        enemy.removeFromParent()
        
        let myLabel = SKLabelNode(fontNamed: "HiraginoSans-W6")
        myLabel.text = "ゲームクリア"
        myLabel.fontSize = 45
        myLabel.position = CGPoint(x:CGRectGetMidX(self.frame), y:CGRectGetMidY(self.frame) - 20)
        addChild(myLabel)
    }
}

 15行目のdidBeginContactはphysicsBody同士が衝突したときに呼ばれるメソッドです。今回は衝突時に敵の消去、stateをゲームクリア状態へ変更、「ゲームクリア」ラベルの表示を行っています。

 5行目のphysicsWorld.contactDelegateは衝突用のdelegateです。ここにselfをセットすることで、SKNode同士の衝突時にGameSceneのdidBeginContactが呼ばれるようになります。

 9行目のcontactTestBitMaskは衝突時にdidBeginContactが呼ばれるためのプロパティです。慣れてくれば自然に使えるようになるので、この説明も軽く流し読みするとよいかと思います。

categoryBitMask

 contactTestBitMaskの前にcategoryBitMaskを説明します。categoryBitMaskはphysicsBodyのプロパティです。physicsBodyがどのカテゴリかを表していて、初期値はUIntの最大値(4294967295)です。

 単体では意味がなく、contactTestBitMaskなどとセットで使われることで意味が出てくるプロパティです。

contactTestBitMask

 charとenemy衝突時にdidBeginContactが呼ばれるためには下のどちらかの条件を満たさないといけません。

  • charのcategoryBitMaskとenemyのcontactTestBitMaskの&演算の結果が0以外になる
  • charのcontactTestBitMaskとenemyのcategoryBitMaskの&演算の結果が0以外になる

 式で書くと下のようになります。

(char.physicsBody!.categoryBitMask & enemy.physicsBody!.contactTestBitMask) != 0 ||
(char.physicsBody!.contactTestBitMask & enemy.physicsBody!.categoryBitMask) != 0

 先ほどはchar.physicsBodyのcategoryBitMaskを1にしました。そうすることで1行目の「char.physicsBody!.categoryBitMask & enemy.physicsBody!.contactTestBitMask」が1になり、衝突時にdidBeginContactが呼ばれるようになりました。

次回からはiOS 9から登場したGamePlayKitの機能も

 今回はゲーム全体の流れを作ってみましたが如何でしたでしょうか。今回作成したコード「TowerDefense.zip」は、こちらからダウンロードできます

 次回からは一つ一つの要素をブラッシュアップしてさらにゲームらしくしていこうと思います。iOS 9から登場したGamePlayKitの機能も徐々に使っていきます。

筆者紹介

杉本裕樹

田町のベンチャーで働くエンジニア。

仕事ではiPhoneアプリの開発やRailsを使ったWebサービス開発を行っている。最近のマイブームはUnityを使った3Dゲーム開発。


前のページへ 1|2|3       

Copyright © ITmedia, Inc. All Rights Reserved.

RSSについて

アイティメディアIDについて

メールマガジン登録

@ITのメールマガジンは、 もちろん、すべて無料です。ぜひメールマガジンをご購読ください。