Unityでリファクタリングことはじめ、旧いサンプルで見かけるアンチパターン

# ダメだといわれるコードを書いてしまう要因
Unityの初心者向けのサイトや書籍でよくやってしまう悪手が幾つかあります。気付かない原因は、
- スケールが小さいゲームだと処理落ちも最初はほとんどなくて放置していること、全体が小さいので自分で管理しているだけだと気にならない
- ネットや書籍に書いてある安易な方法が、小さなサンプルでのみ有効でスケールを大きく作ると支障になる

という場合です。その後、スケールが大きくなったり多人数で共同作業すると失敗することがよくあります。そうしたパターンを並べてみます。

# 何に気を付けるべきなのか
基本的に何を気にすべきかは決まっています。大まかには以下を今回は取り上げます。
1. 処理が冗長になっていないか
同じ処理を一度でいいのに繰り返しているところ。これは目の前のコードでアルゴリズム的に無駄な場合と、フレームを跨いで同じ処理を繰り返す場合、同じ処理を多くのインスタンスでやっている場合も当てはまります。
1. 大規模になってから設計が耐えられるか
何処からでも他の`GameObject`を参照することを可能にした設計がUnityの基本ですが、そこから「触らない方が好い」ものも触れてしまいます、そのために誰かが意図しないでどこかの変数を書き換える、ということが生じます。これをできるだけ避けた方が、意図しない動作をしたときに原因を突き止めて修正がしやすくなります。

# アンチパターンの例
ここからは、実際によく見かける、初心者がサンプルから悪手を学んでしまうパターンを挙げてみます。


### [パターン1]`Update()`に色々入れる
`Update()`に入っている処理は、フレームをまたぐと**無条件で実行される無限ループ**の中に書いたのと同じです。それに気づかないと無駄を生みます。
例えば、何かのフラグが`true`になってるとき"CAUTION"と出すGameObjectを有効にする、という処理を書いたとします。
```Csharp
public bool cautionFlag=false;
public GameObject cautionDisplay;
void Update(){
    if( cautionFlag )
    {
        cautionDisplay.SetActive( true );
    }
    else
    {
        cautionDisplay.SetActive( false );
    }
}
```
この場合、何の`Update()`でやってるかということもありますが、Flagを毎フレームで判断します、もし毎フレームの状況が刻々と変化しないなら、無駄です。

まず、単純化すると以下に書き直せます。

```C#
public bool cautionFlag=false;
public GameObject cautionDisplay;
void Update(){
    cautionDisplay.SetActive( cautionFlag );
}
```
`if`は排除できましたが、これでも「毎フレームの状況が刻々と変化するか」によって、状況は変わります。この場合、`cautionFlag`を引数にして`SetActive`を呼ぶので、アセンブラでいうと単純にPUSHとCALL、POP、RETURNは最低限、実行されます（インライン展開が無い場合）。既に`true`でもまた`true`でというように、同じ値の状態でも実行されるので、結果的に無駄です。
この場合では、`cautionFlag`を書き換えている部分がこのコード上では無いので、何処か他で書き換えないと制御できません。そのフラグを書き換えるタイミングが、この場合は明確にあればその時々でやればいい処理で、それをあえて`Update()`で遅延実行していることになります。
テストして確認すると、`cautionFlag`が`true`になるフレームの次のフレームで表示されるのが確認できます。
この形のままで、無駄に状態が変わらないときに処理しなくする方法は以下があります。
```C#
    public GameObject cautionDisplay;
    private bool cautionFlag = false;
    public bool CautionFlag
    {
        get => cautionFlag;
        set
        {
            if (value != cautionFlag)
            {
                cautionFlag = value;
                cautionDisplay.SetActive(cautionFlag);
            }
        }
    }
    private void Start()
    {
        cautionDisplay.SetActive(cautionFlag);
    }
```
`set`で`CautionFlag`に何か代入されたときに、値が書き換わっているかを確認しています。書き換えられた時には`SetActive`を実行し、状態を変えます。
これをやらなくても、おそらく`GameObject`の内部で同様の処理はしていると想像できますが、呼び出す手間が無駄であり、そして毎フレームすることが無駄なので、これで解消できます。遅延実行もないのでそのフレームの中で処理が行われ、遅れて変化することもありません。
プログラムの処理はCPUとGPUで１フレームを作ることの繰り返しなので、基本的にフレーム毎のループ処理で、ゲームエンジンを用いない場合はC++であれば`main()`などのエントリポイントから初期化後に必ずループする部分があります。つまり、すべてを`Upddate()`に置けば理論上はすべて実装できて動きます。そうした理由で、実装することだけを目標にすると、こうした無駄な処理に気付かないことがあります。

---
### [パターン2]値が変わらないものを再び探す

以下のコードがあったとします。
```C#
[RequireComponent(typeof(CautionDisplayManager))]

void ChangeMessage(string message){
    GetComponent<CautionDisplayManager>().SetText( message );
}
```
この処理は
1. `GameObject.GetComponent`でを用いて型に合う`Component`を探す
1. その中の`.SetText`というメソッドを実行する

という２段階の処理が実行されており、前段階はComponentの差し替えが無い場合は同一の参照を返します。勿論、差し替えられる可能性がある場合は使えませんが、差し替えられることがバグでしかない場合は無視できます。そうした場合は以下に書き換えた方が得策になります。

```C#
private CautionDisplayManager cautionDisplayManager;

void Awake(){
     cautionDisplayManager = GetComponent<CautionDisplayManager>();
}
void ChangeMessage(string message){
    cautionDisplayManager.SetText( message );
}
```
`Update()`内で実行している場合があったら、確実に見直しましょう。他の参照を得るFind等も同様です。こうしてキャッシュしておくことで冗長な処理がなくなり、処理落ちの一因を排除できます。こうした処理や変数の生成も相まって、毎回、繰り返す必要があるかを常に考えましょう。確実に一意の参照しかない場合は、もしかすると`static`を用いたり、分けた`class`をひとつにまとめた方が好い、という場合もあります。また、ここでは見えていませんが、`GetComponent`は失敗する恐れがあるので、その辺の対策は施すべきです、見直す時間が減らせます。

[参考]
* [[Unity初心者Tips]確実に！必要なComponentを入れるRequire ComponentとReset()](https://qiita.com/JunShimura/items/6576eb63c19c2c9f0c0a)
* [[Unity初心者Tips]FindとGetComponentを実行しエラーにどこから呼び出されたかを出す便利メソッド](https://qiita.com/JunShimura/items/32d342830ae917ed55d9)
* [Component.TryGetComponent](https://docs.unity3d.com/ScriptReference/Component.TryGetComponent.html)

---
### [パターン3]何にアタッチされているかをコンポーネント側で判断する
コンポーネントの汎用性を高めるため、色々な`GameObject`にアタッチできるようしていくうちに、何かを判定して振る舞いをかえるように考えて、以下のようなclassを作ったとします。Scene内で、以下の型のキャラクターがあると想定しています。
| 1 | 2 | 3 | 4 |
|:-:|:-:|:-:|:-:|
| player  | monster  | citizen  | animal  |
| 人型の主人公  | 怪物  | 街の人  | 街の動物  |

それぞれの処理をまとめておきたいと考えてひとつのコンポーネントを作ったとします。

```C#
public class CharacterController : MonoBehaviour
{
    public enum CharacterType { // キャラクターのタイプ
        player, 
        monster, 
        citizen , 
        animal
    }
    public CharacterType type;

    // Update is called once per frame
    void Update()
    {
        /*
        全タイプの処理がここにある
        */
        //タイプで分かれる処理
        if (type == CharacterType.player)
        {
            //　Playerの処理
        }
        else if (type == CharacterType.monster) {
            //　Monsterの処理
        }
        if (type == CharacterType.citizen|| type== CharacterType.player)
        {
            // 人型の処理
        }
    }
}
```

これをゲーム内の`GameObject`にそれぞれアタッチして、`CharacterType`で切り替え汎用性を高めようという設計です。しかしながら、アタッチの仕方を変えればこの判定は要りません、毎フレームの無駄な判定の典型です。このコンポーネントの形が有効になる可能性があるとすれば、敵味方が一秒のうちに数十回など頻繁に入れ替わって毎フレーム変化する、という場合ですが、果たしてそういうゲームでしょうか。
この無駄を省く対策方法はいくつかありますが、上記でやったフラグの変更を残して`Action`や`Delegate`で処理する、という方法もありますが、別の方法を探るとした場合、コンポーネントを分けることで対応したとしましょう。
#### まずは仕様を確認
| type |  player | monster | citizen | animal |
|:-|:-:|:-:|:-:|:-:|
| 全タイプの処理  | ◯  | ◯ | ◯ | ◯ |
| playerの処理  | ◯  |   |   |   |
| Monsterの処理  |   | ◯  |   |   |
| 人型の処理  | ◯ |   | ◯ |   |

処理がこのように分かれているので、この場合で必要なのは、以下の`Component`になる。
- 全タイプの処理
- Player
- Monster
- 人型

これらをそれぞれ個別で`Component`にする。どのように個別で用意するかは、以下の方法があります。
##### 方法1)独立した`Component`にする
それぞれで`MonoBehaviour`から派生した`class`を作ります。
```Csharp:Character.cs
public class Character : MonoBehaviour
{
    void Update()
    {
        /*
        全タイプの処理がここにある
        */
        Debug.Log("Update on Character");
    }
}
```
Player側はCharacterの全タイプの処理を必須にアタッチしたいので`[RequireComponent(typeof(Character))]`によって確実にアタッチさせます。

```Csharp:Player.cs
[RequireComponent(typeof(Character))]
public class Player : MonoBehaviour
{
    // Update is called once per frame
    void Update()
    {
        // Playerの処理
        Debug.Log("Update on Player");
    }
}
```
他の`class`も同様に作れます。ただし、ここで問題点があります。`Update`の実行順序が制御できない点です。

![image.png](https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/72979/b870f36d-ea27-acdd-72ad-60352778753a.png)
試しにこの状態で動かすと、実行順番が以下になります。
![image.png](https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/72979/80ef7fda-9ac2-fb38-35a0-391aff4ce8ad.png)

この状態は容易に変えられないことを覚えておきましょう。もし、元の形のように共通の処理をやってからPlayer個別の処理を実行したい場合は、以下のように検討します。

* `Update`が必要か見直して他に変える
* `Character`側の`Update`を別のメソッドに変えて廃止し、`Palyer`から呼び出す

`Update`は汎用性が高いですが、色々な問題を孕みやすいのでできるだけ排除した方が得策になります。

##### 方法2)派生した`Component`にする
処理が内包されているので、上記の`Character`から派生した`PlayerEx`を作ってみます。

```Csharp:PlayerEx.cs
public class PlayerEx : Character
{
    // Update is called once per frame
    void Update()
    {
        // Playerの処理
        Debug.Log("Update on Player");
    }
}
```

これのみをアタッチして実行してみます。

![image.png](https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/72979/8b45fb52-c5d5-7cf4-eda0-6b6e7e20a8e3.png)

そうすると、`PlayerEx`の`Update`のみが実行されます。
この場合は`Character`側での`Update`が無効になるので、`Character`側のメソッドを`Update`ではない`public`か`protected`の別のメソッドにし、それを呼び出す形にすることで対処は可能ですが、前述の個別でコンポーネントを持たせて対応するのと変わらない状況になります。
いずれにせよ、仕様で検討が必要なのは、

:::note warn
 `Update`が複数ある状況は注意が必要
:::

ということです。それでは、初めの`Update`内で判定していたものが好いのか、というとそうではありません。CPU資源をできるだけ消費しないことは、常に意識が必要です。特に判定文はCPU実行のパイプラインにも影響するので、できるだけ排除した方が好いことになります。例えば、時間経過で処理するのに`DeltaTime`を用いるのも`Coroutine`など他の方法が色々、あります。入力処理は`InputSystem`と`OnMove`があれば`Update()`不要で無駄が減ります。
実行順番を制御したい場合、以下も参考になるので見ておきましょう。

[Unity公式の情報]
* [DefaultExecutionOrder](https://docs.unity3d.com/6000.0/Documentation/ScriptReference/DefaultExecutionOrder.html)
* [Script Execution Order](https://docs.unity3d.com/ja/2022.1/Manual/class-MonoManager.html)
* [OnMove](https://docs.unity3d.com/ja/2018.4/ScriptReference/UI.Selectable.OnMove.html)
* [InputSystem](https://docs.unity3d.com/ja/Packages/com.unity.inputsystem@1.4/manual/index.html)

##### 方法3)処理判定を`Awake`で一度だけにして`Action`で処理を構築する
コードが長いですが、元の処理をそのまま再現できる方法がこれになります。
```Csharp:CharacterControllerEx.cs
public class CharacterControllerEx : MonoBehaviour
{
    public enum CharacterType {　// キャラクターのタイプ
        player, 
        monster, 
        citizen , 
        animal
    }
    private Action charactorAction=null;
    private CharacterType _characterType;
    public CharacterType type {
        get => _characterType;
        set
        {
            _characterType = value;
            SetAction();
        }
    }
    [SerializeField]CharacterType defaultType = CharacterType.player;
    private void AllAction()
    {
        //　全プレイヤーの処理
        Debug.Log("Action All Character");
    }

    private void PlayerAction()
    {
        //　全プレイヤーの処理
        Debug.Log("Action Player");
    }
    private void MonsterAction()
    {
        //　全プレイヤーの処理
        Debug.Log("Action monster");
    }
    private void HumanAction()
    {
        //　全プレイヤーの処理
        Debug.Log("Action Human");
    }
    private void SetAction()
    {
        charactorAction = AllAction;
        if (type == CharacterType.player)
        {
            //　Playerの処理
            charactorAction += PlayerAction;
        }
        else if (type == CharacterType.monster)
        {
            //　Monsterの処理
            charactorAction += MonsterAction;
        }
        if (type == CharacterType.citizen || type == CharacterType.player)
        {
            // 人型の処理
            charactorAction += HumanAction;
        }
    }

    private void Awake()
    {
        type = defaultType;
    }
    // Update is called once per frame
    void Update()
    {
        charactorAction();
    }
}

```
処理をそれぞれのブロックごとをメソッド化し、Actionに必要な処理を登録します。こうすることでロジックが簡略化します。もっと進めるとDictionaryでActionにする方法が可能です。
```Csharp
 Dictionary<CharacterType,Action> MethodTable = new Dictionary<CharacterType,Action>();

```
この`Dictionary`に`CharacterType`毎のMethodを登録しておきます。そして`Update`で実行する`Action`にコピーします。汎用性が一番高いのはこれですが、大分、コードが長くなります。後々に利用する可能性があるならあっても好い、という程度でしょうか。

---
### [パターン4]同じ判断を複数のインスタンスで行う
例えばゲームオーバーの判定を複数個所で行っている、という場合です。Scriptが一つでも複数にアタッチしていて同じ判定をしていると無駄が生じます、適宜、中身を見直しましょう。

---
### [パターン5]FindやGetComponentを多用する
これの難点は以下になります。
* 何処のオブジェクトから何を操作しているのか判らなくなると、バグがあった場合に切り分けができず解決を困難にする
* 文字列比較をしているとその分のタイプミスや無駄な動作から逃れられない

オブジェクトの参照は一方向にして、出来るだけ他のコンポーネントの参照を控える形にしておくと、デバッグやメンテナンスが飛躍的に容易くなるのでお勧めします。文字列もtagなどで用いますが、レイヤを駆使して利用を控えるなどが効率化につながります。
プログラミングパターンを学ぶとよいでしょう。

## まとめ

Unityは容易くゲームが作れることを目標にしているため、`Update()`で簡単にゲームを組み立てるなど、そのノリに乗っかりすぎてる場合、簡単にゲームが作れるけど、求めていたものが作れる道をぼかしてしまいます。
実装が進むとどんどんゲームらしくなってきて面白いので見直さずに手を休めずに作り続けた結果、増築を繰り返した建造物のように全体がアンバランスで、手を加えるのがどうしたら好いか分らなくなりがちです。そうなるともう作りたくなくなって、また最初から作ろう、ということにも繋がり、これがループするだけだとまた同じことを繰り返して半端な制作物を量産しがちです。
きちんと設計しておいた方が後から楽で、更に再利用できる部分が増えていくので、また新しいものに取り掛かっても無駄が少なくなります。
そうしたことを考えて製作に臨みましょう、手を動かしただけ、後に指数関数的に能力が拡張できます。