前回まで
- SpriteBuilderの導入
- SpriteBuilderでできたものの確認
- CocoaPodsのインストール
- SpriteBuilderとXCodeで画面遷移する
- SpriteBuilderとSwiftのコンポーネント接続、様々なアニメーションについて
- SpriteBuilderでアニメーションを作る
- SpriteBuilderで作ったオブジェクトをシミュレータに表示する
これらを行いました。
今回のゴール
今回は気球をランダムに生成して、上から降らせていきます。
今回作るゲーム
今回はバルーンショットというゲームを作成する予定です。
もともと僕が作っている
Space Debris
というゲームの続編になります。
これをやっていただければどんなゲームを作ろうとしているか想像がつくかと思います。
ランダムに気球を降らせてみます
気球は生成すれば勝手に落ちていくので、今回はランダムに気球を生成して落としていきます。
まずはコードを書きます。
class GameScene: CCNode {
// 物理ノード
weak var _physicsNode:CCPhysicsNode!
// フレーム毎に呼び出されるメソッド
override func update(delta: CCTime) {
// ランダムに気球を生成します。
if arc4random_uniform(100) == 0 {
// バルーンを生成します。
let balloonNode = CCBReader.load("Parts/BalloonNode")
// 大きさをランダムにします。
balloonNode.scale = Float(arc4random_uniform(25) + 25) * 0.01
// 現在の大きさを取得します。
let width = balloonNode.children[0].contentSizeInPoints.width * CGFloat(balloonNode.scale)
let height = balloonNode.children[0].contentSizeInPoints.height * CGFloat(balloonNode.scale)
// 上部へランダムに表示させます。
balloonNode.position.x = CGFloat(arc4random_uniform(UInt32(self.contentSizeInPoints.width - width))) + width / 2
balloonNode.position.y = self.contentSizeInPoints.height + height
// 物理ノードにバルーンを設置
_physicsNode.addChild(balloonNode)
}
}
}
お世辞にも良いコードとは言えませんが、第一弾のコードとしては十分だと思います。
このコードは機種依存コードなのでこのまま使う事は避けてください。
(端末のパフォーマンスによって挙動が変わります。回避コードは次回紹介致します。)
こちらを実行すれば今回のゴールは達成できます。
今回は上記のコードの解説をしていきます。
updateメソッド
UpdateメソッドはCCNode
に用意されている(正しくはCCSchedulerTarget
プロトコルで定義されている)メソッドです。
FPSの描画のタイミングに呼び出されます。
引数のdelta
は前にupdate
メソッドが呼び出されてからどれくらい時間が経過したかを示す差分の時間が引き渡されます。
本コードが機種依存になっているのは、このdelta
を意識していないコードになっているためです。(機種によってupdateが呼び出される頻度に差が出ます。)
FPSって?
FPSの説明は他のページを見た方が正確な情報が手に入ると思います。
拙いながら簡単に説明しておきます。
FPSはFrames Per Second
の略称です。
OpenGLは一定の時間毎に画面を書き直す(レンダリング)事で画面が動いているように見せてます。
例えばFPS=60
というのは1秒間に60回描画をしている事になります。
通常はFPS=30
が出れば人間の目にはわからないのでFPS=30
が出れば大抵のゲームは問題なく動作します。
Cocos2dでFPSを確認したい場合はこちらをみてください。
自前でFPSを管理すると
- どれくらいのタイミングで呼べば良いか?
- 描画処理と計算処理を別にすべきか?
などの問題を解決しなければなりませんが、Cocos2dを使っていればupdateメソッドだけである程度解決できます。
(updateメソッドで解決できないレベルのゲームを作った事がないのでupdateメソッドだけで解決できない場合の回避策は知りません。。。)
arc4random_uniformメソッド
こちらの解説ページにわかりやすく書かれてます。
上記参考サイトの理由によりrand()
を使わずにarc4random_uniform()
を使用して、乱数を発生させてます。
updateメソッドが呼び出されるたびに0〜99の乱数を発生させ、0が出た場合に気球を出現させてます。
すなわち、1/100で気球が発生してます。
balloonNode.scale
元の気球が大きい画像のため、大きさを変更してます。
Float(arc4random_uniform(25) + 25) * 0.01
0.25〜0.5(正確には0.25〜0.49)の大きさの乱数を発生させて、縮小して気球を生成してます。
乱数で大きさを変えているのは狙いにくい気球と狙いやすい気球を作るためです。
配置
実際の配置は以下の処理で行ってます。
// 現在の大きさを取得します。
let width = balloonNode.children[0].contentSizeInPoints.width * CGFloat(balloonNode.scale)
let height = balloonNode.children[0].contentSizeInPoints.height * CGFloat(balloonNode.scale)
// 上部へランダムに表示させます。
balloonNode.position.x = CGFloat(arc4random_uniform(UInt32(self.contentSizeInPoints.width - width))) + width / 2
balloonNode.position.y = self.contentSizeInPoints.height + height
// 物理ノードにバルーンを設置
_physicsNode.addChild(balloonNode)
balloonNode自体にはContentSizeを設定してないので、子要素の1番目のサイズを取得してscaleに合わせたサイズを取得します。(CGSizeで取得しても良いのですが、アクセスがここだけなので簡略化してます。)
今回はこのようなコードで取得してますが、最終的にはchildren[0]
というコードは無くす予定です。
あとは画面上部に表示させます。
前回はdidLoadFromCCB
で処理をしてたのでself.contentSizeInPoints
が取得できませんでしたが、今回はupdate
内部なのでself.contentSizeInPoints
を取得して計算をしてます。
左右の画面外にでないように配置して、画面の上部に隠れるように配置してます。
これで気球が落ちてきます。
オブジェクトを消していない。
コードを書いていると気付くと思いますが、気球は下に落ちたあともオブジェクト自体は消えてません。
なので、このプログラムを動かし続けるとメモリがどんどん増えていきます。
今回のゲームでは気球が一番下まで落ちたらゲームオーバーにする予定なので、これはこのままでいいです。
次回は
気球は落ちてくるようになりましたが、気球同士が重なってしまいます。
次回はこの回避方法について説明します。
このゲームもよろしくお願いいたします。
Space Debris
気軽に楽しめると思うので、ぜひよろしくお願いいたします!
DLLしていただけると励みになります!