Unityの超個人的メモ

# 「Unityの教科書 Unity 2021完全対応版」を読む
ちょっと書き留めておきたいことを書いておくだけ。

https://www.sbcr.jp/product/4815611347/

### スクリプトとゲームオブジェクト(GameObject)
C#のスクリプトはヒエラルキーウィンドウ上のゲームオブジェクト(GameObject)にアタッチすることで初めて実行できる。
要はスクリプトによって魂を吹き込むのだ。スクリプトの中からオブジェクトの位置などを変更することができる。
特定のオブジェクトではなく、ゲーム全体の進行を統括する特殊なオブジェクトを**監督オブジェクト**と呼んだりする。
監督オブジェクトはゲームオブジェクトの状態変化などに応じてUIの更新を行ったりする。

### コンポーネントとは
ゲームオブジェクトは基底クラスのようなものであって、物体を表示したり、音を鳴らしたりする場合は
ゲームオブジェクトに対してコンポーネントをアタッチする必要がある。座標を持つオブジェクトなら`Transform`コンポーネントというような感じに。
ちなみにゲームオブジェクトにアタッチしたスクリプトもコンポーネントの一種である。
アタッチされているコンポーネントの取得は`GetComponent()`メソッドを使用する。

### キー入力の取得
キー入力の取得関数はいくつかあるが、入力判定(=戻り値がtrueになる)のタイミングが微妙に異なる。
- `GetKey()`: キーを押している間ずっとtrueになる(=押しっぱなしで連続入力扱いになる)。
- `GetKeyDown()`: キーを押し込んだ瞬間に1回だけtrueになる。
- `GetKeyUp()`: キーを話した瞬間に1回だけtrueになる。

### Prefabの考え方
敵キャラや弾丸などの繰り返し複数個も生成されるものは`Prefab`というひな形を作り、
そのオブジェクトのひな形をもとにジェネレータスクリプト(いわば工場)によって実際のオブジェクトを生産するような手法をとる。
このとき、ジェネレータには何の`Prefab`を使って生産すればいいのかを教える必要がある。要は工場に設計図を渡す必要がある。
そこで、`Prefab`を受け入れるメンバーを`public`で定義しておけば`Inspector`の画面から使用する`Prefab`を選択できる(これをアウトレット接続という)。

ジェネレータスクリプトを使わずに手動でインスタンス化してやる方法もある。
あらかじめオブジェクトを配置する場所が決まっている場合などはこちらのほうが楽かもしれない。

`Prefab`を作る操作は若干クセがある。いったんヒエラルキーウィンドウで普通のゲームオブジェクトと同様に設定をしたら、プロジェクトウィンドウにドラッグ＆ドロップして新たなアセットに変換する。

### 物理エンジン(Physics)の使いどころ
`Physics`コンポーネントを使うと衝突や落下などの物理的な挙動を簡単に実現することができる。
スーパーマリオのようにステージ上をキャラクターが動くアクションゲームや当たり判定が複雑なゲームでは`Physics`を使うとよいらしい。
`Physics`を使用してオブジェクトを移動させる場合は、`Transform`コンポーネントのように座標を直接書き換えるのではなく、力をオブジェクトに与える。

当たり判定の種類は`Collision`モードと`Trigger`モードがあり、`Collision`は物体が当たると跳ね返るが、`Trigger`はすり抜ける。これは`Colider`の`IsTrigger`から設定する。
いずれのモードにおいても衝突の状況に応じてコールバックのメソッドが呼び出される。

衝突時の挙動を表現したい場合、衝突する2つのオブジェクトに`Colider`と`Rigidbody`をアタッチする。当たり判定だけをしたい場合、`Colider`は両方に必要だが、`Rigidbody`は少なくとも一方にアタッチすればよい。

`Rigidbody`には`IsKinematic`という設定がある。これを`true`にすると物理演算が適用されなくなる。キネマティックは`運動学的な`という意味があり、加速度などの動的な要因を考慮しないことを示している。

### データのやり取りの雑なまとめ
- 他のゲームオブジェクトにアクセスする。
    - `GameObject.Find()`を使ってゲームオブジェクトを取得し、`public`なメンバにアクセスする。
- ゲームオブジェクトのコンポーネントにアクセスする。
    - `GetComponent<型>()`を使ってコンポーネントを取得し、`public`なメンバにアクセスする。
- `Inspector`からゲームオブジェクトにデータを渡す。
    - `public`なフィールドなどを用意しておき、`Inspector`から引数を与える。
    - `Prefab`にインスタンス化したいゲームオブジェクトを渡す場合などに使用する。
- UIのイベントに応じてゲームオブジェクトのメソッドを呼び出す。
    - 呼び出したいメソッドを`public`に公開しておき、`Inspector`の`OnClick`などにメソッド名を指定する。
    - UI上のボタン操作などをスクリプトに伝えたい場合などに使用する。

### アニメーションの作り方
スプライト(キャラクター、アイテム、発射物や他の 2D ゲーム要素として使用される 2D グラフィックスオブジェクト)が移動した際に歩く動作を表示したい場合はアニメーションを作るとよい。以下のような手順で作る。
1. スプライトの画像を用意し、プロジェクトウィンドウに追加しておく。
1. ヒエラルキーウィンドウからアニメーションを設定したいオブジェクトを選択する。
1. `Animation`ウィンドウを開いてスプライトの画像が切り替わるタイミングを設定する。
1. スクリプトファイルから動作を微調整をする。

### スクリーン座標とワールド座標系の変換
3Dゲームにおいてクリック位置を取得すると、その位置はスクリーン座標系での値になっている。
人間がクリックするゲーム画面は2Dなので、その位置情報をそのまま3Dの座標情報に変換することはできないが、
ゲーム画面を作り出しているカメラとの位置関係が分かれば3Dの座標系(ワールド座標系)の値に変換することができる。
`ScreenPointToRay()`メソッドを使用し、スクリーン座標系上のクリック位置とカメラ位置を結ぶ光線(`Ray`)を取得する。
この光線はワールド座標系におけるベクトルのようなものである。

`Ray`はこのようないかにもベクトルっぽい使い方だけでなく、`Colider`と組み合わせて衝突を検出することもできる。
光線が物体にぶつかるか、ぶつかったのであればどこにぶつかったのかなどを調べることができる。

### 3Dの影がギザギザしているのが気になる場合
`Edit->Project Settings->Quality->Shadow Distance`を小さい値にするとギザギザが減る。

### ちょっとした忘備
- UI要素を追加すると`Canvas`と一緒に`EventSystem`が追加される。これはユーザの入力とUI部品を中継するオブジェクトであり、UI要素を使うならば必ず必要。