LoginSignup
50
50

More than 5 years have passed since last update.

Sprite KitでFlappy Birdを作る

Posted at

Flappy Birdのクローンやパロディやオマージュはたくさん作られているが、私もSprite Kitで試してみた。
コードはこちら:https://github.com/oinariman/RMFlappyBall

demo.gif

要件

まず、Flappy Birdゲームを構成する要素を分解してみた。
以下の要件を満たせば、Flappy Birdみたいになるはず。

ssc.png

①トリ

  • 中央からやや左に位置。
  • 重力に従って落ちる。
  • タップすると少し上に跳ね上がる。

②床

  • ずっと右から左へ等速でスクロールしている。

③壁

  • ランダムにすきまの空いた壁が、定期的に画面の右端に現れる。
  • 壁は画面の左へ等速で移動する。

④点数

  • 壁がトリより左側へ行くたびに1点加算される。

⑤終了条件

  • トリが床や壁にぶつかったらゲームオーバー。

実装

①トリ

丸いスプライトをトリということにして、中央からやや左に置く。
SKPhysicsBodyのインスタンスを与えて、重力に従って落ちるようにする。

画面を触られたら、トリに上向き速度を与えるようにする:

-(void)touchesBegan:(NSSet *)touches withEvent:(UIEvent *)event {
    SKNode *ball = [self childNodeWithName:@"ball"];
    [[ball physicsBody] setVelocity:
     CGVectorMake(0.0, kFlappingVelocityY)];
}

②床

縞模様が右から左に流れていると、ずっと右に進んでいるように見える。
縞模様テクスチャのスプライトを作り、右から左へ移動してまた元に戻る動作を繰り返させた。

    // 右から左へ行ってまたもとに戻る動きを永遠に繰り返す。
    [floor runAction:[SKAction repeatActionForever:
                      [SKAction sequence:
  @[[SKAction moveTo:CGPointMake(0.0, size.height/2.)
            duration:interval],
    [SKAction moveTo:CGPointMake(self.size.width, size.height/2.) duration:0.0]]]]];

床を静止させておいてテクスチャのアニメーションで済ますことも考えたが、壁の速度と合わせる調整がやりづらいのでやめた。

③壁

壁の配置

上の壁と下の壁を、それぞれランダムに高さを変えて置く。
画面の高さを15分割して、上の壁・穴・下の壁にランダムに割り振ることにした。
これでゲームのチューニングがしやすかった。

- (void)putWalls {
    // 画面の高さを15分割
    CGFloat unit = self.size.height / 15.0;

    // 上の壁の高さ = 高さの最小値 + 乱数
    CGFloat upperWallHeight =
    unit * (arc4random() % (kUpperWallHeightMax - kUpperWallHeightMin)
            + kUpperWallHeightMin);

    // すきまの高さは固定

    // 下の壁の高さ = 画面の高さ - (上の壁の高さ + すきまの高さ)
    CGFloat bottomWallHeight =
    self.size.height - upperWallHeight - unit * kHoleHeight;

    [self putWallWithHeight:upperWallHeight
                          y:self.size.height - upperWallHeight / 2.];
    [self putWallWithHeight:bottomWallHeight
                          y:bottomWallHeight / 2.];
}

でも、よく考えたらこの実装じゃ、3.5インチと4インチで難易度が変わっちゃう。

壁の一生

ゲームの開始から終了まで、定期的に壁が作られ続ける。
それぞれの壁は、画面の右端に生まれ、左向きに等速で画面を通過し、左端で消え去る。
壁の移動速度は、画面を通過するのにかかる時間によって決めることとした。

- (void)putWallWithHeight:(CGFloat)height y:(CGFloat)y {
    SKSpriteNode *wall =
    [SKSpriteNode spriteNodeWithColor:wallColor_
                                 size:CGSizeMake(kWallWidth, height)];
    [wall setPosition:CGPointMake(self.size.width + kWallWidth / 2., y)];

    SKPhysicsBody *body = [SKPhysicsBody bodyWithRectangleOfSize:wall.size];
    [body setAffectedByGravity:NO];
    [body setDynamic:NO];
    [wall setPhysicsBody:body];

    // 右から左へ動かした後消す
    [wall runAction:[SKAction sequence:
  @[[SKAction moveTo:
     CGPointMake(-kWallWidth / 2., y) duration:kTimeTakenForWallGoThroughScreen],
    [SKAction removeFromParent]]]];

    [self addChild:wall];
}

なお、床と壁の移動速度が違うとずれて見えるので、壁の移動速度を基準に計算して、床の移動速度を設定している。

④点数

壁がトリより左側に行けば1点入る。
トリは水平方向に動かないので、壁が右端からトリを越えるまでの時間はあらかじめ計算できる。
そこで、壁を1個作ったあと、その壁が右端からトリに到達するまでの時間が経ったら自動的に1点入るようにした。

// 定期的に壁を作る
- (void)putWallsPeriodically {
    [self runAction:
     [SKAction repeatActionForever:
      [SKAction sequence:
  @[[SKAction waitForDuration:kIntervalBetweenWallProductions],
    [SKAction runBlock:^{
          // 壁を1セット作って置く
          [self putWalls];

          // 壁が右端からトリに到達するまでの時間が経ったら自動的に1点入れる
          [self runAction:
           [SKAction sequence:
  @[[SKAction waitForDuration:kTimeTakenForWallGoThroughScreen * 0.75],
    [SKAction runBlock:^{
               SKNode *ball = [self childNodeWithName:@"ball"];
               // 上空を乗り越えるのは禁止
               if ([ball position].y > self.size.height) {
                   [self gameOver];
               }
               // 1点追加
               else {
                   [self incrementPoints];
               }
           }]]]];
      }]]]]];
}

⑤終了条件

SKPhysicsContactDelegateを使って、トリが床か壁にぶつかったら処理が呼ばれるようにする。


以上の実装に若干の調整と演出を加えて、Flappy Birdっぽくなった。

もっとゲームを面白くするためには、壁の速度やすきまの大きさ、重力の強さ等々をチューニングすることが必要。

ゲームが愛されるには、かわいいグラフィックやアニメーション演出も超大事。

作者が嫌いになっても、私はFlappy Birdが大好きです。

50
50
0

Register as a new user and use Qiita more conveniently

  1. You get articles that match your needs
  2. You can efficiently read back useful information
  3. You can use dark theme
What you can do with signing up
50
50