スマートデバイスプログラミング 第2回
Unityで開発してみよう(その1、基礎文法編)

View(画面内の各要素)について

Scene/Game View(左側)
   Scene:レイアウトを確認したり、編集したりする画面
   Game:ゲーム画面(実行中はゲーム画面が前面に出て来ます)

Hierarrchy View(中央上)
   シーン上にあるオブジェクトを管理する為の画面

Project View(中央下)
   プロジェクト内にある物を管理する為の画面

Inspector/Console View(右側)
   Inspector:各オブジェクトの詳細を閲覧、設定する画面
   Console:実行時のエラーなどを表示する画面
   (エラーが出たらConsoleのタブを押して確認してみましょう)

レイアウトは自由に変更できます。
Window→Layouts→RevertFactorySetteinで戻せます。

C#について

C#でのプログラムの記載例

GameCanvasについて

「作りたい物を手軽に簡単に作る」為のライブラリーです。

開発者は「Game.cs」に行いたい処理を書き加えていきます。
画像や音を使いたい場合は「Res」フォルダに足していきます。

一般的なUnityでのゲームの作り方(オブジェクトを配置、設定)とは
色々異なりますので、気になる方は、Unity公式ドキュメントや
過去のテキスト(GameCanvasを使用しないバージョン)を
ご参照ください。

・Game.csの構成。

InitGame(){
  //起動時に1回だけ呼ばれます。
  //ここに初期化処理を書きます。
}

UpdateGame(){
  //1フレーム(初期値は1/60秒ですが、設定で変更できます)毎に呼ばれます。
  //ここに動きの処理を入れていきます。
}

DrawGame(){
 //1フレーム事に呼ばれます。ここに描画の処理をまとめます。
  //上から下に描画処理が実行されるので、
  //手前に描きたい物は、最後に記載する必要があります。
  //(描画優先度の指定も可能です)
}	

・座標系について
 ・基本的な画面解像度は横720x縦1280になっています(変更できます)。
  ・左上が(0,0)、右下が(719,1279)です
 ・x座標(横軸)、y座標(縦軸)の各パラメータを指定することで、
  画面内の任意の位置に描画することができます。

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

 ・int gc.GetPointerFrameCount(int);
  ・タッチされた瞬間からのフレーム数を返します
   押されていない時は0、押した瞬間は1が入ります。
   押し続けて居ると1フレーム毎に値が1増えます。
  ・引数はタッチしたポイントのIDです。
   0以外を入れると、複数箇所をタッチした場合に、
   2カ所目3カ所目等の各フレーム数を取得できます。
  
 ・gc.Random(int min,int max);//最小値と最大値の中で、何れかの数値を返します。
  ・例(サイコロを表現したい場合):gc.Random(1,6);

 ・gc.ClearScreen();//画面をクリアします。
 ・gc.SetColor(int,int,int);//描画色を指定します。(RGBの順で0~255を指定)
 ・gc.SetFontSize(int);//文字の大きさを指定します。
 ・gc.DrawString(string,int x,int y);
  ・座標(x,y)に文字列を描画するメソッドです。

課題

(1)簡単なガチャガチャの仕組みを作ってみましょう。
・タップすると10種のカードA~Jのうち何れかが手に入る(出現確率は均等)
・カードを引くごとにmoneyが100減る(初期値は10,000)
・全種類揃うと「Complete!!」と表示され停止する。
(2)(↑がうまくいったら)画面2秒長押しでリトライできるようにしてみましょう。
(3)(↑がうまくいったら)ABCDEの出現確率を1/3にしてみましょう。
(※A~Eを5%、F~Jを15%に) (4)(↑がうまくいったら)Competeの条件を変更して、ABCDE何れかが5枚揃ったら、にしてみましょう。
(5)(余力があったら)ゲームをより改良するか、学んだ技術を使って何か面白いものを作ってみましょう。

作ったC#のプログラムを添付してください。
(プロジェクトを保存したフォルダのasset以下にあると思います。
コメント欄には、どこまでやったかと(1)のハイスコアを書いてください。
(3),(4)もやった方は、それぞれのハイスコアも書きましょう。
(スコア=残ったマネー、とします)

課題の進め方

  1. GameCanvasをDLして解凍。
  2. フォルダ名をk02に改名
  3. ドキュメント/Unity(Windowsの場合)以下に配置
  4. Unityを起動
  5. 「Open」を押してk02を選択し「フォルダを選択」を押す
  6. (Unityのバージョンによりアラートが出るが、出た場合は「Continue」を押す)
  7. →Unityが起動され、プロジェクトk02が開かれる。
  8. Project窓でAssetsフォルダをダブルクリックして開き、中に入っているGame(.scene)をダブルクリックで開く。
  9. →シーンが開かれる(Hierarchy窓の表示が変わる)
  10. Project窓でAssetsフォルダをダブルクリックして開き、中に入っているGame(.cs)をダブルクリックで開く。
  11. →エディタが起動し、ソースを編集できるようになる
  12. プログラムを編集して保存
  13. Unityに戻って、再生ボタンを押して実行
  14. →プログラムに文法的な問題がなければ、プログラム通りに動くはず

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

  1. game.csを開いて、サンプル表示の部分を消して、プログラムの枠組みだけ残した状態にしましょう。(変数secの宣言、各メソッドの{}の中を消す)
  2. プログラムを編集

    9行目(クラスに入った直後)に変数の宣言を記載

    
    	    int money;
    	    const int CARD_TYPE = 10;
    	    int[] card_count = new int [CARD_TYPE];
    	    string[] card_name = 
    	    	    {"A","B","C","D","E","F","G","H","I","J"};
    	    bool isComplete;
    	    int new_card ;
    

    22行目(InitGame()の中)に初期化処理を記載

    
    	    gc.ChangeCanvasSize(720, 1280);
    	    gc.SetRandomSeed((uint)gc.CurrentTimestamp*1024);
    	    money = 10000;
    	    for (int i = 0; i < CARD_TYPE; i++) {
    	    	card_count[i] = 0;
    	    }
    	    isComplete = false;
    	    new_card = -1;
    

    35行目(UpdateGame()の中)に下記を記載

    
    if (gc.GetPointerFrameCount(0)==1 && ! isComplete) {
    	money -= 100;
    	new_card = gc.Random (0, 9);
    	card_count[new_card]++;
    
    	isComplete = true;
    	for (int i = 0; i < CARD_TYPE; i++) {
    		if (card_count [i] == 0) {
    			isComplete = false;
    		}
    	}
    }
    

    54行目(DrawGame()の中)に下記行を記載

    
    	gc.ClearScreen();
    	gc.SetColor(0,0,0);
    	gc.SetFontSize(36);
    	gc.DrawString("money:"+money,60, 40);
    
    	if(new_card >= 0){
    	  gc.DrawString("new:"+card_name[new_card],60, 80);
    	}
    
    	for(int i=0 ; i< CARD_TYPE ; i++){
              gc.DrawString(card_name[i] + ":" + card_count[i],60, 120+i*40);
    	}
    
    	if(isComplete ){
    	  gc.DrawString("complete!!",60, 520);
    	}
    
  3. セーブして実行してみましょう。

課題2のヒント

gc.GetPointerFrameCount(0)の値を見て、長く押している状態を判別します。
resetValueという名前のメソッドを作って、そこに初期化命令を集めて、
InitGame()と長押し時はresetValueを呼ぶようにすると、今度改造などしやすいです。
(全く同じ処理はできれば一カ所にまとめましょう)
  //UpdateGameの最後の方にif文を追加
  if(gc.GetPointerFrameCount(0) >= 120){
    resetValue()を呼ぶ;
  }

  //Drawの後、クラスを閉じる括弧の前にメソッドを追加
  void resetValue()
  {
     //InitGameに書いている初期化処理を書く
  }

  //メソッドを足したら、InitGame内はresetValue();のみに変更。

課題3のヒント

new_card = gc.Random (0, 9);
の部分を変更します。
        if(25%の確率(ランダムで0~3の結果が0だったら)){
          new_card = ランダムで0~4;
        }
        else {
          new_card = ランダムで5~9;
        }
など。

課題4のヒント

Completeの判定の部分を変更します。
既存の判定部分(isComplete = true;とその先の5行)をコメントアウトor削除して、
代わりに下記を書き加えます。
	isComplete = false;
	for (int i=0; i<5;i++) {
		if (card_count [i] が5以上だったら) {
			isComplete = true;
		}
        }
もしくは、AかBかCかDかEが5以上だったらtrue、という書き方でも。

補足

余力がある人の改良の案

・絵も無し動きも無しでできることを考えてみましょう。

Tips

ProjectViewでGame.csを選んで右クリック→ShowInExprolerで、エクスプローラが開きます(提出時に使ってください)

エディタについて

 標準でついてくるエディタMonoDevelopは日本語入力に不備が多々あります。
 入力せずに済ませるのが現実的ですが、どうしても日本語を入力したい場合は
 他のエディタで打ち込んでコピー&ペーストで持ってくるのが確実です。

 日本語対応するプログラムなども配布されているので、
 検索して試してみると良いかもしれません。
 容量は食いますがVisualStudioCommunityを導入するのもオススメです。

よくある質問

プログラムには間違いらしきものが見当たらないが、ビルドエラーが31個出てビルドできない。

MonoDevelop上でビルドエラーが31個出ている、という場合はこれに該当するものと思われます。

MonoDevelop上ではエラーが出ますが、プログラム自体に問題なければ、Unity上では動きます。

Unity上で再生ボタンを押してみてください。うまく動くかもしれません。

動かない場合はUnityのConsole窓に出ているエラー内容を確認してみましょう。

スクリプトを更新したのに、何も変わらない

プログラムが間違っていてビルドエラーが出ている可能性が高いです。

エディタ上でbuildしてみましょう。

{}の対応が間違っていないか、全角スペースが入っているかなど、確認してみましょう

クリックしても何も反応しない

windows10で、画面タップが有効になっている環境の方は、クリックではなく画面タップしてみましょう。反応があるのではないかと思います。

画面真っ白で何もでない

一部のバージョンのgameCanvasではデフォルトの文字色が白、背景色も白なので、何も見えません。

一部のgameCanvasではデフォルトの文字色が白、背景色も白です。

背景に画像を表示させる、文字色を変更するなどで解決可能です。