コンテンツにスキップ

属性

書き方説明注意
[UdonSynced]変数の同期
[UdonSynced(UdonSyncMode.Linear)]補間つきの同期指定できる種類は型によって違います。
[UdonBehaviourSyncMode(BehaviourSyncMode.Manual)]送るタイミングの指定
[UdonBehaviourSyncMode(BehaviourSyncMode.Continuous)]常時の送信
[FieldChangeCallback(nameof(Value))]変更の通知
[NetworkCallable]ネットワーク越しの呼び出しの許可
[RecursiveMethod]再帰の許可引数とローカル変数の記憶域が、呼び出しごとに作られないためです。
[RecursiveMethod] int Fact(int n)ローカル関数の再帰
[RecursiveMethod] public static int Fact(int n)静的クラスと struct と record のメソッドの再帰
[RecursiveMethod] IsEven / [RecursiveMethod] IsOdd互いに呼び合うメソッド片方だけに付けるとエラーになります(非対応)。
other.SendCustomEvent("Tick")実行中のメソッドへの入り直しコンパイラが、呼び出しの前後で引数とローカル変数を退避して戻すためです。
[Inline]呼び出しの展開
[SerializeField]非公開フィールドの表示
[HideInInspector]公開フィールドの非表示
[Header] [Tooltip]見出しと説明
[Range(0f, 1f)]値の範囲の指定
[Space]余白
[SerializeField, Range(0f, 1f)]1 つのフィールドへの複数指定
[System.Obsolete]非推奨の指定
書き方説明エラー理由代替
private int Down(int n) { return Down(n - 1); }属性を付けずに自分自身を呼ぶTUKI0001環境[RecursiveMethod] を付ける(ループか、自分で持つスタックで書いてもよい)
[RecursiveMethod] の IsEven と、属性の無い IsOdd が呼び合う互いに呼び合うメソッドの片方だけに付けるTUKI0001設計呼び合う全部に [RecursiveMethod] を付ける
SendCustomNetworkEvent(…, nameof(Take), 1)([NetworkCallable] 無し)属性を付けずに、引数つきのメソッドをネットワーク越しに名前で呼ぶTUKI0001環境受け側に [NetworkCallable] を付ける
[DllImport("x")]外部のライブラリを呼ぶTUKI0001環境実行環境のメソッドを使う
引数つきのメソッドの登録名属性が無いと引数の型を含む名前で登録され、nameof で書いた名前と食い違うので名前では参照できません。[NetworkCallable] を付けると、書いた名前のまま登録されます
同期の属性の名前空間この言語の名前空間から書けます。移行元の名前空間を同時に using すると、同じ名前の属性が 2 つ見える状態になってコンパイルのエラーになります(片方の using を外すと通ります。ファイル構成と名前空間)
この表に無い 5 つ[Reactive]・[Computed]・[Effect]・[On] はリアクティブプログラミング、[TsukimiTest] はテストにあります

[UdonSynced] を付けた変数の値が、プレイヤーのあいだで同じに保たれます。

using UnityEngine;
using Tsukimi;
public class AttributesSynced : TsukimiBehaviour
{
[UdonSynced] private int value;
void Start()
{
value = 1;
RequestSerialization();
Debug.Log(value); // => 1
}
}

UdonSyncMode で補間の種類を指定します。

using UnityEngine;
using Tsukimi;
public class AttributesSyncedInterpolated : TsukimiBehaviour
{
[UdonSynced(UdonSyncMode.Linear)] private float value;
void Start()
{
Debug.Log(value); // => 0
}
}

Manual を指定すると、RequestSerialization() を呼んだときに値を送ります。

using UnityEngine;
using Tsukimi;
[UdonBehaviourSyncMode(BehaviourSyncMode.Manual)]
public class AttributesSyncModeManual : TsukimiBehaviour
{
[UdonSynced] private int value;
void Start()
{
value = 1;
RequestSerialization();
}
}

Continuous を指定すると、RequestSerialization() を呼ばずに値が送られます。

using UnityEngine;
using Tsukimi;
[UdonBehaviourSyncMode(BehaviourSyncMode.Continuous)]
public class AttributesSyncModeContinuous : TsukimiBehaviour
{
[UdonSynced] private int value;
void Start()
{
value = 1;
}
}

同期で値が届くと、指定したプロパティの設定側が呼ばれます。

using UnityEngine;
using Tsukimi;
public class AttributesFieldChangeCallback : TsukimiBehaviour
{
[UdonSynced, FieldChangeCallback(nameof(Value))] private int backing;
public int Value
{
get { return backing; }
set { backing = value; }
}
void Start()
{
Value = 1;
Debug.Log(Value); // => 1
}
}

ネットワーク越しの呼び出しの許可

Section titled “ネットワーク越しの呼び出しの許可”

引数つきでネットワーク越しに呼ばれるメソッドには、この属性が必要です。

using UnityEngine;
using Tsukimi;
using VRC.SDK3.UdonNetworkCalling;
public class AttributesNetworkCallable : TsukimiBehaviour
{
[NetworkCallable]
public void Receive(int n)
{
Debug.Log(n);
}
void Start()
{
Debug.Log(1); // => 1
}
}

自分自身を呼ぶメソッドには、この属性が必要です。

using UnityEngine;
using Tsukimi;
public class AttributesRecursiveMethod : TsukimiBehaviour
{
[RecursiveMethod]
private int CountDown(int n)
{
return n <= 0 ? 0 : CountDown(n - 1);
}
void Start()
{
Debug.Log(CountDown(3)); // => 0
}
}

ローカル関数にも付けられます。

using UnityEngine;
using Tsukimi;
public class AttributesRecursiveLocal : TsukimiBehaviour
{
void Start()
{
[RecursiveMethod]
int Fact(int n) { return n <= 1 ? 1 : n * Fact(n - 1); }
Debug.Log(Fact(5)); // => 120
}
}

静的クラスと struct と record のメソッドの再帰

Section titled “静的クラスと struct と record のメソッドの再帰”

静的クラスのメソッドと、struct と record のメソッドにも付けられます。

using UnityEngine;
using Tsukimi;
public static class RecursiveMath
{
[RecursiveMethod]
public static int Fact(int n) { return n <= 1 ? 1 : n * Fact(n - 1); }
}
public struct RecursiveStep
{
public int Step;
[RecursiveMethod]
public int Sum(int n) { return n <= 0 ? 0 : Step + Sum(n - 1); }
}
public record RecursiveTag(int Step)
{
[RecursiveMethod]
public int Sum(int n) { return n <= 0 ? 0 : Step + Sum(n - 1); }
}
public class AttributesRecursiveHelpers : TsukimiBehaviour
{
void Start()
{
RecursiveStep s = new RecursiveStep();
s.Step = 2;
RecursiveTag t = new RecursiveTag(3);
Debug.Log(RecursiveMath.Fact(5)); // => 120
Debug.Log(s.Sum(3)); // => 6
Debug.Log(t.Sum(3)); // => 9
}
}

互いに呼び合うメソッドには、呼び合う全部に付けます。

using UnityEngine;
using Tsukimi;
public class AttributesRecursiveMutual : TsukimiBehaviour
{
[RecursiveMethod]
private bool IsEven(int n) { return n == 0 ? true : IsOdd(n - 1); }
[RecursiveMethod]
private bool IsOdd(int n) { return n == 0 ? false : IsEven(n - 1); }
void Start()
{
Debug.Log(IsEven(4)); // => true
}
}

実行中のメソッドへの入り直し

Section titled “実行中のメソッドへの入り直し”

その場でほかのコードを実行する呼び出しから実行中のメソッドへ入り直す形には、属性は必要ありません。

using Tsukimi;
using VRC.Udon;
public class AttributesReentryThroughOther : TsukimiBehaviour
{
public UdonBehaviour other;
public int depth;
public int last;
public void Hit()
{
int mine = depth;
depth = depth + 1;
// other の Tick がこの Behaviour の Hit を呼び返しても、戻った後の mine はこの呼び出しの値のまま。
if (depth < 2) other.SendCustomEvent("Tick");
last = mine;
}
}
退避する呼び出し自分の Behaviour へ送るイベント(自分への SendCustomEvent、送り先が Others でない自分への SendCustomNetworkEvent)と、別の Behaviour のコードをその場で実行しうる呼び出しです。別の Behaviour は、クラスによらずこの Behaviour を呼び返しうるので、メソッドの呼び出し・SendCustomEvent・SetProgramVariable、SetActive、enabled への書き込み、Destroy、Networking.SetOwner、Transform の親や子の並びを変える呼び出し(SetParent・parent への代入・DetachChildren・SetSiblingIndex など。呼び出しから戻る前に OnTransformParentChanged と OnTransformChildrenChanged が実行されます)、VRCObjectPool.TryToSpawn などが当たります
退避しない呼び出し別の Behaviour のフィールドを読む操作(GetProgramVariable を含む)と、遅延の送信(SendCustomEventDelayedFrames など)です。遅延の送信は後で実行されるので、同じ処理の安い書き方ではなく、別のプログラムです
退避する呼び出しの例外Instantiate と、3D の Collider の enabled への書き込みです。呼び出しの間には何も実行されません(複製の OnEnable と Start は後のフレームで実行され、Collider を無効にしてもトリガーのイベントは送られません)
費用退避は、その呼び出しの時点でメソッドが持っているローカル変数と途中の値をすべて運びます。複数の場所から呼ばれるメソッドは、戻り先を見つけるためにそれぞれの呼び出し元と比べるので、facts.cost は呼び出しそのものよりずっと大きく増えることがあります。書き方を比べるときは inspect の facts.cost で測ります
確認退避するメソッドは inspect の facts.recursiveMethods に出ます(この例では Hit)
UdonSharp への書き出し別の Behaviour を経由して入り直しうるメソッドには [RecursiveMethod] を付けて書き出すので、UdonSharp でも入り直しの前後でローカル変数が保たれます。その場で始まる自分の Behaviour のイベントを通って入り直しうるメソッドを含む Behaviour は、書き出されません(実行中のメソッドへの入り直し)

この属性を付けたメソッドは、大きさによらず呼び出しの場所へ展開されます。

using UnityEngine;
using Tsukimi;
public class AttributesInline : TsukimiBehaviour
{
[Inline]
private int Twice(int n) { return n * 2; }
void Start()
{
Debug.Log(Twice(2)); // => 4
}
}

非公開のフィールドでも、Inspector から値を代入できます。

using UnityEngine;
using Tsukimi;
public class AttributesSerializeField : TsukimiBehaviour
{
[SerializeField] private int value;
void Start()
{
Debug.Log(value); // => 0
}
}

非公開のフィールドが Inspector に出ている

フィールドは公開のままで、Inspector には出なくなります。

using UnityEngine;
using Tsukimi;
public class AttributesHideInInspector : TsukimiBehaviour
{
[HideInInspector] public int value;
void Start()
{
Debug.Log(value); // => 0
}
}

公開フィールドが 1 つあるのに、Inspector には行が出ていない

[Header] は見出しを、[Tooltip] はマウスを乗せたときの説明を、Inspector に出します。

using UnityEngine;
using Tsukimi;
public class AttributesHeaderAndTooltip : TsukimiBehaviour
{
[Header("Group")]
[Tooltip("note")]
public int value;
void Start()
{
Debug.Log(value); // => 0
}
}

Inspector に見出しが出ている

説明はマウスを乗せたときだけ出るので、この画像には写っていません。

Inspector ではスライダーになり、指定した範囲の外の値を代入できなくなります。

using UnityEngine;
using Tsukimi;
public class AttributesRange : TsukimiBehaviour
{
[Range(0f, 1f)] public float value;
void Start()
{
Debug.Log(value); // => 0
}
}

Inspector の入力欄がスライダーになっている

Inspector の幅が狭いと、スライダーは出ずに数値の欄だけになります。範囲の制限は同じように適用されます。

Inspector の項目のあいだに余白を入れます。

using UnityEngine;
using Tsukimi;
public class AttributesSpace : TsukimiBehaviour
{
[Space]
public int value;
void Start()
{
Debug.Log(value); // => 0
}
}

余白を空けた側の Inspector

上が余白を空けた側です。空けない側は次のように詰まります。

余白を空けていない側の Inspector

using UnityEngine;
using Tsukimi;
public class AttributesMultipleOnOneField : TsukimiBehaviour
{
[SerializeField, Range(0f, 1f)] private float value;
void Start()
{
Debug.Log(value); // => 0
}
}

この属性を付けたメンバを使うと、警告が出ます。

using UnityEngine;
using Tsukimi;
public class AttributesObsolete : TsukimiBehaviour
{
[System.Obsolete]
public void Old() { }
void Start()
{
Debug.Log(1); // => 1
}
}