[6:障害物] cocos2d-iPhoneとSpriteBuilderでゲームを1週間で作ろう

SpriteBuilderをつかって、障害物を設置します。さらに、障害物の上下の高さをランダムにして出現させます。みためだけだと、ほぼ完成と言えるような状態になります。

前回まで

  1. ソフトをインストール。背景画像を設置
  2. 主人公をつくる
  3. 物理演算を導入する
  4. 主人公と背景を動かす
  5. 主人公を飛ばす

SpriteBuilderで障害物オブジェクトを作る

SpriteBuilderで新しくファイルを作ります。 Nodeを選択し、名前はObstacle.ccbとします。         SpriteBuilder SpriteBuilder   続いて、作ったObstacle.ccsに画像やNodeを追加していきます。 まずはObstacle.ccsを開きましょう。(ダブルクリック) SpriteBuilder   続いて、画像を置いていきます。 SpriteBuilder 次に、CCNodeを設置します。 位置やサイズはこの後に設定するので、とりあえず置いてみてください。 SpriteBuilder サイズを調整します。 まずはRootとなるCCNodeのサイズを調整します。(最後に追加したCCNodeではありません。) 幅80, 高さ568と指定します。 CCNode   次に、pipe_topの位置を調整します。 Positionを左上に指定し、Xを50「%」、Yを128に指定します。 Anchor pointのx,yを0.50と0.00にします。 Top 同様にpipe_bottomの位置も調整します。 Positionを左上に指定し、Xを50「%」、Yを228に指定します。 Anchor pointのx,yを0.50と1.00にします。 pipe_bottom 最後にカウント用のCCNodeの設定です。 Positionを左上に指定し、Xを22、Yを574に指定し、サイズを幅36と高さ790にします。 SpriteBuilder   それではこのObstacle.ccbを保存し、MainScene.ccbの上に設置してみましょう。 Obstacle.ccb 上図のように設置できることが確認できたら、設置した障害物を一度削除します。障害物の設置は、SpriteBuilder上ではなく、Xcodeで行います。 それではSpriteBuilderでPublishしたあと、Xcodeに移りましょう。 障害物を格納するための配列を作成します。

[code language=”objc” title=”MainScene.m” highlight=”8″]
@implementation MainScene{
CCSprite *_hero; // SpriteBuilderと接続する主人公のスプライト
CCPhysicsNode *_physicsNode; // SpriteBuilderと接続する全画面の物理ノード
CCNode *_ground1; // SpriteBuilderと接続する地面その1
CCNode *_ground2; // SpriteBuilderと接続する地面その2
NSArray *_grounds; // 地面ループ処理用のArray
NSTimeInterval _sinceTouch; // 最後にタッチしてからどれだけ経過したか
NSMutableArray *_obstacles; // 障害物を格納する配列
}
[/code]

続いて、定数を追加します。

[code language=”objc” title=”MainScene.m” highlight=”2,3″]
static const CGFloat scrollSpeed = 80.f; // スクロール速度の定数を定義
static const CGFloat firstObstaclePosition = 280.f; // 最初の障害物の位置
static const CGFloat distanceBetweenObstacles = 160.f; // 障害物と次の障害物の距離
[/code]

最初の障害物の座標と、障害物と障害物の間の距離を定義します。 続いて、障害物を生成するメソッドを作成します。

[code language=”objc” title=”MainScene.m”]
// 障害物を生成する
– (void)spawnNewObstacle {
CCNode *previousObstacle = [_obstacles lastObject];
CGFloat previousObstacleXPosition = previousObstacle.position.x;
if (!previousObstacle) {
// これが一番最初の障害物オブジェクトになります
previousObstacleXPosition = firstObstaclePosition;
}
// CCBファイルから障害物オブジェクトを読み込み、生成します
CCNode *obstacle = [CCBReader load:@"Obstacle"];
obstacle.position = ccp(previousObstacleXPosition + distanceBetweenObstacles, 0);
[_physicsNode addChild:obstacle];
[_obstacles addObject:obstacle];
}
[/code]

CCBファイルを読み込んで障害物オブジェクトを生成し、先ほど定義した距離の分だけ離して配置しています。 さて、障害物生成メソッドは作成したので、最初の障害物だけ設置しましょう。 didLoadFromCCBに以下を追加します。

[code language=”objc” title=”MainScene.m” highlight=”7,8,9,10,11″]
// CCBファイルからロード
– (void)didLoadFromCCB {
// 地面その1とその2を配列に追加
_grounds = @[_ground1, _ground2];
// タッチ操作可能にする。
self.userInteractionEnabled = TRUE;
// 最初の障害物を設置する
_obstacles = [NSMutableArray array];
[self spawnNewObstacle];
[self spawnNewObstacle];
[self spawnNewObstacle];
}

[/code]

これで3つの障害物を設置することが出来ました。 Flappy fly 7 それでは、障害物が永遠に出続けるようにアップデートメソッドを更新します。

[code language=”objc” title=”MainScene.m”]
// アップデート
– (void)update:(CCTime)delta {
// 主人公のX座標を右に進める
_hero.position = ccp(_hero.position.x + delta * scrollSpeed, _hero.position.y);
// 略…

// 障害物の新規作成
// 画面外に出た障害物を格納する配列
NSMutableArray *offScreenObstacles = nil;
// _obstaclesの中にある障害物のうち、左の画面外に出たものをoffScreenObstaclesに格納する
for (CCNode *obstacle in _obstacles) {
CGPoint obstacleWorldPosition = [_physicsNode convertToWorldSpace:obstacle.position];
CGPoint obstacleScreenPosition = [self convertToNodeSpace:obstacleWorldPosition];
if (obstacleScreenPosition.x < -obstacle.contentSize.width) {
if (!offScreenObstacles) {
offScreenObstacles = [NSMutableArray array];
}
[offScreenObstacles addObject:obstacle];
}
}
// offScreenObstaclesに入っている障害物を親ノードから取り除く
for (CCNode *obstacleToRemove in offScreenObstacles) {
[obstacleToRemove removeFromParent];
[_obstacles removeObject:obstacleToRemove];
// 障害物を取り除いたら、新しい障害物を生成する
[self spawnNewObstacle];
}
}
[/code]

Flappy Fly 7

障害物の位置をランダムにする

障害物をX軸上に規則的に配置することができたので、今度は障害物のY軸の位置がランダムになるようにしましょう。 そのためには障害物のクラスを作成する必要があります。 SpriteBuilderのObstacle.ccbのCustom ClassにObstacleと記述します。 Obstacle.ccb さらに、Code Connectionの設定も行いましょう。 上側のパイプは_topPipe、下側のパイプは_bottomPipeとします。 Top Pipe Bottom Pipe   保存してPublishしたら、Xcodeでの作業に移ります。 Xcodeでは、新しいクラスを作成します。CCNodeのサブクラスとしてObstacleを作成しましょう。 Xcode Xcode Xcode Obstacleが作成できました。 Xcode 続いて実装をしていきましょう。 3.5インチでも4インチでも大丈夫なよう定数を調整しています。

[code language=”objc” title=”Obstacle.m”]
#import "Obstacle.h"

@implementation Obstacle {
CCNode *_topPipe; // 上のパイプ
CCNode *_bottomPipe; // 下のパイプ
}
#define ARC4RANDOM_MAX 0x100000000
// 上のパイプの最小値。3.5インチiPhoneにも考慮しています
static const CGFloat minimumYPositionTopPipe = 128.f;
// 下のパイプの最大値。3.5インチiPhoneにも考慮しています
static const CGFloat maximumYPositionBottomPipe = 440.f;
// 上下のパイプの間の距離
static const CGFloat pipeDistance = 142.f;
// 上のパイプの範囲を計算する
static const CGFloat maximumYPositionTopPipe = maximumYPositionBottomPipe – pipeDistance;
// 障害物の位置をランダムに設定
– (void)setupRandomPosition {
// 乱数は0.f〜1.fの範囲で変動
CGFloat random = ((double)arc4random() / ARC4RANDOM_MAX);
CGFloat range = maximumYPositionTopPipe – minimumYPositionTopPipe;
// 上のパイプの位置を指定
_topPipe.position = ccp(_topPipe.position.x, minimumYPositionTopPipe + (random * range));
// 下のパイプの位置を指定
_bottomPipe.position = ccp(_bottomPipe.position.x, _topPipe.position.y + pipeDistance);
}
@end
[/code]

Obstacle.hにもメソッドの宣言をします。

[code language=”objc” highlight=”5″ title=”Obstacle.h”]
#import <Foundation/Foundation.h>
#import "cocos2d.h"
@interface Obstacle : CCNode {
}
– (void)setupRandomPosition;
@end
[/code]

最後にMainScene.mを修正しましょう。 障害物を生成する際に、位置がランダムになるよう修正します。 まずはクラスをインポートします。

[code language=”objc” title=”MainScene.m” highlight=”2″]
#import "MainScene.h"
#import "Obstacle.h" // 障害物クラスをインポート
[/code]

続いてメソッドに書き加えましょう。

[code language=”objc” title=”MainScene.m” highlight=”10, 12,13″]
// 障害物を生成する
– (void)spawnNewObstacle {
CCNode *previousObstacle = [_obstacles lastObject];
CGFloat previousObstacleXPosition = previousObstacle.position.x;
if (!previousObstacle) {
// これが一番最初の障害物オブジェクトになります
previousObstacleXPosition = firstObstaclePosition;
}
// CCBファイルから障害物オブジェクトを読み込み、生成します
Obstacle *obstacle = (Obstacle *)[CCBReader load:@"Obstacle"];
obstacle.position = ccp(previousObstacleXPosition + distanceBetweenObstacles, 0);
// 位置をランダムにします
[obstacle setupRandomPosition];
[_physicsNode addChild:obstacle];
[_obstacles addObject:obstacle];
}
[/code]

これで障害物の位置がランダムになりました。 FlappyFly 7

表示順を変更する

障害物が地面の前に出てしまっているので、コードを加えて表示順を調整します。 定数の宣言の下あたりに、以下のコードを加えます。

[code language=”objc” title=”MainScene.m”]
typedef NS_ENUM(NSInteger, DrawingOrder) {
DrawingOrderPipes,
DrawingOrderGround,
DrawingOrdeHero
};
[/code]

さらに、didLoadFromCCBにZ軸の表示順を追記します。

[code language=”objc” title=”MainScene.m” highlight=”13,14,15,16,17″]
// CCBファイルからロード
– (void)didLoadFromCCB {
// 地面その1とその2を配列に追加
_grounds = @[_ground1, _ground2];
// タッチ操作可能にする。
self.userInteractionEnabled = TRUE;
// 最初の障害物を設置する
_obstacles = [NSMutableArray array];
[self spawnNewObstacle];
[self spawnNewObstacle];
[self spawnNewObstacle];

// 地面の表示順を変更する
for (CCNode *ground in _grounds) {
ground.zOrder = DrawingOrderGround;
}
_hero.zOrder = DrawingOrdeHero;
}
[/code]

最後にspawnNewobstacleを修正します。

[code language=”objc” title=”MainScene.m” highlight=”12,13″]
// 障害物を生成する
– (void)spawnNewObstacle {
CCNode *previousObstacle = [_obstacles lastObject];
CGFloat previousObstacleXPosition = previousObstacle.position.x;
if (!previousObstacle) {
// これが一番最初の障害物オブジェクトになります
previousObstacleXPosition = firstObstaclePosition;
}
// CCBファイルから障害物オブジェクトを読み込み、生成します
Obstacle *obstacle = (Obstacle *)[CCBReader load:@"Obstacle"];
obstacle.position = ccp(previousObstacleXPosition + distanceBetweenObstacles, 0);
// 表示順を変更します。
obstacle.zOrder = DrawingOrderPipes;
// 位置をランダムにします
[obstacle setupRandomPosition];
[_physicsNode addChild:obstacle];
[_obstacles addObject:obstacle];
}
[/code]

以上で表示順の設定が終わりました。

 

Flappy Fly 7

次回は当たり判定とゲームオーバー、リスタートの設定を行います。

 

[7:完成] cocos2d-iPhoneとSpriteBuilderでゲームを1週間で作ろう

コメントを残す

メールアドレスが公開されることはありません。 * が付いている欄は必須項目です