Cocos2d v3 気球を重ならないようにするのとリファクタリング

## 前回まで
* [SpriteBuilderの導入](http://qiita.com/syou007/items/9e6202a88495757dda5f)
* [SpriteBuilderでできたものの確認](http://qiita.com/syou007/items/1cd8b0d2deeb5acd38f1)
* [CocoaPodsのインストール](http://qiita.com/syou007/items/957dd2d9c3ff1b2a7c6d)
* [SpriteBuilderとXCodeで画面遷移する](http://qiita.com/syou007/items/9bebb01aff70dec0e3f3)
* [SpriteBuilderとSwiftのコンポーネント接続、様々なアニメーションについて](http://qiita.com/syou007/items/1c1a2b450cc93098495c)
* [SpriteBuilderでアニメーションを作る](http://qiita.com/syou007/items/bdcd3921a033ed967016)
* [SpriteBuilderで作ったオブジェクトをシミュレータに表示する](http://qiita.com/syou007/items/7492245b28133df94dd1)
* [気球をランダムに生成して降らせる](http://qiita.com/syou007/items/9b7e98afa6afd602f7f7)


これらを行いました。

## 今回のゴール
前回は気球が重なって表示されてしまう状態で終わったので、今回は気球同士が重ならないようにします。
この対応はすぐに終わるので、終わった後は次回に向けてリファクタリングをしていきます。

### 今回作るゲーム
今回はバルーンショットというゲームを作成する予定です。
もともと僕が作っている

![id995207358.png](https://qiita-image-store.s3.amazonaws.com/0/79216/c0a0da78-4bac-2257-9a1d-0594e953ba1e.png)
[Space Debris](https://itunes.apple.com/jp/app/id995207358)
というゲームの続編になります。

これをやっていただければどんなゲームを作ろうとしているか想像がつくかと思います。

## 気球が同士が重ならないようにする。
気球同士が重ならないようにするためには、気球同士に当たり判定をつければいいのです。

![1.png](https://qiita-image-store.s3.amazonaws.com/0/79216/4ce7995d-03bc-8eb8-fba7-83e1e927f0fd.png "1.png")
[以前](http://qiita.com/syou007/items/7492245b28133df94dd1#balloonnode%E3%82%92%E5%A4%89%E6%9B%B4)設定した物理エンジンを受ける箇所を上記のように変更します。

今回はこれらの設定項目について説明をしていきます。

```
以下の項目はリファレンスを読んで説明しているのではなく、実体験として理解した内容を書いていますので誤っている箇所もあるかもしれません。
もし誤りを見つけた場合はコメントに記載していただけると助かります。
```

### Physics shape
これは当たり判定を四角にするか丸にするかを選択できます。
今回は円形のオブジェクトなので丸である`Circle`を選択します。

### Corner radius
障害物の当たり判定するエリアの広さを指定します。
今回は半径`250`で作成してます。

### Dynamic/Static
障害物が動くかどうかを指定します。
Dynamicにすると物体同士が衝突した際に自分も影響します。
一方でStaticにすると物体同士が衝突しても動きません。
Staticは地面とか壁等の物体が当たっても動かない場合に使用してください。

今回は気球同士の衝突でお互い影響を受けて欲しいので`Dynamic`にしてます。

### Affected gravity
重力の影響を受けるかどうかを指定します。
重力は親ノードである`Physics Node`に定義できます。
今回は重力に影響するのでチェックをつけます。

### Affected rotation
衝突時に回転にも影響を受けるかどうかを指定します。
物体同士が衝突すると、物体が回転する場合があります。
その判定を自動でやってくれますが、今回はチェックしません。
気球は常に下を向いてて欲しいからです。

### その他
他の項目についてはまたの機会に説明できたらします。

## 実行してみましょう
これで上記で設定した当たり判定部分が重なることがなくなりました。
気球の下の方は・・・まぁ、重なっても愛嬌ということで先に進みます。

## リファクタリング
現在のコードは主に`GameScene`に書いています。
今回は登場するオブジェクトの種類が少ないのでこれでも良いのですが、様々なオブジェクトが登場してくるとなると`GameScene`が肥大化してきます。
`***Scene`というのはMVCモデルに当てはめるとControllerの存在に近いので、あまり太らせないようにしていきます。

という事で、早速リファクタリングを始めていきましょう！

### SpriteBuilderで作った気球へアクセスできるようにします。
![2.png](https://qiita-image-store.s3.amazonaws.com/0/79216/2a055a68-7c3b-cce5-710a-b7b32de64ae5.png "2.png")
この図のように`BalloonNode`の名前で設定します。

また、気球の大きさを取得したいので以下のSpriteにも名前をつけます。
![3.png](https://qiita-image-store.s3.amazonaws.com/0/79216/2ce4c11c-8ed3-2007-3349-08c833121b93.png "3.png")
`_balloonSprite`という名前をつけておきましょう。

保存したら忘れずに`Publish`しましょう！

### 気球の生成ロジックをBalloonNodeに移します。
内部のプログラムは以下のようになります。

```swift:BalloonNode.swift
// 気球表示ノード
class BalloonNode: CCNode {
    // 気球本体のSprite
    weak var _balloonSprite:CCSprite!
    
    // 気球生成処理
    func didLoadFromCCB() {
        // 大きさをランダムにします。
        self.scale = Float(arc4random_uniform(25) + 25) * 0.01
    }
    
    // 画面サイズを受け取って気球を生成する位置を設定します。
    func setInitPosition(windowSize:CGSize) {
        // 現在の大きさを取得します。
        let width = _balloonSprite.contentSizeInPoints.width * CGFloat(self.scale)
        let height = _balloonSprite.contentSizeInPoints.height * CGFloat(self.scale)
        
        // 画面上部へランダムに表示させます。
        self.position.x = CGFloat(arc4random_uniform(UInt32(windowSize.width - width))) + width / 2
        self.position.y = windowSize.height + height
    }
}
```

以前は`children[0]`のような不確定要素がありましたが綺麗になくなりました！
こういう点はSpriteBuilderの便利なところです。
あ、今回は良いのですが大きめのプロジェクトの場合は[このように](http://qiita.com/syou007/items/1c1a2b450cc93098495c#scene%E3%82%92%E6%A0%BC%E7%B4%8D%E3%81%99%E3%82%8B%E3%82%B0%E3%83%AB%E3%83%BC%E3%83%97%E3%82%92%E4%BD%9C%E6%88%90%E3%81%97%E3%81%BE%E3%81%99)グループを作成しておくと後々の管理が楽になります。

ちなみに_balloonSpriteへweakをつけている理由は[こちら](http://qiita.com/syou007/items/51f2342850e408739cc9)に書いてます。
weakをまだ理解していない方は良ければ読んでください。

### 気球生成する際のロジック
呼び出す方のロジックはこうなります。

```swift:GameScene.swift
class GameScene: CCNode {
    // 物理ノード
    weak var _physicsNode:CCPhysicsNode!
    
    // フレーム毎に呼び出されるメソッド
    override func update(delta: CCTime) {
        // ランダムに気球を生成します。
        if arc4random_uniform(100) == 0 {
            // バルーンを生成します。
            let balloonNode = CCBReader.load("Parts/BalloonNode") as! BalloonNode
            
            // 気球の初期表示位置を設定
            balloonNode.setInitPosition(self.contentSizeInPoints)
            
            // 物理ノードにバルーンを設置
            _physicsNode.addChild(balloonNode)
        }
    }
}
```

だいぶスッキリしましたね！
後はデグレが発生していない事を確認してみてください！

## Objective-c/Swiftにはこれだというフレームワークが存在しない
蛇足になりますが、iPhoneやAndroid開発にはWeb業界には当たり前にあるMVCフレームワークがありません。
なので、MVCモデルを導入しようとした場合は自分で検討して組み込んでいくしかありません。
そして、それはとても敷居が高い事なのでとにかく様々なプロジェクトを作って経験を積んでいかなければなりません。

また、テストを行う習慣もWebほどはありません。
これは上記のフレームワークが確立されていないため、テストが難しいのとUIを多くいじるのでテストコードが煩雑になるためです。
（そもそも、業界の成熟度が低い事も一つの理由でしょう。）

## 次回は
フリックで弾を飛ばすための準備をします。
いよいよParticleを使っていきます。
[Particleの説明](http://qiita.com/syou007/items/83bfb2dcc52243769180)に続きます。