夏までにiPhone アプリつくってみっか!

趣味でiPhone/Androidアプリを開発し、日々勉強した事を書いています。オープンワールド系レースゲームをUnityで開発中です。

【cocos2d】背景をスクロールさせてみた。えっ、こんなにかんたんなの?

縦スクロールシューティングゲームを作ると宣言しながらもずっと横画面だったこの自作アプリもようやく前回から縦画面になり縦シューらしくなってきました。
今回は背景を付け、それをスクロールさせる事でよりそれっぽくしたいと思います。ようやく黒背景からサヨナラできるわけですが、何でもいいから絵が必要なのでとりあえず描いてみました。


f:id:takujidev:20130420194136p:plain
何でしょうこれ。草原と池と道のようなものがある風景に見えますか?
幅640ピクセルx高さ2000ピクセルで描いてみました。ゲームではこのようなテクスチャーを6枚縦に並べて1ステージとし、2分間で1ステージ分スクロールするイメージで考えています。
それでは、この絵を6枚並べてスクロールさせるプログラムを作ってみます。本来は高さ2000 x 6 = 12000ピクセルの絵を描いてそれを6分割するべきなのでしょうが、大きな絵を描くのがしんどいのでとりあえず同じ絵を6枚並べることにします。
さっそく背景用にクラスを作ります。このクラスはスプライトを保持するだけで自分自身は表示されないのでCCNodeを継承します。
で、完成したのがこのプログラムです。

@implementation MyBackground

- (id)initWithFile:(NSString *)filename height:(float)height count:(NSInteger)count duration:(ccTime)duration
{
    if ((self = [super init])) {
        for (int i = 0; i < count; i++) {
            NSString* file = [NSString stringWithFormat:@"%@%d.png", filename, i];
            CCSprite* background = [CCSprite spriteWithFile:file];
            [self addChild:background];
            background.anchorPoint = ccp(0, 0);
            background.position = ccp(0, i * height);
        }
        CGSize winSize = [CCDirector sharedDirector].winSize;
        id moveBy = [CCMoveBy actionWithDuration:duration position:ccp(0, -(height * count - winSize.height))];
        [self runAction:moveBy];
    }
    return self;
}

@end

引数としてベースとなるファイル名、テクスチャの高さ、テクスチャの枚数、スクロールする秒数を受け取ります。for文でテクスチャの枚数分ループを回し、まずstringWithFormatメソッドでベースファイル名とループカウンターから実際のファイル名を作り出します。用意するファイルの名前は、例えばベースファイル名が"bg"だとすると、"bg0.png"〜"bg5.png"となります。(6枚使う場合)
そのファイル名でCCSpriteのインスタンスを生成し、自分にaddChildします。
次に、バックグラウンドスプライトのアンカーポイントを(0, 0)に設定します。これにより、スプライトの位置決めがわかりやすくなります。
次にスプライトの左下にあるアンカーポイントが親ノード(この場合self)の左下を起点に(0, i * height)の位置に来るようpositionプロパティを設定します。
6枚のスプライトの生成と配置が完了したら、アクションを生成します。
これは、CCMoveByでY方向に高さ*枚数-画面の高さ分の距離をduration時間を掛けて下方向に動かすアクションです。高さ*枚数から画面の高さ分を引くのは最後のスプライトの一番上までスクロールしたところで止めるためです。これをやらないと6毎目が画面外に消えるところまでスクロールしてしまいます。また、マイナス符号をつけるのは下にスクロールするためです。
最後にrunActionすればあとは自動的にスクロールし、最後までスクロールした時点で停止します。

さて、このクラスを使う側の実装はつぎのようになっています。

        MyBackground* background = [[MyBackground alloc] initWithFile:@"bg" height:1000 count:6 duration:120];
        [self addChild:background z:-10];

高さ2000ピクセルの絵を描いたのにheightパラメーターで1000を指定しているのは、この絵がRetina対応の絵だからです。Retina用の絵の2ピクセルがcocos2dの座標では1ピクセル(ポイント)として扱われるので、実際の絵のサイズの半分のサイズとして指定します。ここで間違えて2000と指定するとバックグラウンドの絵がつながらず、黒い帯と絵が交互に表示されてしまいます。

今回使用するのがRetina用の絵という事はRetina対応じゃないiPhone3GS以前の機種用には別な絵が必要になります。が、このアプリはiPhone4以降対応ということで逃げたいと思います。2013年の今現在ではこれが一番現実的な選択肢かなと考えています。
(2013/5/9追記:非Retinaの最新モデルであるiPad miniで使われる事を忘れていました。結局非Retina、Retina3.5インチ、 Retina4インチ全てサポートする事になりました。その方法はこちら。)

今回はこんな画面になりました。

次回は、スクロールに伴い前方から様々な敵キャラが次々と現れるようにしたいと思います。
https://itunes.apple.com/jp/app/beecluster-wu-liaono-zongsukurorushutingugemu/id663801586?mt=8&uo=4&at=10laCt