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

配布資料

キー入力を判定するメソッドについて

Input.GetKey (KeyCode.LeftArrow)
 押されているどうかを判定
Input.GetKeyDown (KeyCode.RightArrow)
 押した瞬間かどうかを判定
Input.GetKeyUp (KeyCode.RightArrow)
 離した瞬間かどうかを判定
※引数はエディタでKeyCodeまで入力すると選択肢が出て来ます。

マウス入力を判定するメソッドについて

Input.GetMouseButtonDown(0)
 マウスの左ボタンが押されているどうかを判定
Input.GetMouseButton(0)
 マウスの左ボタンが押された瞬間かを判定
Input.GetMouseButtonUp(0)
 マウスの左ボタンが離された瞬間かを判定
※引数は0だと左クリック、1だと右クリック、2だとホイ―ルクリックを検知します。

Input.mousePosition.x
Input.mousePosition.y
マウスのX座標、Y座標が入っています。(画面中央が0,0です)

オブジェクトにマウスが乗った時に呼び出されるオーバーライド関数も用意されています。
オブジェクトがクリックされたら特定の動作を行う、等の挙動を実装できます。
void OnMouseEnter ()
 オブジェクト内にマウスカーソルが入った時に呼ばれる
void OnMouseExit ()
 オブジェクトからマウスカーソルが出た時に呼ばれる
void OnMouseDown ()
 オブジェクト内でマウスをクリックされた時に呼ばれる

課題

(1)簡単な一人テニスゲームを作ってみましょう。
(2)(↑がうまくいったら)ジャンプゲームを作ってみましょう
(3)(↑がうまくいったら)ボールをクリックしたらジャンプするように変えてみましょう。
(4)(余力があったら)ゲームをより改良するか、学んだ技術を使って何か面白いものを作ってみましょう。

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

  1. 新規プロジェクトを作る(「2D」プロジェクトを選びましょう)
    プログラム
  2. Asset→Create→Folderを選んで、Asset内に新規フォルダを作成
  3. 名前が変えられるようになっているでresと名付けます。
  4. resをダブルクリックして開きます。
  5. DLしたサンプル画像ファイルを開いた場所(ProjectView内)にドラッグ&ドロップします。
  6. →画像がプロジェクトで使えるようになります。
  7. BGをクリックして、Scene窓にドラッグ&ドロップします。
  8. →BGがHierarchy窓に追加されます。(GameObject→2DOcject→Spriteを選択して新しいSpriteを作った後「BG」に改名し、Inspector窓のSpriteの欄にアセット窓から画像BGをドラッグ&ドロップする操作でも、同様の結果になります)
  9. 場所を調整しましょう(Positionをx=0,y=0に)
  10. 描画優先度を調整しましょう(Order in Layerを-1に。数値が大きいほど手前に描かれます。背景なので優先度を下げ、常に一番奥に表示されるようにします)
  11. Hierarchy窓のMainCameraをダブルクリックします。
  12. Inspector窓のCameraの5行目にあるSizeの値を2.4にします。(Scene窓で白い枠をドラッグする操作でもSizeは変更できます)
  13. →ゲーム画面内で背景が大きく表示されるようになります。
  14. Project窓のYellowBallをクリックしてScene窓にドラッグ&ドロップします
  15. →YellowBallもHerarchy窓に追加されます。
  16. 場所を中央の少し左上に調整しましょう(Positionをx=-1.2,y=0.8に)
  17. Project窓のBlockをクリックしてScene窓にドラッグ&ドロップします
  18. →BlockもHerarchy窓に追加されます。
  19. 場所を画面の下の方に調整しましょう(Positionをx=0,y=-2.2に)
  20. Scaleを変更して横長にしましょう。(Scaleをx=3に)
  21. Colorをクリックして、青くしましょう。(RGBを0,0,255に。数値を入力せずに画面から青っぽい部分を選ぶ操作でも構いません)
  22. →Blockが青くなります。(元の画像に色が付いている場合は、掛け合わせた色になります)
  23. Herarchy窓のBlockを右クリックしてrenameを選択して、名前をRacketに変えてあげましょう(Block選択中に再度クリックする操作でも名前変更できます)
  24. 今度は左右と上の壁を作ります。
  25. Project窓のBlockをクリックしてScene窓にドラッグ&ドロップします
  26. 3回繰り返すかHierarchy窓でコピペを駆使して、3種類作りましょう
  27. Positionをx=-3.3,y=0に、Scaleのy=16に、名前をWallLeftに
  28. Positionをx=3.3,y=0に、Scaleのy=16に、名前をWallRightに
  29. Positionをx=0,y=2.56に、Scaleのx=21.6に、名前をWallTopに
  30. 配置としては以上です。それぞれの属性などを設定します。
  31. YellowBallを選んでInspector窓のAddCoomponentをクリックし、Phisics2D→Rigibody2Dを追加します。(物理挙動の機能を追加)
  32. Inspector窓のGravity Scaleを0にします。(重力の影響をなくす)
  33. さらにAddComponentをクリックし、Phisics2D→CircleCollider2Dを追加します。(あたり判定を追加)
  34. Project窓がresを開いている状態なので、AssetをクリックしてAssetを開いている状態にします。(中にはresが入ってます)
  35. Assets→Create→Phisics2DMaterialを選ぶと、New Phisics2DMaterialが生成されます。
  36. Friction(摩擦係数)を0に、Bounciness(跳ね返り係数)を1にします。
  37. YellowBallのInspector窓で、CircleCollider2DのMaterialの欄に、作ったNew Phisics2DMaterialをドラッグアンドドロップします。
  38. Racketを選んでInspector窓のAddComponentをクリックし、Phisics2D→BoxCollider2Dを追加します。(あたり判定を追加)
  39. Materialの欄に、Project窓からNew Phisics2DMaterialをドラッグ&ドロップします。
  40. WallRightとWallLeftとWallTopにもBoxCollider2Dを追加して、Materialも設定します。
  41. Assets→Create→C# ScriptでScriptを作り、YellowBallと改名します。
  42. ダブルクリックしてエディタを起動し、8行目(Start()の中)に1行足します。
  43. transform.GetComponent<Rigidbody2D> ().AddForce (new Vector2 (100, -100));
    //<>は打ち込んでから半角に置き換えてください。
    
  44. 保存してUnityの画面に戻ります。
  45. Hierarchy窓でYellowBallを選んで、inspector窓に作ったスクリプトYellowBallをドラッグ&ドロップします。
  46. Assets→Create→C# ScriptでScriptを作り、Racketと改名します。
  47. ダブルクリックしてエディタを起動し、13行目(Update()の中)に12行足します。
  48. if (Input.GetKey (KeyCode.RightArrow)) {
      transform.Translate (transform.right *0.1f);
    }
    if (Input.GetKey (KeyCode.LeftArrow)) {
      transform.Translate (transform.right *-0.1f);
    }
    if (Input.GetKey (KeyCode.UpArrow)) {
      transform.Translate (transform.up*0.1f);
    }
    if (Input.GetKey (KeyCode.DownArrow)) {
      transform.Translate (transform.up *-0.1f);
    }
    
  49. 保存してUnityの画面に戻ります。
  50. Hierarchy窓でRacketを選んで、inspector窓に作ったスクリプトRacketをドラッグ&ドロップします。
  51. 実行してみましょう。
  1. 課題1がうまくいったら課題2に移りましょう。
  2. Blockの画像5回、画面内にドラッグ&ドロップしましょう。
  3. 座標を調整します。xyそれぞれ(-2.2 , -2.2)(-1.2 , -2.2)(1.2 , -2.2)(2.2 , -2.2)(0 , -0.2)
  4. AddComponentでPhisics2D→BoxCollider2Dを足しましょう。(足してからコピペして座標調整した方が早いかもしれません)
  5. Racketからスクリプトを外します。(歯車を選んでクリック→Remove Componentを選択)(操作できなくします)
  6. Project窓のNew Physics2D Materialのbounsiness(跳ね返り係数)を0にしてあげます
  7. YellowBallのInspector窓で、GravityScaleを1にして、FixedAngleにチェックを入れます。(FixedAngleが見当たらない時は、ConstraintsのFreeze Rotation Zにチェックを入れます)
  8. YellowBallのスクリプトに下記を追加します。
  9. 
    //3行目に↓を追加
    using UnityEngine.UI;
    
    //6行目(class入ってすぐ)に5行追加
    public Text t;
    int score=0;
    float time=30.0f;
    int jumpcount = 0;
    const int MAX_JUMP_COUNT = 2;
    
    //Start()に入れた1行(AddForceで初速を与える行)をコメントアウト
    
    //Update内に下記を足す。
    time -= Time.deltaTime;
    if (time >= 0.0f) {
      t.text = string.Format ("score:{0} time:{1:f1}", score, time);
    } else {
      t.text = string.Format ("score:{0} finished!", score);
    }
    
    if (Input.GetKey (KeyCode.RightArrow)) {
      transform.Translate (transform.right *0.05f);
    }
    if (Input.GetKey (KeyCode.LeftArrow)) {
      transform.Translate (transform.right *-0.05f);
    }
    
    if (Input.GetKeyDown (KeyCode.Space) && jumpcount < MAX_JUMP_COUNT) {
      transform.GetComponent<Rigidbody2D> ().velocity = new Vector3 (0, 5, 0);
      //<>は打ち込んでから半角に置き換えてください。
      jumpcount++;
    }
    
    //Updateが終わった後、classが終わる}の前に下記を足す。
    void OnCollisionEnter2D(Collision2D collision){
      if (collision.gameObject.name == "RedBall" ||collision.gameObject.name == "RedBall 1") {
        collision.gameObject.transform.position = new Vector3 ((Random.value - 0.5f) * 6.0f, Random.value * 2.0f, 0);
        if (time >= 0.0f) {
          score++;
        }
      }
      jumpcount = 0;
    }
    
  10. RedBallを2回ドラッグ&ドロップします。
  11. x,yは( -2.2 , 1.1 )と( 2.2 , 1.1 )にします
  12. AddComponentでCircle collider2dを足します
  13. GameObject→UI→Textでテキストを生成
  14. x,yは( 0,0 )にします。
  15. YellowBallのScriptの変数Tの欄にTextをドラッグ&ドロップします。
  16. 実行してみましょう
  17. 左右キーで移動、スペースキーでジャンプします。
  18. ジャンプ中に1回だけジャンプできます。
  19. (厳密には、玉がオブジェクトに接触してから2回ジャンプできます)
  20. (赤い玉を取った後など、再度ジャンプ可能です)
  21. 赤い玉を取ると1点入り、赤い玉がワープします。
  22. 30秒で取れる玉の数を競うゲームです。
  1. 問題なければ次の課題に
  2. YellowBallのスクリプトに下記を追加します。
  3. 
    //classの終わりの}の前に、下記3行を追加
    void OnMouseDown(){
      transform.GetComponent<Rigidbody2D> ().velocity = new Vector3(0,5,0);
    }
    //<>は打ち込んでから半角に置き換えてください。
    
  4. セーブして実行してみましょう。ボールをクリックすると弾が跳ねるようになります。

補足

余力がある人の改良の案

・各オブジェクトのInspectorのパラメータを変更してみる
・スクリプトの内容を変えてみる
・新しい画像を追加してみる
など、色々やってみてください。
SA高橋君が書いてくれたUnityコラムご参考まで。

Tips

ProjectViewでGameManagerを選んで右クリック→ShowInExprolerで、エクスプローラが開きます(提出時に使ってください)
SceneViewにてオブジェクトを選んでいる際、Alt+右クリックしながらタッチパッドを左右にスライドすることで、表示範囲を拡縮できます。(レイアウトを調整する際使ってください)

GameManagerを使う場合

今回の課題2では、YellowBallの中でスコア管理や文字表示をしていますが、
先週の課題のように空のGameObjectにGameManager.csをAddComponentして、
GameManager内でスコアやタイムの管理をした方が、プログラムとしては綺麗です。
下記のようにYellowBall.csからGameManagerのメソッドを呼び出すこともできます。


GameObject go = GameObject.Find ("GameObject");
if(go != null){
  GameManager gm = go.GetComponent(typeof(GameManager)) as GameManager;
  gm.AddScore();
}
// ※public void AddScore()をGameManager.csに用意する必要があります。

エディタについて

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

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

Unityのマニュアルについて

 以下に一式あります。
 http://docs.unity3d.com/ja/current/Manual/
 使いこなしたい人は色々見てみると良いと思います。

よくある質問

スクリプトを更新したのに、InspectorViewの変数が増えない

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

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

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

保存して再度開いたらブロックやボールが消えた

unityの仕様(不具合)かなと思います。

BG(背景画像)の描画優先度を下げることで解決します。

BGのInspectorViewでOrder in Layerを-1にしてください

(テキストの手順にも追記しておきました)