コンポーネントどうしの連携
書ける形(30)
Section titled “書ける形(30)”| 書き方 | 説明 |
|---|---|
GetComponent<Renderer>() | 型引数での取得 |
GetComponent(typeof(Renderer)) | 型の値での取得 |
GetComponentInChildren<Renderer>() | 子からの取得 |
GetComponentInParent<Renderer>() | 親からの取得 |
GetComponentInChildren<Renderer>(true) | 無効なオブジェクトを含めた取得 |
GetComponents<Renderer>() | 同じ型すべての取得 |
GetComponentsInChildren<Renderer>() | 子からのすべての取得 |
target.GetComponent<Renderer>() | 別のオブジェクトからの取得 |
transform.Find("Lamp") | 名前での子の取得 |
GetComponent<ComponentsLamp>() | 自分で書いた型での取得 |
GetComponents<ComponentsSpeaker>() | 自分で書いた型すべての取得 |
GetComponent<TsukimiBehaviour>() | 基底の型での取得 |
GetComponent<UdonBehaviour>() | 実行環境の型での取得 |
SendCustomEvent(nameof(Ping)) | 自分への呼び出し |
other.SendCustomEvent("Ping") | 別のプログラムへの呼び出し |
SendCustomEventDelayedSeconds(nameof(Ping), 1.5f) | 秒を置いた呼び出し |
SendCustomEventDelayedFrames(nameof(Ping), 10) | フレームを置いた呼び出し |
SendCustomEventDelayedSeconds(nameof(Ping), 1f, EventTiming.LateUpdate) | 呼ばれる時機の指定 |
[NetworkCallable] public void Hit(int damage) | 引数のあるメソッドの登録 |
door.Open() | メソッドの呼び出し |
counter.Add(5) | 引数を渡す呼び出し |
board.Score() | 戻り値のある呼び出し |
tank.level | フィールドの読み出し |
dial.position = 3 | フィールドへの書き込み |
public ComponentsLight[] lights; | 配列での参照 |
public IComponentsSwitch target; | インタフェースでの参照 |
public UdonBehaviour other; | 実行環境の型での参照 |
(int)other.GetProgramVariable("count") | 値の読み出し |
other.SetProgramVariable("count", 5) | 値の書き込み |
GetProgramVariable(nameof(count)) | 自分の変数の読み書き |
書けない形(12)
Section titled “書けない形(12)”| 書き方 | 説明 | エラー | 理由 | 代わりに |
|---|---|---|---|---|
SendCustomEvent("Ping") | 自分に Ping というメソッドが無い | TUKI0001 | 設計 | 名前を直す。nameof で書くと綴りの誤りが出ない |
SendCustomEvent(nameof(Ping)) | Ping が private になっている | TUKI0001 | 設計 | public にする |
SendCustomEvent(nameof(Hit)) | Hit が引数を取る | TUKI0001 | 設計 | Hit に [NetworkCallable] を付ける |
[NetworkCallable] private void Ping() | 属性を public でないメソッドに付ける | TUKI0001 | 環境 | public にする |
[NetworkCallable] public static void Ping() | 属性を static メソッドに付ける | TUKI0001 | 環境 | static を外す |
[NetworkCallable] public int Ping() | 属性を戻り値のあるメソッドに付ける | TUKI0001 | 環境 | 戻り値を void にする |
[NetworkCallable] public void Ping(a, ..., i) | 属性を引数 9 個のメソッドに付ける | TUKI0001 | 環境 | 引数を 8 個までにする |
GetComponents<UdonBehaviour>() | UdonBehaviour を型引数にして全部取る | TUKI0001 | 未実装 | GetComponents(typeof(UdonBehaviour)) と書く |
sink.Take(p) | 自分で作った struct を相手へ渡す | TUKI0101 | 未定 | 成分ごとに分けて渡す |
sink.Take(ref n) | ref を付けて相手へ渡す | TUKI0001 | 未実装 | 戻り値で受け取る |
Gate.Ping() | 相手の型の static メソッドを呼ぶ | TUKI0001 | 未定 | static を外して、相手の実体のメソッドとして呼ぶ |
holder.__state | __ で始まるフィールドを相手から触る | TUKI0001 | 設計 | 名前の先頭の __ を外す |
2 つの呼び方
Section titled “2 つの呼び方”| 名前で呼ぶ | 型を持って呼ぶ | |
|---|---|---|
| 相手の持ち方 | TsukimiBehaviour か UdonBehaviour | 相手の Behaviour の型 |
| 書き方 | other.SendCustomEvent("Ping") | door.Open() |
| 呼べるメソッド | public なもの(引数があるときは [NetworkCallable] が要る) | public で static でないもの |
| 引数 | SendCustomEvent では渡せない(ネットワーク越しに送る形は同期) | 渡せる(単独の値と、その配列) |
| 戻り値 | 受け取れない | 受け取れる |
| 名前の誤り | 自分に送るときだけコンパイラが見る | コンパイラが見る |
| 相手のファイル | 要らない | 要る |
型を持って呼ぶ形は、名前で呼ぶ形に変換されてから走ります。引数は相手の変数へいったん書き込まれて
渡るので、変数に置けない型は渡せません。自分で作った struct を渡せないのはこのためです(上の表)。
GetComponent は、その型が付いていなければ null を返します。transform.Find も、
その名前の子が無ければ null を返します。返ってきた null を
そのまま使うと実行が止まります(Udon の実行モデル)。
名前の検査の範囲
Section titled “名前の検査の範囲”自分に送る名前は、コンパイラが検査します。SendCustomEvent(nameof(Ping)) と書いて Ping が
自分に無ければ、コンパイルが止まります。
相手に送る名前は検査しません。相手のプログラムは別のファイルにあり、コンパイラはそのファイルを
見ていないためです。相手に無い名前を送っても、コンパイルは通ります。GetProgramVariable と
SetProgramVariable に渡す名前も、同じ理由で検査しません。
1 つのファイルに書けるもの
Section titled “1 つのファイルに書けるもの”このページの例は 1 つのファイルで完結させるため、相手の形だけを abstract で置いています。
実際に書くときは、相手を別のファイルに具象の Behaviour として置いて、そこから継承させるか、
その型をそのままフィールドの型に書きます。
名前で呼んだときに起きること
Section titled “名前で呼んだときに起きること”- 名前で呼ぶと、相手はそのメソッドを実行します
- 相手に無い名前を送っても、何も起きません。エラーにはなりません
- 名前で読み書きすると、相手の
privateなフィールドにも届きます。見える範囲は C# の 規則で、実行環境の側には残らないためです
コンポーネントの取得
Section titled “コンポーネントの取得”同じ GameObject に付いているコンポーネントは GetComponent で取ります。
見つからなければ null が返るので、使う前に調べます。
型引数での取得
Section titled “型引数での取得”取りたい型を型引数に書きます。同じ GameObject に付いているコンポーネントを 1 つ返します。
using UnityEngine;using Tsukimi;
public class ComponentsGetComponent : TsukimiBehaviour{ void Start() { Renderer r = GetComponent<Renderer>(); Debug.Log(r == null); }}型の値での取得
Section titled “型の値での取得”型引数の代わりに型の値を渡す形も書けます。戻り値は Component なので、使う型へキャストします。
using UnityEngine;using Tsukimi;
public class ComponentsGetComponentTypeof : TsukimiBehaviour{ void Start() { Renderer r = (Renderer)GetComponent(typeof(Renderer)); Debug.Log(r == null); }}子からの取得
Section titled “子からの取得”自分と、自分の下にぶら下がっているオブジェクトを探します。
using UnityEngine;using Tsukimi;
public class ComponentsGetComponentInChildren : TsukimiBehaviour{ void Start() { Renderer r = GetComponentInChildren<Renderer>(); Debug.Log(r == null); }}親からの取得
Section titled “親からの取得”自分と、自分の上にあるオブジェクトを探します。
using UnityEngine;using Tsukimi;
public class ComponentsGetComponentInParent : TsukimiBehaviour{ void Start() { Renderer r = GetComponentInParent<Renderer>(); Debug.Log(r == null); }}無効なオブジェクトを含めた取得
Section titled “無効なオブジェクトを含めた取得”true を渡すと、無効になっているオブジェクトも探します。渡さなければ有効なものだけを探します。
using UnityEngine;using Tsukimi;
public class ComponentsGetComponentInactive : TsukimiBehaviour{ void Start() { Renderer r = GetComponentInChildren<Renderer>(true); Debug.Log(r == null); }}同じ型すべての取得
Section titled “同じ型すべての取得”同じ型のコンポーネントが複数付いているとき、全部を配列で受け取ります。
using UnityEngine;using Tsukimi;
public class ComponentsGetComponents : TsukimiBehaviour{ void Start() { Renderer[] all = GetComponents<Renderer>(); Debug.Log(all.Length); }}子からのすべての取得
Section titled “子からのすべての取得”下にぶら下がっているオブジェクトの分も含めて、全部を配列で受け取ります。
using UnityEngine;using Tsukimi;
public class ComponentsGetComponentsInChildren : TsukimiBehaviour{ void Start() { Renderer[] all = GetComponentsInChildren<Renderer>(); Debug.Log(all.Length); }}別のオブジェクトからの取得
Section titled “別のオブジェクトからの取得”GameObject を持っていれば、そのオブジェクトに付いているコンポーネントを取れます。
using UnityEngine;using Tsukimi;
public class ComponentsGetComponentOfObject : TsukimiBehaviour{ public GameObject target;
void Start() { Renderer r = target.GetComponent<Renderer>(); Debug.Log(r == null); }}名前での子の取得
Section titled “名前での子の取得”子のオブジェクトを名前で探します。見つからなければ null が返ります。
using UnityEngine;using Tsukimi;
public class ComponentsFindChild : TsukimiBehaviour{ void Start() { Transform child = transform.Find("Lamp"); Debug.Log(child == null); }}自分で書いた型での取得
Section titled “自分で書いた型での取得”自分で書いた Behaviour の型でも取れます。返ってきた値は、そのままメソッドを呼べます。
using UnityEngine;using Tsukimi;
public abstract class ComponentsLamp : TsukimiBehaviour{ public abstract void TurnOn();}
public class ComponentsGetComponentOwnType : TsukimiBehaviour{ void Start() { ComponentsLamp lamp = GetComponent<ComponentsLamp>(); if (lamp != null) { lamp.TurnOn(); } }}自分で書いた型すべての取得
Section titled “自分で書いた型すべての取得”自分で書いた Behaviour の型でも、全部を配列で受け取れます。
using UnityEngine;using Tsukimi;
public abstract class ComponentsSpeaker : TsukimiBehaviour{ public abstract void Play();}
public class ComponentsGetComponentsOwnType : TsukimiBehaviour{ void Start() { ComponentsSpeaker[] all = GetComponents<ComponentsSpeaker>(); Debug.Log(all.Length); }}基底の型での取得
Section titled “基底の型での取得”基底の型でも取れます。相手の型を知らずに、名前で呼ぶ相手だけを持ちたいときの形です。
using UnityEngine;using Tsukimi;
public class ComponentsGetComponentBehaviour : TsukimiBehaviour{ void Start() { TsukimiBehaviour b = GetComponent<TsukimiBehaviour>(); Debug.Log(b == null); // => 実行環境の値 }}実行環境の型での取得
Section titled “実行環境の型での取得”実行環境が持っている UdonBehaviour の型でも取れます。
using UnityEngine;using Tsukimi;using VRC.Udon;
public class ComponentsGetComponentUdonBehaviour : TsukimiBehaviour{ void Start() { UdonBehaviour b = GetComponent<UdonBehaviour>(); Debug.Log(b == null); }}using UnityEngine;using Tsukimi;using VRC.Udon;
public class R_components_get_components_udon : TsukimiBehaviour{ void Start() { UdonBehaviour[] all = GetComponents<UdonBehaviour>(); Debug.Log(all.Length); }}名前での呼び出し
Section titled “名前での呼び出し”メソッドの名前を文字列で渡すと、そのメソッドが呼ばれます。名前で呼べるのは public な
メソッドです。名前は nameof でも文字列リテラルでも書けます。
自分への呼び出し
Section titled “自分への呼び出し”自分のメソッドを名前で呼びます。自分に無い名前を書くと、コンパイルが止まります。
using UnityEngine;using Tsukimi;
public class ComponentsSendCustomEvent : TsukimiBehaviour{ public void Ping() { Debug.Log(1); }
void Start() { SendCustomEvent(nameof(Ping)); }}using UnityEngine;using Tsukimi;
public class R_components_unknown_name : TsukimiBehaviour{ void Start() { SendCustomEvent("Ping"); }}別のプログラムへの呼び出し
Section titled “別のプログラムへの呼び出し”TsukimiBehaviour の型で相手を持てば、相手の型を知らなくても名前で呼べます。
この形の名前はコンパイラが検査しません(名前の検査の範囲)。
using UnityEngine;using Tsukimi;
public class ComponentsSendCustomEventOther : TsukimiBehaviour{ public TsukimiBehaviour other;
void Start() { other.SendCustomEvent("Ping"); }}秒を置いた呼び出し
Section titled “秒を置いた呼び出し”using UnityEngine;using Tsukimi;
public class ComponentsSendDelayedSeconds : TsukimiBehaviour{ public void Ping() { Debug.Log(1); }
void Start() { SendCustomEventDelayedSeconds(nameof(Ping), 1.5f); }}フレームを置いた呼び出し
Section titled “フレームを置いた呼び出し”using UnityEngine;using Tsukimi;
public class ComponentsSendDelayedFrames : TsukimiBehaviour{ public void Ping() { Debug.Log(1); }
void Start() { SendCustomEventDelayedFrames(nameof(Ping), 10); }}呼ばれる時機の指定
Section titled “呼ばれる時機の指定”第 3 引数で、フレームのどこで呼ばれるかを選べます。書かなければ Update になります。
using UnityEngine;using Tsukimi;using VRC.Udon.Common.Enums;
public class ComponentsSendDelayedTiming : TsukimiBehaviour{ public void Ping() { Debug.Log(1); }
void Start() { SendCustomEventDelayedSeconds(nameof(Ping), 1f, EventTiming.LateUpdate); }}引数のあるメソッドの登録
Section titled “引数のあるメソッドの登録”引数のあるメソッドは、そのままの名前では呼べません。[NetworkCallable] を付けると、
そのままの名前で呼べるようになります。SendCustomEvent に引数を渡す口はありません。
using UnityEngine;using Tsukimi;using VRC.SDK3.UdonNetworkCalling;
public class ComponentsSendCustomEventWithArguments : TsukimiBehaviour{ [NetworkCallable] public void Hit(int damage) { Debug.Log(damage); }
void Start() { SendCustomEvent(nameof(Hit)); }}using UnityEngine;using Tsukimi;
public class R_components_send_with_args : TsukimiBehaviour{ public void Hit(int damage) { Debug.Log(damage); }
void Start() { SendCustomEvent(nameof(Hit)); }}型を持った参照
Section titled “型を持った参照”相手の型を持つと、メソッドをそのまま呼べます。引数と戻り値をコンパイラが検査するので、
名前で呼ぶ形より誤りが早く出ます。以下の例は 1 つのファイルで完結させるため、相手の形だけを
abstract で置いています(1 つのファイルに書けるもの)。
メソッドの呼び出し
Section titled “メソッドの呼び出し”using UnityEngine;using Tsukimi;
public abstract class ComponentsDoor : TsukimiBehaviour{ public abstract void Open();}
public class ComponentsCallAcross : TsukimiBehaviour{ public ComponentsDoor door;
void Start() { door.Open(); }}引数を渡す呼び出し
Section titled “引数を渡す呼び出し”引数を渡せます。渡せるのは単独の値と、その配列です。自分で作った struct は渡せません。
using UnityEngine;using Tsukimi;
public abstract class ComponentsCounter : TsukimiBehaviour{ public abstract void Add(int n);}
public class ComponentsCallAcrossArgument : TsukimiBehaviour{ public ComponentsCounter counter;
void Start() { counter.Add(5); }}using UnityEngine;using Tsukimi;
public struct R_components_pair{ public int a; public int b;}
public abstract class R_components_sink : TsukimiBehaviour{ public abstract void Take(R_components_pair p);}
public class R_components_cross_struct : TsukimiBehaviour{ public R_components_sink sink;
void Start() { R_components_pair p; p.a = 1; p.b = 2; sink.Take(p); }}戻り値のある呼び出し
Section titled “戻り値のある呼び出し”using UnityEngine;using Tsukimi;
public abstract class ComponentsScoreBoard : TsukimiBehaviour{ public abstract int Score();}
public class ComponentsCallAcrossReturn : TsukimiBehaviour{ public ComponentsScoreBoard board;
void Start() { Debug.Log(board.Score()); }}フィールドの読み出し
Section titled “フィールドの読み出し”using UnityEngine;using Tsukimi;
public abstract class ComponentsTank : TsukimiBehaviour{ public int level;}
public class ComponentsFieldAcrossRead : TsukimiBehaviour{ public ComponentsTank tank;
void Start() { Debug.Log(tank.level); }}フィールドへの書き込み
Section titled “フィールドへの書き込み”using UnityEngine;using Tsukimi;
public abstract class ComponentsDial : TsukimiBehaviour{ public int position;}
public class ComponentsFieldAcrossWrite : TsukimiBehaviour{ public ComponentsDial dial;
void Start() { dial.position = 3; Debug.Log(dial.position); }}配列での参照
Section titled “配列での参照”同じ型の相手を配列で持てます。編集画面から差し込んで、1 つのループで回せます。
using UnityEngine;using Tsukimi;
public abstract class ComponentsLight : TsukimiBehaviour{ public abstract void TurnOn();}
public class ComponentsReferenceArray : TsukimiBehaviour{ public ComponentsLight[] lights;
void Start() { for (int i = 0; i < lights.Length; i++) { lights[i].TurnOn(); } }}インタフェースでの参照
Section titled “インタフェースでの参照”Behaviour に付けたインタフェースの型でも持てます(インタフェース)。
using UnityEngine;using Tsukimi;
public interface IComponentsSwitch{ void Toggle();}
public class ComponentsReferenceInterface : TsukimiBehaviour{ public IComponentsSwitch target;
void Start() { if (target != null) { target.Toggle(); } }}実行環境の型での参照
Section titled “実行環境の型での参照”UdonBehaviour の型で持つと、名前での呼び出しと、変数の名前での読み書きが使えます。
メソッドを直接呼ぶことはできません。
using UnityEngine;using Tsukimi;using VRC.Udon;
public class ComponentsReferenceUdonBehaviour : TsukimiBehaviour{ public UdonBehaviour other;
void Start() { other.SendCustomEvent("Ping"); other.SetProgramVariable("count", 3); Debug.Log((int)other.GetProgramVariable("count")); }}変数の名前での読み書き
Section titled “変数の名前での読み書き”相手の変数は名前でも読み書きできます。相手の型を持っていなくても使えます。
値の読み出し
Section titled “値の読み出し”戻り値は object なので、使う型へキャストします。キャストした型が中身と違うと、
書いたとおりの値になりません。
using UnityEngine;using Tsukimi;
public class ComponentsGetProgramVariable : TsukimiBehaviour{ public TsukimiBehaviour other;
void Start() { int count = (int)other.GetProgramVariable("count"); Debug.Log(count); }}using UnityEngine;using Tsukimi;
public class R_components_progvar_no_cast : TsukimiBehaviour{ public TsukimiBehaviour other;
void Start() { int count = other.GetProgramVariable("count"); Debug.Log(count); }}値の書き込み
Section titled “値の書き込み”第 2 引数は object を取るので、どの型の値でも渡せます。
using UnityEngine;using Tsukimi;
public class ComponentsSetProgramVariable : TsukimiBehaviour{ public TsukimiBehaviour other;
void Start() { other.SetProgramVariable("count", 5); }}自分の変数の読み書き
Section titled “自分の変数の読み書き”自分に対しても使えます。名前を nameof で書けば、フィールドの名前を変えたときに一緒に変わります。
using UnityEngine;using Tsukimi;
public class ComponentsProgramVariableSelf : TsukimiBehaviour{ private int count = 3;
void Start() { SetProgramVariable(nameof(count), 9); Debug.Log((int)GetProgramVariable(nameof(count))); }}