# 夏休み・練習課題

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

目標

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

ポイント：

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

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

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

例：２つの整数を足してください：

```c#
int sum = 20 + 15;
```

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

<details id="bkmrk-%E7%AD%94%E3%81%88-gameobject-enemy-"><summary>答え</summary>

```c#
GameObject enemy = Instantiate(enemyPrefab);
```

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

<details id="bkmrk-%E7%AD%94%E3%81%88-rigidbody-rb-%3D-ba"><summary>答え</summary>

```c#
Rigidbody rb = ball.GetComponent<Rigidbody>();
```

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

<details id="bkmrk-%E7%AD%94%E3%81%88-vector3-velocity-"><summary>答え</summary>

```c#
Vector3 velocity = rb.linearVelocity;
velocity.x = 5;
velocity.z = -1;
rb.linearVelocity = velocity;
```

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

<details id="bkmrk-%E7%AD%94%E3%81%88-rigidbody%E3%81%A7%E5%8B%95%E3%81%8B%E3%81%99%E5%A0%B4%E5%90%88%E3%80%81t"><summary>答え</summary>

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

```c#
rb.MoveRotation(Quaternion.Euler(0, 90, 0));
```

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

<details id="bkmrk-%E7%AD%94%E3%81%88-if%28input.getkeydo"><summary>答え</summary>

```c#
if(Input.GetKeyDown(KeyCode.Space)
{
    Destroy(ball);
}
```

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

<details id="bkmrk-%E7%AD%94%E3%81%88-box.transform.pos"><summary>答え</summary>

```c#
box.transform.position = new Vector3(1, 0.5f, 0);
```

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

<details id="bkmrk-%E7%AD%94%E3%81%88-vector3-pos-%3D-box"><summary>答え</summary>

```c#
Vector3 pos = box.transform.position;
pos.x = 5;
box.transform.position = pos;
```

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

<details id="bkmrk-%E7%AD%94%E3%81%88-%E5%B0%91%E3%81%AA%E3%81%8F%E3%81%A6%E3%82%82%E3%80%81%EF%BC%92%E3%81%A4%E3%81%AE%E3%82%84%E3%82%8A%E6%96%B9%E3%81%8C%E3%81%82%E3%82%8B-v"><summary>答え</summary>

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

```c#
Vector3 pos = box.transform.position;
pos.x -= 1;
box.transform.position = pos;
```

 または

```c#
box.transform.Translate(-1, 0, 0);
```

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

<details id="bkmrk-%E7%AD%94%E3%81%88-for-%28int-i-%3D-0%3B-i"><summary>答え</summary>

```c#
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);
}  
```

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

<details id="bkmrk-%E7%AD%94%E3%81%88-vector3-catpos-%3D-"><summary>答え</summary>

```c#
Vector3 catPos = cat.transform.position;
Vector3 mousePos = mouse.transform.position;
Vector3 direction = mousePos - catPos

float distance = direction.magnitude;
```

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

<details id="bkmrk-%E7%AD%94%E3%81%88-if-%28distance-%3C-1."><summary>答え</summary>

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

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

<details id="bkmrk-%E7%AD%94%E3%81%88-enum-shirtsize-%7B-"><summary>答え</summary>

```c#
enum ShirtSize
{
    Small,
    Medium,
    Large,
    ExtraLarge
}
```

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

<details id="bkmrk-%E7%AD%94%E3%81%88-shirtsize-myshirt"><summary>答え</summary>

```c#
ShirtSize myShirt = ShirtSize.Large;
```

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

<details id="bkmrk-%E7%AD%94%E3%81%88-switch-%28myshirt%29-"><summary>答え</summary>

```c#
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;
}
```

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

<details id="bkmrk-%E7%AD%94%E3%81%88-if-%28input.getkeyu"><summary>答え</summary>

```c#
if (Input.GetKeyUp(KeyCode.UpArrow))
{
    Debug.Log("JUMP!");
}
```

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

<details id="bkmrk-%E7%AD%94%E3%81%88-if-%28input.getbutt"><summary>答え</summary>

```c#
if (Input.GetButtonDown("Attack"))
{
    Debug.Log("攻撃");
}
```

</details>### シーン、ゲームオブジェクト、コンポーネント

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

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

<details id="bkmrk-%E7%AD%94%E3%81%88-%E3%82%B2%E3%83%BC%E3%83%A0%E3%82%AA%E3%83%96%E3%82%B8%E3%82%A7%E3%82%AF%E3%83%88%EF%BC%9A%E3%82%B7%E3%83%BC%E3%83%B3%EF%BC%88hie"><summary>答え</summary>

<span style="text-decoration: underline;">ゲームオブジェクト</span>：シーン（Hierarchy）の中にある１つのもの（例：プレーヤー、敵対、木、壁、スコアの表示など）

<span style="text-decoration: underline;">コンポーネント</span>：ゲームオブジェクトにアタッチするものであり、ゲームオブジェクトの機能を増やす（例：物理演算：Rigidbody、当たり判定：Collider、サウンド再生：AudioSource、カスタム機能：スクリプト）

</details>18\. Rigidbodyというコンポーネントはいつ使う？

<details id="bkmrk-%E7%AD%94%E3%81%88-%E3%81%82%E3%82%8B%E3%82%B2%E3%83%BC%E3%83%A0%E3%82%AA%E3%83%96%E3%82%B8%E3%82%A7%E3%82%AF%E3%83%88%E3%82%92%E7%89%A9%E7%90%86%E7%9A%84%E3%81%AB%E7%A7%BB"><summary>答え</summary>

あるゲームオブジェクトを物理的に移動させたいとき（重力、速度、加速度などで移動させる）</details>19\. Colliderというコンポーネントはいつ使う？

<details id="bkmrk-%E7%AD%94%E3%81%88-%C2%A0%E5%BD%93%E3%81%9F%E3%82%8A%E5%88%A4%E5%AE%9A%E3%81%AE%E5%87%A6%E7%90%86%E3%81%AE%E3%81%9F%E3%82%81%E3%81%AB%E4%BD%BF%E3%81%86%E3%80%82%E8%A1%9D"><summary>答え</summary>

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

</details>20\. コライダーをトリガーモード（isTrigger）をチェックするとなにが変わる？

<details id="bkmrk-%E7%AD%94%E3%81%88-%C2%A0%E3%82%B2%E3%83%BC%E3%83%A0%E3%82%AA%E3%83%96%E3%82%B8%E3%82%A7%E3%82%AF%E3%83%88%E3%82%92%E8%A1%9D%E7%AA%81%E3%81%9B%E3%81%9A%E3%80%81%E3%82%B3"><summary>答え</summary>

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

</details>21\. RigidbodyがないColliderを使える？なぜ？

<details id="bkmrk-%E7%AD%94%E3%81%88-%C2%A0%E4%BD%BF%E3%81%88%E3%82%8B%E3%80%82%E5%BD%93%E3%81%9F%E3%82%8A%E5%88%A4%E5%AE%9A%EF%BC%88%E8%A1%9D%E7%AA%81%EF%BC%89%E3%81%AE%E3%81%BF%E3%81%8C"><summary>答え</summary>

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

</details>22\. Rigidbodyの`linearVelocity`はなんですか？

<details id="bkmrk-%E7%AD%94%E3%81%88-%E3%83%AA%E3%82%B8%E3%83%83%E3%83%89%E3%83%9C%E3%83%87%E3%82%A3%E3%81%AE%E7%A7%BB%E5%8B%95%E9%80%9F%E5%BA%A6%E3%81%A7%E3%81%82%E3%82%8B%E3%80%82"><summary>答え</summary>

リジッドボディの移動速度である。</details>23\. Rigidbodyの`AddForce`で何ができる？`linearVelocity`と何が違う？

<details id="bkmrk-%E7%AD%94%E3%81%88-%E5%8A%9B%E4%B8%8E%E3%81%88%E3%81%A6%E7%A7%BB%E5%8B%95%E3%81%95%E3%81%9B%E3%82%8B%EF%BC%88%E3%82%B2%E3%83%BC%E3%83%A0%E3%82%AA%E3%83%96%E3%82%B8%E3%82%A7"><summary>答え</summary>

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

</details>24.「プレハブ」とは何ですか？はいつ使う？

<details id="bkmrk-%E7%AD%94%E3%81%88-%E3%82%B9%E3%82%AF%E3%83%AA%E3%83%97%E3%83%88%E3%82%84%E3%82%B3%E3%83%B3%E3%83%9D%E3%83%BC%E3%83%8D%E3%83%B3%E3%83%88%E3%82%92%E3%82%A2%E3%82%BF%E3%83%83"><summary>答え</summary>

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

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

<details id="bkmrk-%E7%AD%94%E3%81%88-animation-clip%E3%81%AF%EF%BC%91%E3%81%A4"><summary>答え</summary>

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

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

<details id="bkmrk-%E7%AD%94%E3%81%88-canvas%E3%80%82%E3%82%AD%E3%83%A3%E3%83%B3%E3%83%90%E3%82%B9%E3%81%AE%E4%B8%AD%E3%81%AB%E3%80%81%E3%83%9C"><summary>答え</summary>

Canvas。キャンバスの中に、ボタン、テキスト、画像などを配置する。</details>27\. あるRigidbodyの重力が効かないでほしいとき、どうすれば良いでしょうか？

<details id="bkmrk-%E7%AD%94%E3%81%88-unity-%E3%81%AE-inspector"><summary>答え</summary>

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

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

<details id="bkmrk-%E7%AD%94%E3%81%88-%EF%BC%92%E3%81%A4%E3%81%AE%E8%A7%A3%E6%B1%BA%E7%AD%96%E3%81%8C%E8%80%83%E3%81%88%E3%82%89%E3%82%8C%E3%82%8B%E3%80%82-%E3%82%B9%E3%82%AF%E3%83%AA"><summary>答え</summary>

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

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

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

</details>29\. SpriteRendererとは何でしょうか？

<details id="bkmrk-%E7%AD%94%E3%81%88-2d%E3%81%AE%E7%94%BB%E5%83%8F%E3%82%92%E8%A1%A8%E7%A4%BA%E3%81%99%E3%82%8B%EF%BC%882d%E3%82%B2%E3%83%BC%E3%83%A0%E5%B0%82"><summary>答え</summary>

2Dの画像を表示する（2Dゲーム専用のコンポーネント）</details>30\. InspectorでスプライトをY軸で逆さまにしたいなら、どうすれば良い？

<details id="bkmrk-%E7%AD%94%E3%81%88-inspector%E3%81%A7%E3%80%8Csprite"><summary>答え</summary>

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

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

</details>31\. スプライトのモード「Single」と「Multiple」の違いは何でしょうか？

<details id="bkmrk-%E7%AD%94%E3%81%88-single%E3%81%AF%E3%80%8C%E5%8D%98%E4%BD%93%E3%80%8D%E3%81%A8%E3%81%84%E3%81%86%E6%84%8F%E5%91%B3%E3%81%A7"><summary>答え</summary>

Singleは「単体」という意味で、画像の中にスクリプトが１つしかない。Multipleは「複数」という意味であり、同じ画像に中ではたくさんのスプライトが入っている。この場合は、Sprite Editorで切り分けないといけない。</details>32\. シーンを切り替えるために、`LoadScene`を呼び出す前に、どこに追加すれば良いでしょうか？

<details id="bkmrk-%E7%AD%94%E3%81%88-file-%3E-build-prof"><summary>答え</summary>

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

</details>33\. 「タグ」は何に使える？

<details id="bkmrk-%E7%AD%94%E3%81%88-%E3%82%B2%E3%83%BC%E3%83%A0%E3%82%AA%E3%83%96%E3%82%B8%E3%82%A7%E3%82%AF%E3%83%88%E3%81%AE%E7%89%B9%E5%AE%9A%E3%81%AB%E4%BD%BF%E3%81%86%E3%80%82%E3%80%8C"><summary>答え</summary>

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

</details>34\. TextMeshProというコンポーネントをなんのために使うのでしょうか？

<details id="bkmrk-%E7%AD%94%E3%81%88-ui%E3%81%A7%E3%83%86%E3%82%AD%E3%82%B9%E3%83%88%E3%82%92%E8%A1%A8%E7%A4%BA%E3%81%99%E3%82%8B%E3%81%9F%E3%82%81%E3%81%AE%E3%82%B3%E3%83%B3"><summary>答え</summary>

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

</details>35\. UI の「Anchor」（アンカー）の使い方について説明してください。

<details id="bkmrk-%E7%AD%94%E3%81%88-%C2%A0ui%E3%81%AE%E8%A6%81%E7%B4%A0%EF%BC%88%E7%94%BB%E5%83%8F%E3%80%81%E3%83%86%E3%82%AD%E3%82%B9%E3%83%88%E3%80%81%E3%83%9C%E3%82%BF"><summary>答え</summary>

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

</details>36.「Ray」（レイ）というものはなんでしょうか？使い方を説明してください。

<details id="bkmrk-%E7%AD%94%E3%81%88-ray%E3%81%AF%E3%80%8C%E3%83%93%E3%83%BC%E3%83%A0%E3%80%8D%E3%81%AE%E3%82%88%E3%81%86%E3%81%AA%E3%82%82%E3%81%AE%E3%81%A7%E3%80%81"><summary>答え</summary>

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

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

</details>### C# / スクリプト

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

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

<details id="bkmrk-%E7%AD%94%E3%81%88-update%EF%BC%9A%E3%82%B2%E3%83%BC%E3%83%A0%E3%81%AE%E3%83%95%E3%83%AC%E3%83%BC%E3%83%A0%E6%AF%8E%E3%81%AB"><summary>答え</summary>

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

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

<details id="bkmrk-%E7%AD%94%E3%81%88-destroy%E3%81%AF%E3%82%B2%E3%83%BC%E3%83%A0%E3%82%AA%E3%83%96%E3%82%B8%E3%82%A7%E3%82%AF%E3%83%88"><summary>答え</summary>

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

</details>39\. 「`Time.deltaTime`」とは何でしょうか？

<details id="bkmrk-%E7%AD%94%E3%81%88-%E5%89%8D%E3%83%95%E3%83%AC%E3%83%BC%E3%83%A0%E3%81%8B%E3%82%89%E9%81%8E%E3%81%94%E3%81%97%E3%81%9F%E6%99%82%E9%96%93%E3%81%A7%E3%81%82%E3%82%8B%E3%80%82"><summary>答え</summary>

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

</details>40\. 「`Time.timeScale = 0`」にすれば、ゲームはどうなる？

<details id="bkmrk-%E7%AD%94%E3%81%88-%E6%99%82%E9%96%93%E3%81%AB%E4%BE%9D%E5%AD%98%E3%81%99%E3%82%8B%E5%87%A6%E7%90%86%E3%81%8C%E6%AD%A2%E3%81%BE%E3%82%8B%E3%80%82%E5%8D%98%E7%B4%94%E3%81%AA"><summary>答え</summary>

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

</details>41\. 「`public`」と「`private`」の違いについて説明してください。

<details id="bkmrk-%E7%AD%94%E3%81%88-%C2%A0%E3%80%8Cpublic%E3%80%8D%E3%81%A8%E3%80%8Cprivat"><summary>答え</summary>

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

</details>42\. 「`OnCollisionEnter`」と「`OnTriggerEnter`」の違いを説明してください。

<details id="bkmrk-%E7%AD%94%E3%81%88-oncollisionenter%E3%81%AF"><summary>答え</summary>

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

</details>43\. 「`OnTriggerEnter`」「`OnTriggerStay`」「`OnTriggerExit`」の違いを説明してください。

<details id="bkmrk-%E7%AD%94%E3%81%88-%E3%81%99%E3%81%B9%E3%81%A6%E3%81%AE%E3%83%A1%E3%82%BD%E3%83%83%E3%83%89%E3%81%AF%E3%83%88%E3%83%AA%E3%82%AC%E3%83%BC%E3%83%A2%E3%83%BC%E3%83%89%E3%81%AB"><summary>答え</summary>

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

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

</details>44\. 「`OnCollisionEnter`」の引数（Collision）は何に使えるでしょうか？

<details id="bkmrk-%E7%AD%94%E3%81%88-%C2%A0oncollisionxxxx%E3%81%AE"><summary>答え</summary>

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

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

詳細：[https://docs.unity3d.com/6000.4/Documentation/ScriptReference/Collision.html](https://docs.unity3d.com/6000.4/Documentation/ScriptReference/Collision.html)

</details>45\. 「`SerializeField`」どこで使う？なんのため？

<details id="bkmrk-%E7%AD%94%E3%81%88-%E9%9D%9E%E5%85%AC%E9%96%8B%EF%BC%88private%EF%BC%89%E3%81%AE%E3%83%A1%E3%83%B3%E3%83%90%E3%83%BC"><summary>答え</summary>

非公開（private）のメンバー変数を Unity の Inspector で変えられるようにする。</details>46\. 「event」というキーワードは何に使うのでしょうか？

<details id="bkmrk-%E7%AD%94%E3%81%88-c%23%E3%81%AE%E3%82%A4%E3%83%99%E3%83%B3%E3%83%88%E3%82%92%E5%AE%A3%E8%A8%80%E3%81%99%E3%82%8B%E3%81%A8%E3%81%8D%E3%81%AB%E4%BD%BF%E3%81%86"><summary>答え</summary>

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

発生する側：

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

受け取る側：

- 登録：`オブジェクト.イベント名 += 受け取るメソッド名`
- 受け取る：`void 受け取るメソッド名（引数1, 引数2, …）`

</details>### スクリプト作成

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

<details id="bkmrk-%E7%AD%94%E3%81%88-using-unityengine"><summary>答え</summary>

```c#
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("時間切れ");
    }
}
```

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

<details id="bkmrk-%E7%AD%94%E3%81%88-using-unityengine-1"><summary>答え</summary>

```c#
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();
    }
}
```

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

<details id="bkmrk-%E7%AD%94%E3%81%88-using-unityengine-2"><summary>答え</summary>

```c#
using UnityEngine;

public class CountdownWait : MonoBehaviour
{
    // Unityで紐づけ
    [SerializeField]
    private Countdown countdown;

    private void Start()
    {
        countdown.Timeout += OnTimeout;
    }

    private void OnTimeout()
    {
        Debug.Log("イベントを受け取った");
    }
}
```

</details>### スクリプト解析

#### スクリプト A

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

```c#
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 相手）

<details id="bkmrk-%E7%AD%94%E3%81%88-%E3%80%8C%E8%87%AA%E5%88%86%E3%80%8D---%E5%8F%96%E5%BE%97%E3%81%97%E3%81%9Frigidb"><summary>答え</summary>

「自分」 - 取得したRigidbodyは、本スクリプトと同じゲームオブジェクトにあるので（7行目）</details>51\. どの方向にlinearVelocityが変わる？（自分の方 or 相手の方）

<details id="bkmrk-%E7%AD%94%E3%81%88-%E3%80%8C%E7%9B%B8%E6%89%8B%E3%80%8D---direction%E3%83%99"><summary>答え</summary>

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

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

<details id="bkmrk-%E7%AD%94%E3%81%88-%EF%BC%92%E3%81%A4%E3%81%AE%E3%82%B2%E3%83%BC%E3%83%A0%E3%82%AA%E3%83%96%E3%82%B8%E3%82%A7%E3%82%AF%E3%83%88%E3%82%92%E8%A1%9D%E7%AA%81%E3%81%97%E3%81%9F"><summary>答え</summary>

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

</details>#### スクリプト B

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

```c#
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\. このスクリプトを実行し、スペースキーを押したらどうなるのか説明してください。

<details id="bkmrk-%E7%AD%94%E3%81%88-%E3%81%82%E3%82%8B%E3%83%97%E3%83%AC%E3%83%8F%E3%83%96%E3%81%8B%E3%82%89%E3%82%AA%E3%83%96%E3%82%B8%E3%82%A7%E3%82%AF%E3%83%88%E3%82%92%E3%82%B3%E3%83%94"><summary>答え</summary>

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

</details>#### スクリプト C

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

```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はそれぞれ何ポイントでしょうか？

<details id="bkmrk-%E7%AD%94%E3%81%88-mp%E3%81%AF100%E7%82%B9%E3%80%81hp%E3%81%AF50%E7%82%B9"><summary>答え</summary>

MPは100点、HPは50点

</details>55\. 11行目〜17行目でどんなことが行われていると思う？

<details id="bkmrk-%E7%AD%94%E3%81%88-%C2%A0%E3%83%88%E3%83%AA%E3%82%AC%E3%83%BC%E3%81%AB%E5%85%A5%E3%81%A3%E3%81%9F%E3%81%A8%E3%81%8D%E3%80%81%E5%85%A5%E3%81%A3%E3%81%A6%E3%81%8D%E3%81%9F"><summary>答え</summary>

 トリガーに入ったとき、入ってきたゲームオブジェクトのタグは「fire」だったら、HPが５点減る</details>56\. HPの回復処理を説明してください。

<details id="bkmrk-%E7%AD%94%E3%81%88-%E3%80%8Cq%E3%80%8D%E3%82%AD%E3%83%BC%E3%82%92%E3%81%8A%E3%81%A3%E3%81%97%E3%81%B1%E3%81%AA%E3%81%97%E3%81%A7%E3%80%81%EF%BC%91%E7%A7%92%E5%BD%93"><summary>答え</summary>

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

</details>57\. "Q”キーを５秒押すと、MPはどうなる？

<details id="bkmrk-%E7%AD%94%E3%81%88-mp%E3%81%AF25%E7%82%B9%E3%81%8C%E6%B8%9B%E3%82%8B"><summary>答え</summary>

MPは25点が減る

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

<details id="bkmrk-%E7%AD%94%E3%81%88-mp%E3%81%AFinspector%E3%81%A7%E7%B7%A8%E9%9B%86%E3%81%8C%E3%81%A7"><summary>答え</summary>

MPはInspectorで編集ができる

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

<details id="bkmrk-%E7%AD%94%E3%81%88-void-ontriggerent"><summary>答え</summary>

```c#
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); 
    }
}
```

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

<details id="bkmrk-%E7%AD%94%E3%81%88-%E3%81%BE%E3%81%9A%E3%80%81%E3%82%B9%E3%82%AF%E3%83%AA%E3%83%97%E3%83%88%E3%81%AE%E9%A0%AD%E3%81%AB%EF%BC%9A-%2F%2F-%E5%9B%9E"><summary>答え</summary>

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

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

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

```c#
if (Input.GetKey(restoreKey))
```

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

<details id="bkmrk-%E7%AD%94%E3%81%88-void-ontriggerent-1"><summary>答え</summary>

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

</details>