シリアライズ可能なクラス
CoddyのUnityジャーニー「Unityにおけるゲームアーキテクチャ」セクションの一部。レッスン 15/50。
設定が多いスクリプトは、Inspector に長く平坦なリストとして表示されます。通常の C# クラスを使えば、設定をまとめられます。[System.Serializable] を付けると、そのクラス型のフィールドはフィールド名の折りたたみ項目として表示され、その中にクラスのフィールドが並びます。1 つのクラスを複数のフィールドや複数のスクリプトで使えます。
[System.Serializable]
public class Stats
{
public float speed = 2f;
public int damage = 10;
}
public class Enemy : MonoBehaviour
{
public Stats normal;
public Stats enraged;
private Stats current;
void Start()
{
current = normal;
}
void Update()
{
transform.Translate(0f, 0f, current.speed * Time.deltaTime);
}
public void Enrage()
{
current = enraged;
}
}Inspector には Normal と Enraged の 2 つの折りたたみ項目が表示され、それぞれに Speed と Damage があります。各 Enemy はそれぞれ独自の Stats オブジェクトを 2 つ持ち、各自の Inspector で値を設定します。コードからは normal.speed のように読み取ります。Unity はスクリプトの読み込み時にこれらのオブジェクトを作成するため、= new Stats() がなくても normal が null になることはありません。また、フィールド初期化子(2 と 10)が新しい Enemy の初期値になります。struct も同じ属性を付ければ同様に機能します。[System.Serializable] public struct Range { public float min; public float max; }。また、Vector3 と同様に、代入時にコピーされます。
この属性が必要なのは、Unity が指定された型だけを保存するためです。付けないと、クラスは Inspector に表示されません。折りたたみ項目はなく、そこで設定した値は保存されず、Unity はオブジェクトも作成しないため、normal.speed は NullReferenceException をスローします。クラス内でも通常の Inspector のルールが適用されます。public フィールド、または [SerializeField] を付けた private フィールドを使い、プロパティや static フィールドは使いません。
チャレンジ
簡単探検家の懐中電灯には2種類のビームがあり、Spaceキーで切り替えます。周囲を見渡すための、幅広く暖かみのあるビームと、洞窟の奥深くまで届く、集束した冷たい白色のビームです。Flashlight.csでは、それぞれのビームの3つの設定を、独立した6つのフィールドに保存しています。シーンでは、設定がビームごとにグループ化されているので、スクリプトもそれに合わせる必要があります。
- 3つのpublicフィールドを持つ構造体
Beamを宣言します。フィールドはcolor(Color)、range、angle(float)です。Inspectorに表示されるようにします。 - 6つの独立したフィールドを、2つのBeamフィールド
wideとfocusedに置き換えます。シーンでは、wideは暖かみのある色、rangeは6、angleは80に設定されており、focusedは冷たい白色、rangeは15、angleは25に設定されています。 Apply()で現在のビームのBeamを読み取り、そこからLightのcolor、range、spotAngleを設定します。それ以外はそのままです。懐中電灯はwideビームで開始し、Spaceキーでビームを切り替えます。
Playを押し、Spaceキーを押して洞窟の奥を照らしてから、Checkを押します。
自分で試してみよう
using UnityEngine;
using UnityEngine.InputSystem;
public class Flashlight : MonoBehaviour
{
public Color wideColor = Color.white;
public float wideRange = 5f;
public float wideAngle = 60f;
public Color focusedColor = Color.white;
public float focusedRange = 10f;
public float focusedAngle = 30f;
private bool focusedOn;
private Light lamp;
void Start()
{
lamp = GetComponent<Light>();
Apply();
}
void Update()
{
if (Keyboard.current.spaceKey.wasPressedThisFrame)
{
focusedOn = !focusedOn;
Apply();
}
}
void Apply()
{
lamp.color = focusedOn ? focusedColor : wideColor;
lamp.range = focusedOn ? focusedRange : wideRange;
lamp.spotAngle = focusedOn ? focusedAngle : wideAngle;
}
}
このレッスンには短いクイズがあります。レッスンを始めて解答し、進捗を記録しましょう。