スマートデバイスプログラミング 第4回
Unityで開発してみよう(その3、表示編)

参考資料

GameCanvasについて

・GameCanvasの機能:今週使う変数、メソッド

 ・gc.DrawImage(GcImage,int x,int y);
      座標x,yにGcImageの画像を表示します。
      画像は「GcImage.」にresフォルダの画像ファイル名を足して指定します。
      (例:GcImage.BallYellow)

課題

(1)画面の上から青いボールと黄色いボール、赤いボールが降って来るようにしてみよう。
(2)(↑がうまくいったら)画面内にキャラクターを出して、画面内を左右に動くようにしてみよう。
画面の右半分を押すと右に、左半分を押すと左に動くようにしてみよう。
(3)(↑がうまくいったら)降って来るボールをキャッチするゲームを完成させよう。
・色ごとに1から3点入る
・30秒で取れる得点を競う。
(4)(↑がうまくいったら)動きのアニメーションを付けたり、連続して同じ色を取るとボーナス点が入るように変えてみましょう。

作ったC#のプログラムを添付してください。
(プロジェクトを保存したフォルダのAssets以下にあると思います)
コメント欄には、どこまでやったかと、ゲームのハイスコアを書いてください。

課題の進め方

プログラムの編集を始める前に毎回する準備作業の手順を、別ページに移しました。
「課題の進め方」
※今回は第4回なので、フォルダはk04に改名してください。
サンプルの起動を確認し、スクリプトが編集できる状態になったら、
続きを読み進めてください。

課題1をやってみましょう

  1. まず画像を準備しましょう。
  2. 追加画像データのzipを開くと、青いボールとキャラクターの画像が入っています。
  3. Unity画面の左下部にあるProject窓でResフォルダを開いてみましょう。
  4. BallRedとBallYellowとBlueSkyの画像、Click1,Click2が入っています。
  5. 画像をこのフォルダに追加することで、ゲーム内で新規の画像を使えるようになります。
  6. 青いボールのファイルをProject窓内のBallRed,BallYellowがあるところにドラッグ&ドロップしてみましょう。
  7. 次に、プログラムを編集します。

    5行目(クラスに入った直後)に変数の宣言を書く

    
    const int BALL_NUM = 30;
    int[] ball_x = new int [BALL_NUM];
    int[] ball_y = new int [BALL_NUM];
    int[] ball_col = new int [BALL_NUM];
    int[] ball_speed = new int [BALL_NUM];
    GcImage[] ball_img = new GcImage [BALL_NUM];
    int ball_w = 24;
    int ball_h = 24;
    

    InitGame()に初期化処理を書く

    
    gc.SetResolution(640, 480);
    for(int i =0 ; i < BALL_NUM ; i ++ )
    {
      resetBall(i);
    }
    

    UpdateGame()に更新処理を書く

    
    for(int i =0 ; i < BALL_NUM ; i ++ )
    {
      ball_y[i] = ball_y[i] + ball_speed[i];
      if(ball_y[i]> 480){
        resetBall(i);
      }
    }
    

    DrawGame()の中に描画処理を書く

    
    gc.ClearScreen();
    
    for(int i =0 ; i < BALL_NUM ; i ++ ){
      gc.DrawImage(ball_img[i],ball_x[i],ball_y[i]);
    }
    

    DrawGame()の後、クラスを閉じる括弧の前にメソッドを追加

    
    void resetBall(int id){
      ball_x[id] = gc.Random(0,616);
      ball_y[id] = -gc.Random(24,480);
      ball_speed[id] = gc.Random(3,6);
      ball_col[id] = gc.Random(1,3);
      if(ball_col[id]==1){
        ball_img[id] = GcImage.BallYellow;
      }
      else if(ball_col[id]==2){
        ball_img[id] = GcImage.BallRed;
      }
      else {
        ball_img[id] = GcImage.BallBlue; 
      }
    }
    
  8. セーブして実行してみましょう。

課題2のヒント

キャラクターの画像を用意しましょう。
(Characterフォルダの中の画像をすべてresフォルダに追加しましょう)
※Character_LとCharacter_Rは古いgameCanavs用です。画像の一部を表示する機能は無くなりました。

int player_x = 304;
int player_y = 448;
int player_speed = 3;
int player_w = 32;
int player_h = 32;
GcImage player_img = GcImage.GR0;

if(gc.GetPointerFrameCount(0) > 0 ){
  if(gc.GetPointerX(0) > 320) {
    player_x += player_speed;
    player_img = GcImage.GR0;  
  }
  else {
    player_x -= player_speed;  
    player_img = GcImage.GL0;  
  }
}

gc.DrawImage(player_img,player_x,player_y);



などを適宜追加します。

課題3のヒント

(変数は下記を追加しましょう)

int score = 0;
int time = 1800;

(UpdateGame内に下記の処理を追加しましょう)

timeを1減らす。

if(ボールとキャラクターが接触していたら){
  if(timeが0以上なら){
    scoreをcolの値だけ足す
  }
  ボールの座標等をリセット(resetBallを呼ぶ)
}

※接触判定はballの移動処理のあたり(for文で繰り返されるところ)に追加しましょう
。
※判定には前回つかったあたり判定のメソッドを使いましょう。
※gc.CheckHitRect(ボールの座標、幅、高さ、プレイヤーの座標、幅、高さ)

(draw内に下記の処理を追加しましょう)

gc.SetColor(0,0,0);
if(timeが0以上なら){
  gc.DrawString("time:"+time,0,0);
}
else {
  gc.DrawString("finished!!",0,0);
}
gc.DrawString("score:"+score,0,24);

※第1回の連打カウンターとほぼ同内容です。

などを適宜追加します。


課題4のヒント


//comboの機能を入れるついでに、プレイヤーの色が、
//取ったボールの色に変わるようにしてみましょう。

//変数を追加
int player_dir = 1;
int player_col = 4;
int combo = 0;

//ボールを取った時のスコア加算のあと、下記の処理を追加しましょう。

if(player_col == ball_col[i]) {
  combo++;
  score+= combo;
}
else {
  combo = 0;
}
player_col = ball_col[i];

//スコア表示の後にコンボ数も表示してあげましょう。
gc.DrawString("combo:"+combo,0,48);


//以上で、同じ色を連続して取るとコンボボーナスが加算されるようになります。

//次に、アニメーション処理を改変します。

//画面右半分を押したときの処理に1行追加
player_dir = 1;

//画面左半分を押したときの処理に1行追加
player_dir = -1;

//キャラクター表示部分を下記に変えてみましょう。

if(timeが0以上の時){
  drawCharacter(player_x,player_y, player_col, player_dir, (time%60>=15)?2:1);
}
else {
  drawCharacter(player_x,player_y, player_col, player_dir, 3);
}

//drawが終わった後に下記メソッドを追加

void drawCharacter(int x,int y,int col,int dir,int anim){
  GcImage[] images = new []{
   GcImage.YR0, GcImage.YR1, GcImage.YR2, GcImage.YR3,
   GcImage.RR0, GcImage.RR1, GcImage.RR2, GcImage.RR3,
   GcImage.BR0, GcImage.BR1, GcImage.BR2, GcImage.BR3,
   GcImage.GR0, GcImage.GR1, GcImage.GR2, GcImage.GR3,
   GcImage.YL0, GcImage.YL1, GcImage.YL2, GcImage.YL3,
   GcImage.RL0, GcImage.RL1, GcImage.RL2, GcImage.RL3,
   GcImage.BL0, GcImage.BL1, GcImage.BL2, GcImage.BL3,
   GcImage.GL0, GcImage.GL1, GcImage.GL2, GcImage.GL3,
  };
  int img_num = 0;

  //colやanimやdirでimg_numの値を変える
  img_num = (col-1) * 4 + anim;
  if(dir == -1) img_num += 16;

  gc.DrawImage( images[img_num], x ,y );

}



また、timeが0以上の時しかボールを表示しないようにすると、
ゲームの終了が分かりやすくなります。
(他にも分かりやすくする手段はありますが)

補足

次週について

次回はスマートデバイス上でプログラムを動かします。
スマートデバイスとPCを繋ぐusbケーブルを忘れずに持ってきてください。
(ケーブルには通信ケーブルと充電ケーブルがありますが、通信ケーブルが必要です)

また、macの方は、xcodeの最新版をインストールしておいてください。

よくある質問

意図した画像が表示されない

まず、ファイル名の変更ミスが考えられます。

また、既に同じ番号の画像がResフォルダ内にあった場合、
ドラッグ&ドロップの際、被らない番号に変更されます。
意図した番号から変わっていないか、確認してみましょう。

なお、使用する画像はimg0から順番に存在していない場合、
欠番の分、表示される画像がずれます。
この場合はダミーの画像を置くなどして欠番を埋めると良いでしょう。

透過画像を使いたい

8bitまたは32bitの透過情報付きpngを用意してみてください。

画像を追加してもうまく表示されない

gameCanvasの不具合化もしれません。

青いボールの代わりに、青い空の画像の一部を表示してあげましょう。

if(ball_col[i]==3){
  gc.DrawClipImage(0,ball_x[i],ball_y[i],0,0,24,24);
}
else {
  gc.DrawImage(ball_col[i],ball_x[i],ball_y[i]);
}

キャラクターの代わりにボールを表示してあげましょう。

課題2では。
gc.DrawClipImage(0,player_x,player_y,0,0,32,32);
課題4では。
if(player_col>=3){
  gc.DrawClipImage(0,player_x,player_y,0,0,32,32);
}
else {
  gc.DrawImage(player_col,player_x,player_y);
}

赤いボールや空も出ない場合は、空のgameCanvasを展開しなおしましょう。