属性
対応(19)
Section titled “対応(19)”| 書き方 | 説明 | 注意 |
|---|---|---|
[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] | 非推奨の指定 |
非対応(4)
Section titled “非対応(4)”| 書き方 | 説明 | エラー | 理由 | 代替 |
|---|---|---|---|---|
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 }}補間つきの同期
Section titled “補間つきの同期”UdonSyncMode で補間の種類を指定します。
using UnityEngine;using Tsukimi;
public class AttributesSyncedInterpolated : TsukimiBehaviour{ [UdonSynced(UdonSyncMode.Linear)] private float value;
void Start() { Debug.Log(value); // => 0 }}送るタイミングの指定
Section titled “送るタイミングの指定”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 }}ローカル関数の再帰
Section titled “ローカル関数の再帰”ローカル関数にも付けられます。
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 }}互いに呼び合うメソッド
Section titled “互いに呼び合うメソッド”互いに呼び合うメソッドには、呼び合う全部に付けます。
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 は、書き出されません(実行中のメソッドへの入り直し) |
呼び出しの展開
Section titled “呼び出しの展開”この属性を付けたメソッドは、大きさによらず呼び出しの場所へ展開されます。
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
Section titled “Inspector”非公開フィールドの表示
Section titled “非公開フィールドの表示”非公開のフィールドでも、Inspector から値を代入できます。
using UnityEngine;using Tsukimi;
public class AttributesSerializeField : TsukimiBehaviour{ [SerializeField] private int value;
void Start() { Debug.Log(value); // => 0 }}
公開フィールドの非表示
Section titled “公開フィールドの非表示”フィールドは公開のままで、Inspector には出なくなります。
using UnityEngine;using Tsukimi;
public class AttributesHideInInspector : TsukimiBehaviour{ [HideInInspector] public int value;
void Start() { Debug.Log(value); // => 0 }}
見出しと説明
Section titled “見出しと説明”[Header] は見出しを、[Tooltip] はマウスを乗せたときの説明を、Inspector に出します。
using UnityEngine;using Tsukimi;
public class AttributesHeaderAndTooltip : TsukimiBehaviour{ [Header("Group")] [Tooltip("note")] public int value;
void Start() { Debug.Log(value); // => 0 }}
説明はマウスを乗せたときだけ出るので、この画像には写っていません。
値の範囲の指定
Section titled “値の範囲の指定”Inspector ではスライダーになり、指定した範囲の外の値を代入できなくなります。
using UnityEngine;using Tsukimi;
public class AttributesRange : TsukimiBehaviour{ [Range(0f, 1f)] public float value;
void Start() { Debug.Log(value); // => 0 }}
Inspector の幅が狭いと、スライダーは出ずに数値の欄だけになります。範囲の制限は同じように適用されます。
Inspector の項目のあいだに余白を入れます。
using UnityEngine;using Tsukimi;
public class AttributesSpace : TsukimiBehaviour{ [Space] public int value;
void Start() { Debug.Log(value); // => 0 }}
上が余白を空けた側です。空けない側は次のように詰まります。

1 つのフィールドへの複数指定
Section titled “1 つのフィールドへの複数指定”using UnityEngine;using Tsukimi;
public class AttributesMultipleOnOneField : TsukimiBehaviour{ [SerializeField, Range(0f, 1f)] private float value;
void Start() { Debug.Log(value); // => 0 }}非推奨の指定
Section titled “非推奨の指定”この属性を付けたメンバを使うと、警告が出ます。
using UnityEngine;using Tsukimi;
public class AttributesObsolete : TsukimiBehaviour{ [System.Obsolete] public void Old() { }
void Start() { Debug.Log(1); // => 1 }}