ゲームの仕上げ

2011年6月3日(金)
北村 真二

タイトル画面

最後に簡単なタイトル画面を作り、ゲーム起動時にはそこから開始されるようにしてみよう。そして、画面タップでゲーム開始、ゲームオーバーやゲームクリアになったら画面タップでタイトルに戻るという流れを作ってみる。

図4:タイトルとゲーム画面の流れ(クリックで拡大)

タイトル画面には「Game Start」という文字を表示しておくことにする、その表示のための画像をプロジェクトに登録して、GameControllerのプロパティーに表示用のUIImageViewを追加する。また、現在表示されている画面がタイトルなのか、ゲームなのかを記録しておく型を以下のように定義しておく。さらに画面クリアとタイトル画面、ゲーム画面を作るメソッドを追加する。

typedef enum {
  MODE_TITLE,	//タイトル
  MODE_GAME,	//ゲーム
} ModeType;

@interface GameController : NSObject {
  ~ 省略 ~
  UIImageView*		imageView;
  ModeType			mode;
}
  ~ 省略 ~
-(void)clearGameView;
-(void)setUpTitle;
-(void)setUpGame;
@end

以下が追加メソッドの内容だ。画面クリアのメソッドは現在GameBoardViewに乗っているサブビューを全て削除している。

//画面のクリア
-(void)clearGameView {
  NSArray*	ary = [gameView subviews];
  for (int i=0; i < [ary count]; i++) {
    UIView*	view = [ary objectAtIndex:i];
    [view removeFromSuperview];
  }
}

タイトル画面の作成はモードタイプの設定と画面クリアを行った後、画面中央にイメージビューを表示している。

//タイトル
-(void)setUpTitle {
  mode = MODE_TITLE;
  [self clearGameView];
  imageView = ;
  [gameView addSubview:imageView];
  imageView.center = CGPointMake(160, 240);
}

ゲーム画面は今まで初期化メソッドにあったビューの作成をここで行うようにしている。先に説明したSEやBGM関係の初期化はそのまま初期化メソッドに残して、BGMの再生開始のみをここで行うようにする。

//ゲーム画面
-(void)setUpGame {
  
    mode = MODE_GAME;
    [self clearGameView];
    isGameClear = NO;
    isGameOver = NO;
    //キャラクターを生成
    //ニンジン
    {
      carotCount = 3;
      int		tileIndex[3] = {10, 55, 66};
      for (int i=0; i < 3; i++) {
        UIImage*	image = [UIImage imageNamed:@"carot_00.png"];
        NSMutableArray*	array = [NSArray arrayWithObject:image];
        GamePieceView*	carot = ;
        tile.item = carot;
        carot.tile = tile;
        carot.center = [tile center];
        carot.state = STATE_STAY;
      }
    }

    //うさぎ
    {
      NSMutableArray*	array = [NSMutableArray array];
      int			i;
      for(i=0; i < 15; i++){
        NSString*	name = [NSString stringWithFormat:@"rabit00_%03d.png", i];
        UIImage*	image = [UIImage imageNamed:name];
        [array addObject:image];
    }
    pieceView = [[[GamePieceView alloc] initWithFrame:CGRectMake(0, 0, 48, 48) 
              Images:array 
              Delegate:self] autorelease];
      pieceView.type = TYPE_RABBIT;
      //配置
      [gameView addSubview:pieceView];
      GameBoardTile*	tile = [self.gameView tileAtIndex:44];
      tile.piece = pieceView;
      pieceView.tile = tile;
      pieceView.center = [tile center];
      //タイマースタート
      [pieceView timerStart];
    }
  
    //オオカミ
    {
      NSMutableArray*	array = [NSMutableArray array];
      int			i;
      for(i=0; i < 15; i++){
        NSString*	name = [NSString stringWithFormat:@"wlof00_%03d.png", i];
        UIImage*	image = [UIImage imageNamed:name];
        [array addObject:image];
    }
    enemyView = [[[GamePieceView alloc] initWithFrame:CGRectMake(0, 0, 48, 48) 
              Images:array 
              Delegate:self] autorelease];
    enemyView.type = TYPE_WLOF;
    enemyView.speed = 50;
    //配置
    [gameView addSubview:enemyView];
    GameBoardTile*	tile = [self.gameView tileAtIndex:22];
    tile.piece = enemyView;
    enemyView.tile = tile;
    enemyView.center = [tile center];
    enemyView.state = STATE_SLEEP;
    //タイマースタート
    [enemyView timerStart];
  }
  
  //ライフ表示
  EffectView*	efView;
  lifeImageArray = [[NSMutableArray array] retain];
  UIImage*	image = [UIImage imageNamed:@"LifeHart.png"];
  for (int i=0; i < 3; i++) {
    efView = [[EffectView alloc] initWith:image];
    efView.isFinishDelete = YES;
    [lifeImageArray addObject:efView];
    [gameView addSubview:efView];
    [efView release];
    efView.center = CGPointMake(320-24-(24*i),32);
  }
  
  [bgmPlayer play];//BGM再生開始
  
  gameTimeCount = 90;	//制限時間
  //タイム表示
  timeLabel = [[UILabel alloc] initWithFrame:CGRectMake(0, 0, 100, 32)];
  [gameView addSubview:timeLabel];
  timeLabel.backgroundColor = [UIColor clearColor];
  timeLabel.textColor = [UIColor whiteColor];
  timeLabel.center = CGPointMake(160, 32);
  [timeLabel release];
  timeLabel.textAlignment = UITextAlignmentCenter;
  timeLabel.font = [UIFont boldSystemFontOfSize:28];
  timeLabel.text = [NSString stringWithFormat:@"%02d:%02d", 
            gameTimeCount/60, 
            gameTimeCount-(60*(gameTimeCount/60))];
  //タイマー開始
  gameTimer = [NSTimer scheduledTimerWithTimeInterval:1.0	//1秒ごとにタイマー実行
                      target:self 
                      selector:@selector(gameTimeCount:) 
                      userInfo:nil 
                      repeats:YES];
  }

そして、タイトル画面、ゲーム画面の切り替えを行うため、GameBoardViewからのタッチアップイベントを受けるデリゲートメソッドの先頭で、モードとフラグなどから判断して処理の切り分けを行う。これにより、タイトル画面でタップすればゲームが開始され、ゲームクリアやゲームオーバーでタップすればタイトル画面に移行できるようになる。

//タッチアップ
-(void) gameBoardViewTouchUp:(GameBoardView*)gmView 
            Location:(CGPoint)touchPt Taps:(int)taps 
            Event:(UIEvent*)event
{
    if(mode==MODE_TITLE){
      [self setUpGame];
      return;
  }
  else if(mode==MODE_GAME && ( isGameClear || isGameOver )){
      [self setUpTitle];
      return;
  }
  
  GameBoardTile*	tile = [gmView tileAtPoint:touchPt];
  if( tile ){
      [pieceView moveWith:tile];
  }
}

サンプル一式は、会員限定特典としてダウンロードできるので、記事末尾をご確認いただきたい。

最後まで読んでくださった皆さま、ありがとうございました。

  • 「ゲームの仕上げ」サンプルプログラム

STUDIO SHIN

家庭用ゲームの企画開発、Mac OS / iOSアプリの開発を主な生業とする。
20年ほど前から家庭用ゲーム開発に携わりファミコンからDS、PSP、Wiiまで幅広く開発。15年前からMac OS Xアプリケーションを開発「DotShotX」「GIFQuickMaker」などを公開。iPhoneアプリ「将棋盤」「DotTouch」「Rabbit Maze」などを開発。開発アプリはアップルのApp Storeで公開中。

連載バックナンバー

Think ITメルマガ会員登録受付中

Think ITでは、技術情報が詰まったメールマガジン「Think IT Weekly」の配信サービスを提供しています。メルマガ会員登録を済ませれば、メルマガだけでなく、さまざまな限定特典を入手できるようになります。

Think ITメルマガ会員のサービス内容を見る

他にもこの記事が読まれています