ワールドの実行中に部品に何かをさせるときは、部品に T# スクリプト(.mochi.xml の隣に置く同じ名前の .cs・TsukimiSharp で書く)を付けます。部品を置いた所ごとに、そのスクリプトを実行する UdonBehaviour が 1 つ付きます。
| |
|---|
| C# のファイル | 部品の <Name>.mochi.xml と同じフォルダの <Name>.cs です。このファイルがあるだけで、部品は T# スクリプトを持つ部品になります |
| クラス | <Name> という名前のクラスを、ファイルの最上位か名前空間の直下に書き、TsukimiBehaviour を継承します。基底クラスは <Name>.cs の宣言に直接書きます(自作のクラスを挟んだ継承は MOCHI3015 です) |
partial | MoCHI が <Name>.Mochi.cs を生成する部品(props か実行時の束縛がある部品)では必要です |
| プログラムアセット | T# のプログラムアセット <Name>.asset を同じフォルダに置きます。Assets > Create > T# Script で .cs と一緒に作れます(作られたクラスに partial を足します) |
| UdonBehaviour | 部品を置いた所ごとに 1 つ付き、そのプログラムを実行します |
| 同じ名前の既存のスクリプト | 部品のための .cs でなければ、どちらかの名前を変えます |
| T# の無い環境 | MOCHI8001 になります |
次の部品 Frame は、隣に Frame.cs を置くと T# スクリプトを持つ部品になります。例の確認は .cs を置かずに行うので、確認しているのは .mochi.xml の書き方だけです。
<Frame name="First" index="0" position="0 1.5 0"/>
<Frame name="Second" index="1" position="1 1.5 0"/>
<!-- file: Assets/Gallery/Frame.mochi.xml -->
<Prop name="index" type="int"/>
<Prop name="lit" type="bool" runtime="true" default="false"/>
<Object name="Rim" active="{lit}"/>
部品の C# のファイルです(例の確認の対象外)。
public partial class Frame : TsukimiBehaviour
public void Select(int selected) { SetProps(selected == index); }
MoCHI が上の 2 つのファイルから生成する中身です(例の確認の対象外・末尾の指紋は省略)。
// This file was generated by MoCHI from Frame.mochi.xml. Do not edit it:
// edit Frame.mochi.xml or Frame.cs instead. If this file is changed by hand, generation stops until it is regenerated.
public partial class Frame
// Props declared in Frame.mochi.xml
[global::UnityEngine.SerializeField] private int index;
[global::UnityEngine.SerializeField, global::Tsukimi.Reactive] private bool lit;
// Runtime props arrive here, all at once
public void SetProps(bool lit)
// Runtime props sent by name from a part with a T# script that uses this one, one prop at a time
[global::UnityEngine.SerializeField, global::UnityEngine.HideInInspector] private bool mochiInLit;
public void MochiReceiveLit()
[global::UnityEngine.SerializeField, global::UnityEngine.HideInInspector] private global::UnityEngine.GameObject mochiRimActive;
[global::Tsukimi.Effect] private void MochiRimActive()
mochiRimActive.SetActive(lit);
| メンバー | 内容 |
|---|
| props ごとのフィールド | private で [SerializeField] が付きます。runtime="true" の props には [Reactive] も付きます |
SetProps(…) | runtime="true" の props があるときだけ生成します。全部の実行時の props を、宣言の順に受け取ります |
mochiIn<名前> と MochiReceive<名前>() | runtime="true" の props ごとに生成します。使う側の T# スクリプトを持つ部品が実行時の値を名前で渡すための受け皿のフィールドと、受け皿の値をその props だけに書くメソッドです(ほかの props は変えません) |
mochi<名前>Active と Mochi<名前>Active | 実行時の active の束縛ごとに、対象の GameObject を持つフィールドと、SetActive を呼ぶ [Effect] のメソッドを生成します。<名前> は対象の要素の name(束縛でない場合)か、要素の名前から作ります |
mochi<名前> と Mochi<名前> | 実行時の値を書いたコンポーネントの属性ごとに、対象のコンポーネントを持つフィールドと、そのプロパティに書く [Effect] のメソッドを生成します。<名前> は対象の GameObject の名前・コンポーネントの型・属性の名前から作ります |
mochi<子><props> と Mochi<子><props> | T# スクリプトを持つ子の部品の実行時の props に実行時の値を渡す属性ごとに、子の UdonBehaviour を持つフィールドと、子の受け皿へ書いてその props の MochiReceive<名前>() を呼ぶ [Effect] のメソッドを生成します。<子> は子の要素の name(束縛でない場合)か、要素の名前から作ります |
<For>・<If>・<Else> の中の束縛 | 書き先のフィールドが配列になり、[Effect] のメソッドは配列の要素へ順に書きます。置いた所ごとに、そこで作られた物が並びます(取らなかった枝なら焼きません) |
mochi<名前>Arg<番号> | 関数を呼ぶ束縛ごとに、引数を持つフィールドです(<For> などの中では配列)。置いた所ごとに、使った所の値を設定します。[Effect] のメソッドには、関数が読むメンバーを [Effect(nameof(…))] で書きます |
| 先頭の注記と末尾の指紋 | 手で変更されたかを、末尾の指紋で判定します |
| 名前空間 | クラスが名前空間の中にあれば、同じ名前空間に生成します |
| 生成しない部品 | props も実行時の束縛も無い部品です。このときクラスに partial は不要です |
| 配置先 | .cs と同じフォルダです |
| |
|---|
runtime の無い props | 使った所に書いた値を、置いた所ごとの UdonBehaviour に設定します |
runtime="true" の props | 使った所の値が最初の値です。実行中は SetProps(…) で変更し、フィールドへ直接は代入しません |
T# スクリプトを持たない部品の runtime="true" | 書けます。受け取った値は、ほかの props と同じく prefab に書かれます |
| クラスからの props への書き込み | 部品のクラスが自分の props のフィールドへ書き込むと、MOCHI6001 のエラーです。見るのは T# が一緒にコンパイルする同じ partial クラスのファイルで、.Tests.cs は除きます。実行時の props は SetProps(…) で変更するか、自分で宣言した [Reactive] のフィールドに値を持ちます。runtime の無い props は生成時に決まり、書き込んでも生成した prefab は変わらないので、変える値は自分で宣言したフィールドに持ちます |
| 書き込みとして数える書き方 | 代入・複合代入・++・--・ref と out の引数です(this. を付けた書き方も含みます)。bool・int・float・Vector3・Color の props では、pos.x = … のようなフィールドの中への書き込みも数えます。同じ名前の引数やローカル変数への書き込み・ほかのインスタンスのフィールド(other.index = …)・SetProgramVariable は数えません |
MOCHI6001 のときの生成 | <Name>.Mochi.cs は書き、prefab は前の出力のまま残します。エラーは 1 つの部品につき 10 件まで出ます |
実行時に変わる値は、T# スクリプトを持つ部品の本体の中で実行時の props か C# のメンバーを束縛したときに生まれ、書く場所ごとに次の 26 通りに扱われます。実行時に変わる値を書けるのは active・コンポーネントの属性・実行時の props だけです。
| 書く場所 | 扱い | 番号 |
|---|
active | bool の実行時の props か、[Reactive] のフィールドか、[Computed] のプロパティを束縛できます。部品の Start と値の変化のたびに GameObject の active が切り替わります | |
active の prefab に保存する値 | 起動時の値が生成時に分かる物は、その値で保存します(ワールドの読み込み時と、Play でないエディターでもその状態です)。分かるのは、実行時の props(置いた所に書いた値か default)と、bool の [Reactive] のフィールド(宣言の初期値・書かなければ false)です。フィールドでも、クラスが起動中(Start・OnEnable・[Effect] と、そこから使うメソッドとプロパティ)に書く物・[UdonSynced] の物・ほかのスクリプトが書く物は除きます。inactive で保存した GameObject とその下の UdonBehaviour は、最初に表示されるまで OnEnable も Start も実行しません。下の T# スクリプトの部品は、表示される前でも親が起動時に渡した props を受け取ります | |
| active で保存する物 | [Computed] のプロパティか関数に従う物・親が実行時に渡す props に従う物は、起動時の値によらず active で保存します。部品の Start までは表示され、読み込み時にはコンポーネントの OnEnable が実行され、playOnAwake の AudioSource は鳴り始めます。隠した状態で保存するには、実行時の props か [Reactive] のフィールドを直接束縛します | |
bool でない値の active | エラーです | MOCHI3006 |
{!名前} | bool の値の反対を束縛します | |
bool でない値の {!名前} | エラーです | MOCHI3006 |
| コンポーネントの属性 | active と同じ物を束縛できます。属性の名前の C# のプロパティに、起動時と値が変わるたびに書きます。部品と一緒に足すコンポーネント・<Prefab>・<At> の中・add="true" のどれでも書けます | |
| Udon から書けないプロパティ・型の合わない値 | 生成物と一緒のコンパイルのエラーで、場所は .mochi.xml の属性です | MOCHI3016 |
T# が変化を追えないメンバーの active | エラーです([Reactive] のフィールドでも [Computed] のプロパティでも実行時の props でもない物) | MOCHI5005 |
| props でも行でもない名前 | 部品の C# のメンバーとして読みます。クラスに無い名前は、生成物と一緒のコンパイルでエラーになります | MOCHI3016 |
<If> の test | エラーです。表示の切り替えは active に書きます | MOCHI5003 |
名前・key・位置・回転・拡大・static・size・pivot・<Prefab src>・実行時でない props | 生成時に決まる値なので、エラーです | MOCHI5004 |
配列・UnityEvent・物の参照の属性と、material・mainTexture・color | まだ対応していません | MOCHI9001 |
<For>・<If>・<Else> の中 | 書けます。生成物はデータに依りません: 無い行や取らない枝の中の束縛も数えるので、部品を使うどのエントリポイントも同じ生成物を書きます | |
overflow="repeat" の <Prefab> とその中 | まだ対応していません | MOCHI9001 |
関数を呼ぶ束縛 {Name(…)} | 部品の C# のメソッドを、生成時に決まる引数で呼んだ値です。<For> の行ごとに別の値を持たせるときに使います(active="{IsCurrent(art.index)}")。部品の .mochi.xml の中だけで書けます | |
| 関数の引数 | 数・true/false・'文字'・props・行の列です。メソッドの引数の型は bool・int・float・string・Vector3・Color です。引数は順に書きます。後ろの既定値つきの引数は省けます(C# の既定値で呼ばれ、MoCHI は既定値を読みません)。省いた引数の型は問いません | |
| 実行時に変わる値の引数 | エラーです。計算は [Computed] のプロパティに書きます | MOCHI5004 |
| 呼び出しや式の引数・数の合わない引数・名前つきの引数・部品の外の関数の束縛 | エラーです | MOCHI5002 |
| 引数の型に変換できない値 | エラーです | MOCHI3006 |
| 関数の値が変わる時 | MoCHI はメソッドと、そこから使う同じクラスのメソッドとプロパティ(T# が一緒にコンパイルする同じ partial クラスのファイルの中。同じフォルダとその下か Assets/ の下の TsukimiShared にある、同じ名前空間のファイルで、.Tests.cs は除きます)とローカル関数を読み、読んでいる [Reactive] のフィールド・[Computed] のプロパティ・実行時の props のどれかが変わるたびに設定し直します。同じ名前の引数やローカル変数は、フィールドを隠します。どれも読まないメソッドは、起動時に 1 回だけ呼ばれます | |
| ほかのインスタンスやクラスのメンバーを読む関数 | 追うのは部品の自分のインスタンスのメンバーだけです。ほかのインスタンス(next.lit・next?.label)やほかのクラス(bell.ringing)の [Reactive] のフィールド・[Computed] のプロパティ・実行時の props は、変わっても設定し直さないので警告です(生成物と prefab は作ります)。ほかのインスタンスのメソッドの呼び出し(next.IsLit())の中は見ません。実行中に変わる値は、自分のインスタンスの [Reactive] のフィールドに写して読みます | MOCHI5006 |
| 読めない関数 | それらのファイルに無い・同じ名前が 2 つ以上・値を返さない・読むメンバーを変える(プロパティの set や構造体のフィールドを通す物も含む)・それらのファイルに無いメソッド(基底クラスのメソッドなど)を呼ぶ・params・in・ref・out の引数(省く場合も含む)、はエラーです | MOCHI3015 |
T# スクリプトを持つ子の部品の runtime="true" の props | 渡せます。起動時と値が変わるたびに、子のその props が設定され、子の束縛が従います。設定するのは渡した props だけで、子のほかの実行時の props(子が自分の SetProps(…) で変えた値を含みます)はそのままです。渡した props は、子が途中で変えていても、親の値が変わるたびに親の値に戻ります。子の .cs は、どのフォルダにあってもかまいません | |
| 子の props の型に変換できない値 | 生成物と一緒のコンパイルのエラーで、場所は .mochi.xml の属性です(int から float へのような暗黙の変換は通ります) | MOCHI3016 |
T# スクリプトを持たない部品の runtime="true" の props | 渡せます | |
| 対象 | 規則 | 番号 |
|---|
| props の名前 | C# の識別子(ASCII の英字・数字・_ で、数字で始まらない)で、C# のキーワードでなく、__ と mochi(大文字と小文字を問わない)で始まらない名前です。mochi で始まる名前は、MoCHI が生成するコードが使います | MOCHI3014 |
| 使えない props の名前 | クラスの名前・SetProps・_・nameof です | MOCHI3015 |
| 生成するメンバーと同じ名前 | クラスに書けません。生成するメンバーは、props の名前・SetProps・mochi か Mochi で始まる名前です | MOCHI3015 |
| クラスの宣言 | <Name> のクラスが無い・partial が無い・TsukimiBehaviour を直接継承しない場合はエラーです | MOCHI3015 |
| 段 | 内容 |
|---|
| 1. 保存 | <Name>.Mochi.cs を先に書きます。スクリプトは生成物のメンバーを使うので、生成物より前にはコンパイルできません |
| 2. コンパイルの後 | T# が Behaviour を生成物と一緒にコンパイルした後で、prefab を生成し、置いた所ごとの UdonBehaviour に値を設定します。同期の方式は、スクリプトが [UdonBehaviourSyncMode] で宣言した方式です。同じ GameObject に付けた <UdonBehaviour> のプログラムが None 以外の違う方式を宣言していると MOCHI1012 です |
| |
|---|
| 待っている間 | エントリポイントはコンパイル待ちで、ワールドのアップロードは停止します。生成物の Inspector には Waiting for T# to compile the T# scripts of its parts. と出ます |
| コンパイルできないスクリプト | MOCHI3016 です。生成物は書かれたままで、prefab は更新されません。示された場所を直します。生成物の中の、実行時の active の束縛から作った行で失敗したときは、場所は .mochi.xml のその束縛です |
プログラムアセットが無い・別の .cs 用 | MOCHI2013 です |
inspect の compiles | T# が最新のソースでコンパイルしたかを inspect は判定できないので、Unity が待っている間も true になることがあります。判定は Unity が行います |
| |
|---|
<Name>.Mochi.cs の変更 | しません。末尾の指紋が合わないと、その部品を使う全部のエントリポイントの生成が、生成し直すまで一時停止します |
| 削除 | MoCHI は <Name>.Mochi.cs を削除しません。props も実行時の束縛も無くなった部品の隣に残っていると、MOCHI2014 の警告が出ます |
| |
|---|
| 書き方 | <Object> の中に <UdonBehaviour programSource="…/Judge.asset" speed="2.5" label="/Board/Text"/> と書きます。.cs とプログラムのアセットは、ほかの場所に在るままで使えます |
programSource | T# のプログラムのアセット(.asset)へのパスです。コンパイル済みである必要があります(そうでなければ MOCHI2013)。ほかのコンパイラーのプログラムのアセットは、まだ付けられません(MOCHI9001) |
| ほかの属性 | プログラムの公開変数です。プログラムに無い名前は MOCHI1005 で、変数の一覧が出ます |
| 値の書き方 | 変数の型で決まります。bool・int・float・string・Vector3・Color は props と同じ、アセットの型はアセットへのパス、GameObject・Transform・コンポーネント・UdonBehaviour は同じ prefab の中の物へのパスです(TextAsset も .txt・.bytes などへのパスで書けます)。これらの型の配列は要素を ; で区切ります(空の値は大きさ 0)。コンポーネントの配列の属性と違い、string の配列は空の要素も残します(words="apple; banana;" は 3 つ目が "" の 3 要素です)。パスは、書いたファイル(props として渡されたパスは渡したファイル、表から来たパスは表)から解決します。Vector2・Quaternion などの型は MOCHI9001 です |
| T# が作った値 | GPU のカーネルのマテリアルとモデルの重みのテクスチャ(T# がプログラムのために作った物)を代入する変数は、MoCHI が埋めます。書かないでください(書いた属性があれば、そちらを使います) |
| 値を当てる時 | 部品の props と同じく、prefab を生成した後に Unity の中で当てます |
| 同期の方式 | プログラムが [UdonBehaviourSyncMode] で宣言した方式です。VRChat は 1 つの GameObject の同期する UdonBehaviour に同じ方式を持たせるので、None 以外の違う方式(Continuous と Manual)を宣言したプログラムを同じ GameObject に付けると MOCHI1012 です(別の GameObject に付けます)。None を宣言したプログラムと、宣言しないプログラムは数えません |
| 呼び方 | onClick="/Judge:Run" で呼べます |
| 数 | 1 つの物に 2 つ以上付けられます。それぞれに違う key(単純な名前)を付けます。key の無い物は 1 つまでです。同じ key が 2 つ・key の無い物が 2 つは MOCHI4001 です。key はその物のほかのコンポーネントの key とも重ねられません(同一性と key)。key と programSource は公開変数になりません |
| T# スクリプトを持つ部品のルート | ルート要素の直下に書くときは key が必要です。その物の key の無い UdonBehaviour は、部品のスクリプトの物です(MOCHI4001) |
#key | パスの最後に #key を付けて、その物の UdonBehaviour の 1 つを指します(onClick="/Judge#sound:Play"・ear="/Judge#sound")。# の無いパスは、その物のただ 1 つの UdonBehaviour を指し、2 つ以上あれば MOCHI1009 です。無い key は MOCHI2016 です |
置いた <Prefab> の中の物 | prefab の中の GameObject には key が無いので、UdonBehaviour が 2 つ以上ある GameObject は指せません(MOCHI1009)。指す UdonBehaviour は、prefab の中で 1 つだけを持つ GameObject に置きます |
| fileID | key の無い物は、1 つだけ付けていたときと同じ fileID です。2 つ目を足しても、それへの参照は切れません |
| T# の無い環境 | MOCHI8001 です |