ちょっとだけ便利になるかもしれない拡張メソッド集 [Unity]

# はじめに
自分が個人的なゲーム開発をする際に使い回している拡張メソッド集を紹介します。
拡張メソッドを定義する動機ですが、例えば、`Instantiate`は複製したいオブジェクトを引数で渡す静的メソッドですが、拡張メソッドの形で定義しておくことでコードを書く流れに沿って記述できるようになります(書きやすくなったと感じるかは人によると思います)。
```CS
// 通常
Instantiate(gameObject);
// 拡張メソッド
gameObject.Instantiate();
```
なお下記メソッド群は何らかの静的クラス内に定義することを想定しています。

# GetOrAddComponent
対象の`GameObject`が指定した`T`型のコンポーネントを持つ場合はそれを取得し、なければ追加して返す拡張メソッドです。
```CS
public static T GetOrAddComponent<T>(this GameObject gameObject) where T : Component
{
    var component = gameObject.GetComponent<T>();
    return component != null ? component : gameObject.AddComponent<T>();
}

public static T GetOrAddComponent<T>(this Component component) where T : Component
{
    return GetOrAddComponent<T>(component.gameObject);
}
```

## 使い方
```CS
// GameObjectから取得するか作成して返す
var sampleMonoBehaviour = gameObject.GetOrAddComponent<SampleMonoBehaviour>();
// Componentに対しても生えている
this.GetOrAddComponent<SampleMonoBehaviour>();
```

# Instantiate
プレハブやシーン上に既にあるインスタンスを複製(生成)して返します。

```CS
/// <summary>
/// 拡張対象のGameObjectを複製(生成)して返す
/// </summary>
public static GameObject Instantiate(this GameObject gameObject)
{
    return Object.Instantiate(gameObject);
}

/// <summary>
/// 生成後に親となるTransformを指定して、拡張対象のGameObjectを複製(生成)して返す
/// </summary>
public static GameObject Instantiate(this GameObject gameObject, Transform parent)
{
    return Object.Instantiate(gameObject, parent);
}

/// <summary>
/// 生成後の座標及び姿勢を指定して、拡張対象のGameObjectを複製(生成)して返す
/// </summary>
public static GameObject Instantiate(this GameObject gameObject, Vector3 pos, Quaternion rot)
{
    return Object.Instantiate(gameObject, pos, rot);
}

/// <summary>
/// 生成後に親となるTransform、また生成後の座標及び姿勢を指定して、拡張対象のGameObjectを複製(生成)して返す
/// </summary>
public static GameObject Instantiate(this GameObject gameObject, Vector3 pos, Quaternion rot, Transform parent)
{
    return Object.Instantiate(gameObject, pos, rot, parent);
}

/// <summary>
/// 生成後に親となるTransform、また生成後のローカル座標を指定して、拡張対象のGameObjectを複製(生成)して返す
/// </summary>
public static GameObject InstantiateWithLocalPosition(this GameObject gameObject, Transform parent,
    Vector3 localPos)
{
    var instance = Object.Instantiate(gameObject, parent);
    instance.transform.localPosition = localPos;
    return instance;
}

public static T Instantiate<T>(this T component) where T : Component
{
    return Object.Instantiate(component);
}

public static T Instantiate<T>(this T component, Transform parent) where T : Component
{
    return Object.Instantiate(component, parent);
}

public static T Instantiate<T>(this T component, Vector3 pos, Quaternion rot) where T : Component
{
    return Object.Instantiate(component, pos, rot);
}

public static T Instantiate<T>(this T component, Vector3 pos, Quaternion rot, Transform parent)
    where T : Component
{
    return Object.Instantiate(component, pos, rot, parent);
}

public static T InstantiateWithLocalPosition<T>(this T component, Transform parent,
    Vector3 localPos) where T : Component
{
    var instance = Object.Instantiate(component, parent);
    instance.transform.localPosition = localPos;
    return instance;
}
```

## 使い方
```CS
using UnityEngine;

public class InstantiateUser : MonoBehaviour
{
    [SerializeField] private SampleMonoBehaviour samplePrefab;

    private void Start()
    {
        // samplePrefabを複製して、生成したインスタンスを返却
        var createdInstance = samplePrefab.Instantiate();
        // 生成後の座標を指定
        samplePrefab.Instantiate(transform);
        // 生成後の座標・姿勢を指定
        samplePrefab.Instantiate(Vector3.zero, Quaternion.identity);
        // 生成後の座標・姿勢・親を指定
        samplePrefab.Instantiate(Vector3.zero, Quaternion.identity, transform);
        // 生成後の親・ローカル座標を指定
        samplePrefab.InstantiateWithLocalPosition(transform, Vector3.zero);
    }
}
```

# IsInLayerMask
渡された`LayerMask`と`GameObject`のレイヤーを比較し、`LayerMask`内に`GameObject`のレイヤーが含まれているかを返します。
```CS
public static bool IsInLayerMask(this GameObject gameObject, LayerMask layerMask)
{
    int objLayerMask = (1 << gameObject.layer);
    return (layerMask.value & objLayerMask) > 0;
}

public static bool IsInLayerMask(this Component component, LayerMask layerMask)
{
    return IsInLayerMask(component.gameObject, layerMask);
}
```

## 使い方
```CS
using UnityEngine;

public class Player : MonoBehaviour
{
    [SerializeField] private LayerMask attackTarget;

    public void Attack(Enemy enemy)
    {
        // ターゲットレイヤーに含まれている場合のみ攻撃
        if (enemy.IsInLayerMask(attackTarget))
        {
        }
    }
}
```

# Destroy
拡張対象のオブジェクトを破棄します。

```CS
public static void Destroy(this GameObject gameObject)
{
    Object.Destroy(gameObject);
}

public static void Destroy(this Component component)
{
    Object.Destroy(component);
}

/// <summary>
/// ComponentがアタッチされているGameObjectを破棄する
/// </summary>
public static void DestroyGameObject(this Component component)
{
    Object.Destroy(component.gameObject);
}
```

## 使い方
```CS
SampleMonoBehaviour sampleMonoBehaviour1 = this.AddComponent<SampleMonoBehaviour>();
SampleMonoBehaviour sampleMonoBehaviour2 = this.AddComponent<SampleMonoBehaviour>();

sampleMonoBehaviour1.Destroy();
sampleMonoBehaviour2.Destroy();
sampleMonoBehaviour2.gameObject.Destroy();
```