UnityのいろいろなTips 

# はじめに
当たり前に設定していることでも忘れてしまうことがよくあるので備忘録もかねて記事にしました。  
Unityのバージョンは、**2017.4** を基準に作成してあります。  


# 画面サイズを変更するとUIが崩れる
Canvas Scalerが"Constant Pixel Size"になっているのが原因。  
下の画像のように"UI Scale Mode"を"Scale With Screen Size"にするとよい。  
また、"Reference Resolution"にはメインで使用する解像度を指定しておく。  
<font color="red">※ただし、アスペクト比を変える場合はここの設定だけでは不十分</font>  
スマートフォンの複数バージョン対応や、縦横持ち対応などのアスペクト比を変えた場合のUIの設計は、  
Unity公式ドキュメントに [複数解像度のためのUI設計](https://docs.unity3d.com/ja/current/Manual/HOWTO-UIMultiResolution.html) がありますので、そちらを参照ください。
![cc9009570527503c5835bc7e32f476e0.png](https://qiita-image-store.s3.amazonaws.com/0/242152/b13fc9cb-b02f-82f5-5aa8-dbe93a8bb290.png)

# スクリプト上でUIを生成した時に原点がずれる
例えば、

``` CSharp
Image img = new GameObject("img").AddComponent<Image>();
img.rectTransform.position = Vector2.zero;
```
と、しても原点に生成されないときがあります。  
UIの複数の解像度にも対応した相対的な位置は、"anchoredPosition"を使用します。

``` CSharp
Image img = new GameObject("obj").AddComponent<Image>();
img.rectTransform.anchoredPosition = new Vector2(0,0);
```

# Publicな変数がInspectorでも変更できてしまう  
宣言した変数上に"[System.NonSerialized]"を書けばInspectorに表示されなくなります。  
Editorで変更する仕様でない限り、書いておけば他人が見たときに外から読み取りたい旨がわかるようになります。

``` CSharp
[System.NonSerialized]
Public int hoge = 0;
```

# Privateな変数をInspectorに表示させたい
表示させたい変数の上に"[SerializeField]"を書く。  
Editor上で値を書き換えたいときにPublicだと外から読み(書き)たいのか、Inspectorから指定したいのかわからないので、privateな変数でも大丈夫ならこちらの方法で書くといいでしょう。

``` CSharp
[SerializeField]
private int hoge = 0;
```

# フレームレートが落ちる(カクカクする)とキャラクターのスピードが遅くなる
Unity上でスクリプトを作成するとデフォルトでUpdate()が生成されてしまうため、そこに書きがちですが、Updateはフレームレート依存な関数なので、移動などの物理的な挙動に関してはFixedUpdate()に書くか、Update()に書く場合はTime.deltaTimeをかけるといいです。
参考までに

``` CSharp
void Update()
{
  gameObject.transform.position += Vector3.forward * Time.deltaTime;
}
```

もしくは、

``` CSharp
void FixedUpdate()
{
 gameObject.transform.position += Vector3.forward;
}
```

# 他のScriptから参照したい
UnityというかC#の話なうえ、ケースバイケースでその時によって変わりますが、使い分けてください。  
当たり前に使うことですが、なぜか調べてもなかなか出てこない上にGameObject.Find()が目立っている気がしたのでいろいろな方法を載せておきます。

## ManagerとしてSingletonにする
Enemyとか、Itemなど同じものが複数個生成される場合では使えませんが、GameManager等の一つしか生成されないスクリプトによく使う方法です。

``` CSharp:hogeManager.cs
public int hoge = 100;

public static Instance;
void Awake()
{
 if(Instance == null) Instance = this;
}

void OnDisable()
{
 Instance = null;
}

```

とし、呼び出すほうでは、

``` CSharp
void Start()
{
 Debug.Log(hogeManager.Instance.hoge); //100
}
```
とすると簡単に使用できます。Singletonの詳しい使い方や組み方、MonoBehaviourとのより良い共存方法などは調べると沢山出てきます。  
そちらのほうが丁寧に分かりやすく解説されていると思いますので、各自で調べてみてください。

## FindWithTag()等で保持しておく

参照したいScriptがついているGameObjectにTagをつけて、StartやAwakeで保持しておく方法。  
GameObject.Find()でも大丈夫ですが、重たい処理な為、特に利用が制限される場合じゃなければFindWithTag()を利用するのが無難だと思います。

``` CSharp

HogeScript hoge;

void Start()
{
 hoge = GameObject.FindWithTag("hoge").GetComponent<HogeScript>();
}
```

## Inspectorで直接アタッチする

SerializeField等でInspectorに表示させ、ドラッグアンドドロップでアタッチする方法です。  
直感的でわかりやすく手間のかからない方法ですが、プロジェクトファイルを移動した際にアタッチが外れることが多々あります。  

## 接触したオブジェクトに送る

上記と違い、極端に限定的ですが、Enemyに当たったらダメージを与えるとか、Itemに触れたらインベントリに入れるなど、  
接触した時に接触したもののスクリプトを呼びたい時に使う方法です。  

``` CSharp

void OnTriggerEnter(collider col)
{
 if(col.tag == "enemy")
 {
  col.GetComponent<enemy>().Damage();
 }
}

```  

# あとがき
もっといろいろ書きたいことがあった気がしますが、思い出せないのでその都度更新していく予定です。  
それではよきUnityライフを！

# 参考文献
[Unity - Manual](https://docs.unity3d.com/Manual/index.html)