Skip to main content

夏休み・練習課題

義務ではないが、練習不足と思う学生にはおすすめ

目標

  • Unityでの開発と調査能力を向上する
  • 先生が教えていない課題もあるので、少し調べる必要な場合もある
  • 迷わず、判断力、開発スピードをUPする
  • 自分の今のゆるいところを明確し、固める

ポイント:

  • 順番気にせず、答えれるのを先に答えて、難しい質問は最後に残す
  • 最後に回答があるが、課題により、いくつかの解決方法がある。
  • 下記の解決は、あくまで先生のやり方である。

C# / スクリプト(言語、およびUnityのの基礎)

次の質問をC#で回答してください(1行〜5行程度)

例:2つの整数を足してください:

int sum = 20 + 15;

1. ゲーム実行中に「enemyPrefab」プレハブから具体的なゲームオブジェクト「enemy」を作成してください。

答え
GameObject enemy = Instantiate(enemyPrefab);

2. 「ball」というゲームオブジェクトからRigidbodyのコンポーネントを取得てください。

答え
Rigidbody rb = ball.GetComponent<Rigidbody>();

3. 取得したRigidbodyの速度は、X軸で毎秒5単位、Z軸で毎秒-1単位にしてください。また、Y軸の速度を変えないでください(元の通りに保持する)

答え
Vector3 velocity = rb.linearVelocity;
velocity.x = 5;
velocity.z = -1;
rb.linearVelocity = velocity;

4. 取得したRigidbodyをY軸周りに90度回転してください。

答え

Rigidbodyで動かす場合、Transformをいじるのではなく、Rigidbodyのメソッドを使わないといけない。Rigidbodyを回転させるには「MoveRotation」を使用する。

rb.MoveRotation(Quaternion.Euler(0, 90, 0));

5. スペースキーを押したら、「ball」ゲームオブジェクトを削除する処理を書いてください。

答え
if(Input.GetKeyDown(KeyCode.Space)
{
    Destroy(ball);
}

6.「box」というゲームオブジェクトの位置を「x=1, y=0.5, z=0」にしてください。

答え
box.transform.position = new Vector3(1, 0.5f, 0);

7. 「box」というゲームオブジェクトの位置を「x=5」にし、「y」と「z」は元の数値のままにしてください。

答え
Vector3 pos = box.transform.position;
pos.x = 5;
box.transform.position = pos;

8.「box」というゲームオブジェクトの位置を現在の位置よりも、左の方に1単位に動かしてください。

答え

少なくても、2つのやり方がある

Vector3 pos = box.transform.position;
pos.x -= 1;
box.transform.position = pos;

 または 

box.transform.Translate(-1, 0, 0);

9. Unityで「1〜100」の間に乱数10個を生成してください。

答え
for (int i = 0; i < 10; i++)
{
  // 整数の場合は最大値を除く(1~100)
  int rnd_i = Random.Range(1, 101); 

  // 小数型の場合は、最大値を含む
  float rnd_f = Random.Range(1.0f, 100.0f);
}  

10. 「cat」と「mouse」の2つのゲームオブジェクトの間の距離を求めてください。

答え
Vector3 catPos = cat.transform.position;
Vector3 mousePos = mouse.transform.position;
Vector3 direction = mousePos - catPos

float distance = direction.magnitude;

11. 「cat」と「mouse」の距離が「1.5」単位よりも小さければ、「mouse」は「cat」から「3」単位を離れる。

答え
if (distance < 1.5f)
{
    mousePos = catPos + direction.normalized * 3.0f;
    mouse.transform.position = mousePos;
}

12. 4種類のTシャツのサイズ(Small、 Medium、 Large、 ExtraLarge)を表す列挙型「ShirtSize」を宣言してください。

答え
enum ShirtSize
{
    Small,
    Medium,
    Large,
    ExtraLarge
}

13. ShirtSizeの列挙から「myShirt」の変数を宣言し、ラージサイズにする

答え
ShirtSize myShirt = ShirtSize.Large;

14. Debug.Logを使い、Tシャツのサイズにより、日本語でサイズを表示してください:
      Small:“小”、Medium:”並”、Large:”大”、ExtraLarge:”特大”

答え
switch (myShirt)
{
    case ShirtSize.Small:
        Debug.Log("小");
        break;
    case ShirtSize.Medium:
        Debug.Log("中");
        break;
    case ShirtSize.Large:
        Debug.Log("大");
        break;
    case ShirtSize.ExtraLarge:
        Debug.Log("特大");
        break;
}

15. 入力クラス(Input)を使い、上の矢印キー(↑)を放せば、Debug.Logで”JUMP!”というメッセージを表示してください。

答え
if (Input.GetKeyUp(KeyCode.UpArrow))
{
    Debug.Log("JUMP!");
}

16. 入力クラス(Input)を使い、InputManager で定義した ”Attack” アクションが行った場合、Debug.Logで”攻撃”を表示してください。

答え
if (Input.GetButtonDown("Attack"))
{
    Debug.Log("攻撃");
}

シーン、ゲームオブジェクト、コンポーネント

 次の質問を文章で回答してください:

17. ゲームオブジェクトとコンポーネントの違いを説明してください。

答え

ゲームオブジェクト:シーン(Hierarchy)の中にある1つのもの(例:プレーヤー、敵対、木、壁、スコアの表示など)

コンポーネント:ゲームオブジェクトにアタッチするものであり、ゲームオブジェクトの機能を増やす(例:物理演算:Rigidbody、当たり判定:Collider、サウンド再生:AudioSource、カスタム機能:スクリプト)

18. Rigidbodyというコンポーネントはいつ使う?

答え あるゲームオブジェクトを物理的に移動させたいとき(重力、速度、加速度などで移動させる)

19. Colliderというコンポーネントはいつ使う?

答え

 当たり判定の処理のために使う。衝突モードとトリガーモード2種類がある

20. コライダーをトリガーモード(isTrigger)をチェックするとなにが変わる?

答え

 ゲームオブジェクトを衝突せず、コライダーをすり抜けるが、その範囲の中に他のゲームオブジェクトが入っているかどうか「IsTriggerXXX」で確認できる。

21. RigidbodyがないColliderを使える?なぜ?

答え

 使える。当たり判定(衝突)のみが発生し、動かないので、壁、床面などに最適

22. RigidbodyのlinearVelocityはなんですか?

答え リジッドボディの移動速度である。

23. RigidbodyのAddForceで何ができる?linearVelocityと何が違う?

答え

力与えて移動させる(ゲームオブジェクトを押したら、引っ張ったりする)。linearVelocityと異なって、Rigidbodyの重さ(質量)の影響が発生する。つまり、AddForceを使う場合、Rigidbodyが重ければ重いほど、動き辛くなるが、linearVelocityを変えると直接に速度が変わるので、重さが関係ない。

24.「プレハブ」とは何ですか?はいつ使う?

答え

スクリプトやコンポーネントをアタッチし、独立に使えるゲームオブジェクトのかたまりである。プレハブは「図形」として使えることができ、実行中、またはUnityエディタで何度重複ができる。

25. 「Animation Clip」「Animator」と「Animation Controller」の連携を説明してください。

答え
    Animation Clipは1つのアニメーションである(例:ジャンプ、走る、歩く、攻撃する) Animation Controllerは遷移を管理する(遷移グラフ)。条件(パラメータ)により、Animation Clip の切り替えができる。 Animatorはゲームオブジェクトにアタッチするコンポーネントで、Animation Controller を設定できる。

    26. UIを作るために、最も重要なコンポーネントを記述してください。

    答え Canvas。キャンバスの中に、ボタン、テキスト、画像などを配置する。

    27. あるRigidbodyの重力が効かないでほしいとき、どうすれば良いでしょうか?

    答え

    Unity の Inspector で「Use Gravity」のチェックを外す

    28. ベタベタの壁を作りたくて、何か衝突したら、弾みなく、衝突したオブジェクトを壁に張り付くような現象を作りたい。どうすれば良いでしょうか?

    答え

    2つの解決策が考えられる。

      スクリプトで衝突したときに、Rigidbodyが効かなくなる(isKinematic = true) PhysicsMaterialで「Bounciness」(弾み)を「0」にする、「Friction」(魔雑)「1」にする

      最終的な効果が多少異なるが、べたべたの壁をエフェクトを作成できる。

      29. SpriteRendererとは何でしょうか?

      答え 2Dの画像を表示する(2Dゲーム専用のコンポーネント)

      30. InspectorでスプライトをY軸で逆さまにしたいなら、どうすれば良い?

      答え

      Inspectorで「Sprite Renderer」の「Flip Y」をチェックする

      Transform の Scale Y を -1 にする手もあるが、コライダーに悪影響がある。

      31. スプライトのモード「Single」と「Multiple」の違いは何でしょうか?

      答え Singleは「単体」という意味で、画像の中にスクリプトが1つしかない。Multipleは「複数」という意味であり、同じ画像に中ではたくさんのスプライトが入っている。この場合は、Sprite Editorで切り分けないといけない。

      32. シーンを切り替えるために、LoadSceneを呼び出す前に、どこに追加すれば良いでしょうか?

      答え

      File > Build Profiles(ファイル > ビルドプロフィール)画面で、「Scene List」の中に切り替えたいシーンを追加しないといけない。

      33. 「タグ」は何に使える?

      答え

      ゲームオブジェクトの特定に使う。「xxxx.CompareTag("タグ")」を使うと、同じタグかどうかを確認できる。

      34. TextMeshProというコンポーネントをなんのために使うのでしょうか?

      答え

      UIでテキストを表示するためのコンポーネントである。

      35. UI の「Anchor」(アンカー)の使い方について説明してください。

      答え

       UIの要素(画像、テキスト、ボタンなど)を画面の角や中央から相対的に配置するためのものである。いろんな画面サイズを対応するため、UIの要素を絶対的ではなく、アンカーを使って、相対的に配置するべき。

      36.「Ray」(レイ)というものはなんでしょうか?使い方を説明してください。

      答え

      Rayは「ビーム」のようなもので、スクリプトで当たり判定を確認できるためにつかう。Rayは「原点」(origin)と「向き」(direction)をもち、Physics.Raycastで何か当たるかどうかを確認できる。

      使い道がいっぱいある。例えば、シューティングゲームで、弾が当たったかどうかを確認できるし、画面をクリックすると、3D空間で何を選択したのかを確認できる。

      C# / スクリプト

      次の質問を文章で回答してください:

      37. 「FixedUpdate」「Update」「LateUpdate」の違いを説明してください。それぞれいつ使うと思う?

      答え
        Update:ゲームのフレーム毎に実行する。普通の処理を行うところ。 FixedUpdate:一定間隔の時間で実行する。物理にかかわる処理(Rigidbodyなど)にはおすすめ。 LateUpdate:Updateの後に実行する。少し遅れて実行させたい処理はここに書くべき。

        38. ゲームオブジェクトの「Destroy」と「SetActive(false)」の違いを説明してください。

        答え
          Destroyはゲームオブジェクトを完全に削除する。ゲームから抜けて、2度も使えなくなる。 SetActive(false)は一時的に無効にする。ゲームに残り、もう一度使いたいときには SetActive(true)で有効ができる。

          39. 「Time.deltaTime」とは何でしょうか?

          答え

          前フレームから過ごした時間である。タイマーや速度に依存する移動量などに使う数値。

          40. 「Time.timeScale = 0」にすれば、ゲームはどうなる?

          答え

          時間に依存する処理が止まる。単純なポーズ(Pause)に使える。

          41. 「public」と「private」の違いについて説明してください。

          答え

           「public」と「private」はアクセス修飾子である。「public」のメソッドや変数が他のクラス(スクリプト)からアクセス(読み込みこと、書き込むこと)ができる。一方「private」のメソッドと変数は、宣言されたクラスのみでアクセスができ、他のクラスからアクセスができない。

          42. 「OnCollisionEnter」と「OnTriggerEnter」の違いを説明してください。

          答え
            OnCollisionEnterは衝突が始まるときに呼び出される。(衝突モードのコライダー) OnTriggerEnterは「Is Trigger」のチェックしたコライダーの中に何か入ったときに呼び出される。(トリガーモードのコライダー)

            43. 「OnTriggerEnter」「OnTriggerStay」「OnTriggerExit」の違いを説明してください。

            答え

            すべてのメソッドはトリガーモードになっているコライダーの時に発生する

              OnTriggerEnter:トリガーは他のコライダーの中に入った瞬間 OnTriggerStay:トリガーは他のコライダーの中にあるとき OnTriggerExit:トリガーは他のコライダーの中から出た瞬間

              44. 「OnCollisionEnter」の引数(Collision)は何に使えるでしょうか?

              答え

               OnCollisionXXXXの「Collision」には衝突に関する情報が入っている。

              たとえば、衝突してきたオブザーバーは「Collision.gameObject」であり、衝突した3D位置は「Collision.point」である。

              詳細:https://docs.unity3d.com/6000.4/Documentation/ScriptReference/Collision.html

              45. 「SerializeField」どこで使う?なんのため?

              答え 非公開(private)のメンバー変数を Unity の Inspector で変えられるようにする。

              46. 「event」というキーワードは何に使うのでしょうか?

              答え

              C#のイベントを宣言するときに使う。イベントを作るには、「発生する側」と「受け取る側」の2つが必要。

              発生する側:

                宣言:public event System.Action<引数1,引数2…> イベント名 発生:イベント名?.Invoke(数値1, 数値2…);

                受け取る側:

                  登録:オブジェクト.イベント名 += 受け取るメソッド名 受け取る:void 受け取るメソッド名(引数1, 引数2, …)

                  スクリプト作成

                  47. 「Countdown」というスクリプトをを作成し、ゲームが起動してから3秒後にConsoleで「時間切れ」を表示してください(1回だけ)

                  答え
                  using UnityEngine;
                  
                  public class Countdown : MonoBehaviour
                  {
                      // 残りの時間
                      private float timer = 3.0f;
                      
                      // 時間が切れたか?
                      private bool isTimeout = false;
                      
                      private void Update()
                      {
                          // 時間が切れたか? → 何もしない
                          if (isTimeout)
                              return;
                          
                          // 時間を減らす
                          timer -= Time.deltaTime;
                          
                          // まだ時間ある? → 何もしない
                          if (timer > 0)
                              return;
                              
                          // 時間切れにする
                          isTimeout = true;
                  
                          // コンソールで表示
                          Debug.Log("時間切れ");
                      }
                  }

                  48. 「Countdown」を編集し、「Timeout」というイベントを追加してください。時間が切れたら、イベントを発生してください。

                  答え
                  using UnityEngine;
                  
                  public class Countdown : MonoBehaviour
                  {
                      // タイムアウトイベントの宣言
                      public event System.Action Timeout
                  
                      // 残りの時間
                      private float timer = 3.0f;
                      
                      // 時間が切れたか?
                      private bool isTimeout = false;
                      
                      private void Update()
                      {
                          // 時間が切れたか? → 何もしない
                          if (isTimeout)
                              return;
                          
                          // 時間を減らす
                          timer -= Time.deltaTime;
                          
                          // まだ時間ある? → 何もしない
                          if (timer > 0)
                              return;
                              
                          // 時間切れにする
                          isTimeout = true;
                          
                          // コンソールで表示
                          Debug.Log("時間切れ");
                  
                          // イベント発生
                          Timeout?.Invoke();
                      }
                  }

                  49.「CountdownWait」の新しいスクリプトを作成し、Unity上でCountdownとの紐づけできるようにしてください。そして、CountdownのTimeoutイベントを登録し、イベントを受け取ったら、「イベントを受け取った」を表示してください。

                  答え
                  using UnityEngine;
                  
                  public class CountdownWait : MonoBehaviour
                  {
                      // Unityで紐づけ
                      [SerializeField]
                      private Countdown countdown;
                  
                      private void Start()
                      {
                          countdown.Timeout += OnTimeout;
                      }
                  
                      private void OnTimeout()
                      {
                          Debug.Log("イベントを受け取った");
                      }
                  }

                  スクリプト解析

                  スクリプト A

                  以下のスクリプトを解析し、下にある質問を回答してください

                  public class ObjectPusher : MonoBehaviour
                  {
                      public float speed = 10;
                  
                      void OnCollisionEnter(Collision other)
                      {
                         var rbody = GetComponent<Rigidbody>();
                         var direction = other.transform.position - transform.position;
                         rbody.linearVelocity = direction.normalized * speed;
                      }
                  }

                  自分(スクリプトを持っているゲームオブジェクト)と相手(衝突してきたゲームオブジェクト)が衝突した場合は9行目で「linearVelocity」を変えているが…

                  50. どちらのlinearVelocityが変わるでしょうか?(自分 or 相手)

                  答え 「自分」 - 取得したRigidbodyは、本スクリプトと同じゲームオブジェクトにあるので(7行目)

                  51. どの方向にlinearVelocityが変わる?(自分の方 or 相手の方)

                  答え

                  「相手」 - directionベクトルは相手の方に向いている(方位 = 相手 - 自分)

                  52. 全体的に、このスクリプトは何をするのかを説明してください。

                  答え

                  2つのゲームオブジェクトを衝突したら、自分が相手に向かって速度を設定する。

                  スクリプト B

                  以下のスクリプトを解析し、下にある質問を回答してください

                  public class InstanceMaker : MonoBehaviour
                  {
                      [SerializeField]
                      private GameObject original;
                  
                      private GameObject [] copies = new GameObject[10];
                      private int lastCopy = 0;
                  
                      void Update()
                      {
                          if (Input.GetKeyUp(KeyCode.Space))
                          {
                              if (lastCopy < 10)
                              {
                                  copies[lastCopy] = Instantiate(original);
                                  lastCopy++;
                              }
                              else
                              {
                                  for(int i = 0; i < 10; i++)
                                  {
                                      Destroy(copies[i]);
                                  }
                                  lastCopy = 0;
                              }
                          }
                      }
                  }

                  53. このスクリプトを実行し、スペースキーを押したらどうなるのか説明してください。

                  答え

                  あるプレハブからオブジェクトをコピーし、シーンに追加する。ただし、11個目を作成しょうとしたら、作成したゲームオブジェクトをすべて削除する。

                  スクリプト C

                  以下のスクリプトを解析し、下にある質問を回答してください

                  public class Player : MonoBehaviour
                  {
                      private int HP = 100;   // ヒットポイント
                      [SerializeField]
                      private int MP = 100;   // マジックポイント
                  
                      void Start()
                      {
                         HP = 50;
                      }
                  
                      void OnTriggerEnter2D(Collider2D other)
                      {
                          if (other.CompareTag("fire"))
                          {
                              HP -= 5;
                          }
                      }
                  
                      void Update()
                      {
                          if (Input.GetKey(KeyCode.Q))
                          {
                              HP += 10 * Time.deltaTime;
                              MP -=  5 * Time.deltaTime;
                          }
                      }
                  }

                  54. ゲームが開始のとき、プレーヤーはHPとMPはそれぞれ何ポイントでしょうか?

                  答え

                  MPは100点、HPは50点

                  55. 11行目〜17行目でどんなことが行われていると思う?

                  答え  トリガーに入ったとき、入ってきたゲームオブジェクトのタグは「fire」だったら、HPが5点減る

                  56. HPの回復処理を説明してください。

                  答え

                  「Q」キーをおっしぱなしで、1秒当たりにMPの5点を消費し、HPの10点を回復する

                  57. "Q”キーを5秒押すと、MPはどうなる?

                  答え

                  MPは25点が減る

                  58. Inspectorで編集できる変数を指定してください。

                  答え

                  MPはInspectorで編集ができる

                  59. HPとMPは「ゼロ」以下にならないように、スクリプトの適切なところに編集してください。

                  答え
                  void OnTriggerEnter2D(Collider2D other)
                  {
                      if (other.CompareTag("fire"))
                      {
                          HP -= 5;
                          
                          // 0以下にならないように
                          HP = Mathf.Max(HP, 0); 
                      }
                  }
                  
                  void Update()
                  {
                      if (Input.GetKey(KeyCode.Q))
                      {
                          HP += 10 * Time.deltaTime;
                          MP -=  5 * Time.deltaTime;
                          
                          // 0以下にならないように
                          MP = Mathf.Max(MP, 0); 
                      }
                  }

                  60. “Q”を固定せず、Inspectorでキーを設定できるようにしてください。

                  答え

                  まず、スクリプトの頭に:

                  // 回復のキーをUnityで設定
                  [SerializeField]
                  private KeyCode restoreKey;

                  そして、Updateでif文の条件を変える:

                  if (Input.GetKey(restoreKey))

                  61. HPが「ゼロ」になったら、ゲームオブジェクトを削除してください。

                  答え
                  void OnTriggerEnter2D(Collider2D other)
                  {
                      if (other.CompareTag("fire"))
                      {
                          HP -= 5;
                          if (HP <= 0)
                              Destroy(gameObject);
                      }
                  }