Unityに おいて、クラスに属性を付けることは、特定の用途でクラスの挙動やインスペクターでの表示を制御するために使われます。
これにより、Unityエディター上での動作をカスタマイズしたり、クラスのインスペクターでの表示方法を制御することができます。
いくつかの代表的なクラスに対する属性とその用途を紹介します。
1. [System.Serializable]
[System.Serializable]属性は、クラスをインスペクターで表示するために使用されます。この属性を付けることで、そのクラスがUnityのシリアル化システムに対応し、インスペクターで表示・編集できるようになります。
使用例:
[System.Serializable]
public class CustomData
{
public string message;
public int value;
}
public class SerializableExample : MonoBehaviour
{
public CustomData data;
}
CustomDataクラスに[System.Serializable]を付けることで、SerializableExampleクラスのdataフィールドがインスペクターで表示されるようになります。
2. [RequireComponent]
[RequireComponent]属性は、指定したコンポーネントが必須であることを示します。この属性をクラスに付けると、スクリプトがアタッチされたときに、指定したコンポーネントも自動的にアタッチされます。
使用例:
[RequireComponent(typeof(Rigidbody))]
public class RequireComponentExample : MonoBehaviour
{
void Start()
{
Rigidbody rb = GetComponent<Rigidbody>();
if (rb != null)
{
Debug.Log("Rigidbody is attached");
}
}
}
RequireComponent属性を使うと、このスクリプトをオブジェクトにアタッチするときに、自動的にRigidbodyコンポーネントが追加されます。
3. [AddComponentMenu]
[AddComponentMenu]属性を使うと、スクリプトをコンポーネントメニューに登録し、メニュー内で簡単に見つけられるようにできます。カスタムクラスを特定の場所に配置するのに便利です。
使用例:
[AddComponentMenu("Custom/CustomComponent")]
public class CustomComponent : MonoBehaviour
{
void Start()
{
Debug.Log("Custom Component Added");
}
}
AddComponentMenu属性を付けることで、Unityエディターの「Add Component」メニューにCustom/CustomComponentという項目が追加され、そこから直接アタッチできるようになります。
4. [ExecuteInEditMode]
[ExecuteInEditMode]属性を付けることで、クラスのメソッドがエディター上で実行中でも動作するようになります。通常はプレイモードでしか実行されない処理を、エディターでオブジェクトを編集している際にも実行できます。
使用例:
[ExecuteInEditMode]
public class EditModeExample : MonoBehaviour
{
void Update()
{
Debug.Log("Running in Edit Mode");
}
}
ExecuteInEditModeを付けることで、このクラスはプレイモード外でもUpdateメソッドが呼び出されるようになります。
5. [DisallowMultipleComponent]
[DisallowMultipleComponent]属性を付けると、同じコンポーネントを複数追加することを防ぐことができます。この属性は、特定のコンポ ーネントが1つしか存在しないようにしたい場合に使用します。
使用例:
[DisallowMultipleComponent]
public class SingleComponentExample : MonoBehaviour
{
void Start()
{
Debug.Log("This component can't be added more than once");
}
}
DisallowMultipleComponentを付けると、このスクリプトをオブジェクトに2つ以上追加することができなくなります。
System.Serializableを使って、カスタムクラスや構造体を作成し、それをUnityEventの引数として利用することは可能です。さらに、これによりインスペクターでカスタムクラスのフィールドを設定できるようになります。
ただし、UnityEvent自体に直接System.Serializableを適用するわけではなく、カスタムクラスやデータ構造をSystem.Serializableにして、それをUnityEventの引数として扱う形になります。
以下に、System.Serializableなカスタムクラスを作成し、それをUnityEventに渡してインスペクターから引数を設定する例を示します。
1. SerializableなクラスをUnityEventに渡す例
ステップ 1: カスタムクラスを作成し、Serializableにする
using System;
using UnityEngine;
// このクラスをインスペクターでシリアライズ可能にする
[System.Serializable]
public class CustomData
{
public string message;
public int value;
}
CustomDataクラスは、System.Serializable属性を使用してイン スペクターで編集できるようにしています。- このクラスには、
string型のmessageと、int型のvalueというフィールドを持っています。
ステップ 2: UnityEventでカスタムクラスを使用する
using UnityEngine;
using UnityEngine.Events;
public class UnityEventWithCustomData : MonoBehaviour
{
// CustomDataを引数に取るUnityEvent
[System.Serializable]
public class CustomDataEvent : UnityEvent<CustomData> { }
// インスペクターで設定できるUnityEvent
public CustomDataEvent onCustomDataEvent;
public CustomData data;
void Start()
{
// イベントを発火し、CustomDataを渡す
onCustomDataEvent?.Invoke(data);
}
}
UnityEvent<CustomData>を定義して、インスペクターからCustomDataを渡せるようにしています。onCustomDataEventはCustomDataEvent型で、CustomDataを引数として受け取ります。
ステップ 3: インスペクターで設定
- Unityエディター上で、このスクリプトをGameObjectにアタッチします。
- スクリプトをアタッチしたGameObjectのインスペクターに、
onCustomDataEventが表示されます。 - さらに
CustomDataクラスのフィールド(messageとvalue)もインスペクターに表示されます。 - イベントリスナーを設定し、実行時に指定した引数が渡されるようにします。
2. カスタムクラスを使ってイベントを処理する例
using UnityEngine;
public class CustomDataReceiver : MonoBehaviour
{
// イベントが発生したときに呼び出されるメソッド
public void OnCustomDataReceived(CustomData data)
{
Debug.Log($"Received message: {data.message}, Value: {data.value}");
}
}
- こちらは、
UnityEventで渡されたCustomDataを受け取るクラスです。 OnCustomDataReceivedメソッドをインスペクターでイベントリスナーに登録し、イベントが発生したときにこのメソッドが実行されます。
3. インスペクターでの設定方法
UnityEventWithCustomDataスクリプトを持つGameObjectを選択すると、インスペクターにonCustomDataEventの設定フィールドが表示されます。- 「+」ボタンを押してリスナーを追加します。
- リスナーに
CustomDataReceiverを持つGameObjectを割り当て、その中のOnCustomDataReceivedメソッドを選択します。 - これで、
StartメソッドでonCustomDataEvent.Invoke(data)が実行されると、CustomDataReceiverのOnCustomDataReceivedメソッドが呼び出され、CustomDataが渡されます。
System.Serializableの別の使い方
[System.Serializable]はJSONシリアライズの際にも役立ちます。 UnityでデータをJSON形式に変換する場合、クラスやデータ構造がシリアライズ可能である必要があり、[System.Serializable]を使うことでそれが実現できます。
[System.Serializable]の主な使いどころは、Unityのシリアライズシステムやデータの永続化に関わる部分です。JSONシリアライズ以外にも、いくつかの使い所がありますので、それぞれについて詳しく説明します。
1. JSONシリアライズ
[System.Serializable]は、Unityの**JsonUtility**を使ってデータをJSONに変換するために必要です。JsonUtilityは、クラスや構造体をJSON形式に変換したり、逆にJSONからオブジェクトに変換したりできますが、その際にシリアライズ可能であることが前提です。
使用例:
using UnityEngine;
[System.Serializable]
public class PlayerData
{
public string playerName;
public int level;
public float health;
}
public class JsonExample : MonoBehaviour
{
void Start()
{
PlayerData player = new PlayerData { playerName = "John", level = 10, health = 99.5f };
// オブジェクトをJSONに変換
string json = JsonUtility.ToJson(player);
Debug.Log("Serialized JSON: " + json);
// JSONをオブジェクトに変換
PlayerData deserializedPlayer = JsonUtility.FromJson<PlayerData>(json);
Debug.Log("Deserialized Player Name: " + deserializedPlayer.playerName);
}
}
PlayerDataクラスは[System.Serializable]を付けているので、JsonUtilityでJSON形式に変換できます。
2. インスペクターでカスタムクラスを表示
[System.Serializable]は、Unityのインスペクターにカスタムクラスや構造体を表示させるためにも使用されます。通常、Unityのインスペクターではプリミティブ型(int、float、stringなど)やUnityの組み込み型(Vector3、Quaternionなど)のみが表示されますが、[System.Serializable]を付けることで、独自に定義したクラスもインスペクターに表示できるようになります。
使用例:
[System.Serializable]
public class Weapon
{
public string name;
public int damage;
}
public class Inventory : MonoBehaviour
{
public Weapon sword;
}
- この例では、
Weaponクラスに[System.Serializable]を付けているため、InventoryスクリプトをアタッチしたGameObjectのインスペクターにWeaponクラスのフィールドが表示されます。
3. スクリプタブル・オブジェクトでのデータ保存
[System.Serializable]は、スクリプタブル・オブジェクトと組み合わせて使用され、ゲームデータや設定を保存するために利用されます。スクリプタブル・オブジェクトは、データをオブジェクトとして扱うための仕組みであり、Unityエディター上でデータを作成・保存・編集できるようにします。シリアライズ可能にすることで、カスタムデータを保存可能にします。
使用例:
[System.Serializable]
public class EnemyStats
{
public int health;
public int attack;
public float speed;
}
[CreateAssetMenu(fileName = "NewEnemy", menuName = "Enemy Stats")]
public class EnemyData : ScriptableObject
{
public EnemyStats stats;
}
EnemyStatsをシリアライズすることで、ScriptableObjectのインスペクターで敵のステータスを設定・保存できるようになります。
4. セーブデータの永続化
[System.Serializable]は、データをファイルに保存する場合にも利用されます。例えば、バイナリ形式やJSON形式でセーブデータを保存する場合、シリアライズ可能なオブジェクトとして扱われ、ゲームの状態を保存・読み込む際に使われます。
使用例:
using System.IO;
using System.Runtime.Serialization.Formatters.Binary;
using UnityEngine;
[System.Serializable]
public class GameData
{
public int score;
public int level;
}
public class SaveLoadExample : MonoBehaviour
{
public GameData data;
public void SaveGame()
{
BinaryFormatter formatter = new BinaryFormatter();
using (FileStream file = File.Create(Application.persistentDataPath + "/savefile.dat"))
{
formatter.Serialize(file, data);
}
}
public void LoadGame()
{
if (File.Exists(Application.persistentDataPath + "/savefile.dat"))
{
BinaryFormatter formatter = new BinaryFormatter();
using (FileStream file = File.Open(Application.persistentDataPath + "/savefile.dat", FileMode.Open))
{
data = (GameData)formatter.Deserialize(file);
}
}
}
}
- この例では、
GameDataクラスがシリアライズされ、バイナリ形式でセーブファイルに保存されています。
5. カスタムエディターの作成
[System.Serializable]は、カスタムエディターを作成するときにも役立ちます。インスペクターの見た目をカスタマイズしたり、特定のクラスやデータ構造を扱いやすくするために利用されます。
例えば、カスタムクラスをシリアライズして、そのデータをカスタムエディター上で扱うことで、より直感的なUIを作成できます。
シリアライズするデータクラスを作成
using UnityEngine;
[System.Serializable]
public class Weapon
{
public string weaponName;
public int damage;
public float range;
}
public class WeaponHolder : MonoBehaviour
{
public Weapon[] weapons;
}
このデータクラスを表示するカスタムエディターを作成
using UnityEngine;
using UnityEditor;
[CustomEditor(typeof(WeaponHolder))]
public class WeaponHolderEditor : Editor
{
public override void OnInspectorGUI()
{
// デフォルトのインスペクターレイアウトを描画
DrawDefaultInspector();
// ターゲットのWeaponHolderオブジェクトを取得
WeaponHolder weaponHolder = (WeaponHolder)target;
// カスタムフィールドの表示
if (GUILayout.Button("Print Weapon Names"))
{
foreach (Weapon weapon in weaponHolder.weapons)
{
Debug.Log(weapon.weaponName);
}
}
}
}
ボタンを押すと、インスペクターに表示された武器リストの名前がログに出力されます。