クラウド スクリプティング プログラマ ガイド
このガイドでは、Mesh Cloud Scripting API と開発者ツールを使用して環境を構築する方法について説明します (これらは Unity でプロジェクトとして開始され、その後 Mesh コレクションにアップロードされます)。 Mesh Cloud Scripting の概念と基本的なアーキテクチャを理解するには最初に azure の Set クラウド スクリプト インフラストラクチャを読み取うことをお勧めします。
このセクションでは、Mesh Cloud Scripting API の機能とインターフェイスについて説明します。これは、環境での動作を駆動するスクリプトを記述するために使用されます。
基本的な DOM 構造体
DOM 構造体は、Unity シーンの構造を反映します。 アプリケーションの "Scene" メンバーは、Mesh Cloud Scripting コンポーネントがアタッチされているゲーム オブジェクトに対応します。 次の Mesh Cloud Scripting API クラスは、エディターで作成された Unity オブジェクトと 1 対 1 でマップされます。
- GameObject (& Transform コンポーネント) -> TransformNode
- Light コンポーネント -> PointLightNode、SpotLightNode、DirectionalLightNode
- Animationor コンポーネント -> AnimationNode (および派生クラス、以下を参照)
- Box コライダー コンポーネント -> BoxGeometryNode
- Sphere コライダー コンポーネント -> SphereGeometryNode
- カプセル コライダー コンポーネント -> CapsuleGeometryNode
- Mesh コライダー コンポーネント -> MeshGeometryNode
- Text Mesh Pro コンポーネント -> TextNode
- Rigidbody コンポーネント -> RigidBodyNode
たとえば、Light コンポーネント (ポイント ライトに設定) と球コライダーがアタッチされたゲーム オブジェクトを使用してシーンを作成した場合、シーンには、PointLightNode と SphereGeometryNode の 2 つの子を持つ TransformNode が含まれます。
さらに、一部の Mesh Cloud Scripting API オブジェクトには、対応する Unity コンポーネントが組み込まれません。 これらは、Mesh ツールキット パッケージの一部である Unity で作成できる追加のコンポーネントです。
- Mesh Cloud Scripting コンポーネント (前述)
- WebSlate コンポーネント
Unity DOM をメッシュ DOM にマッピングする
Mesh Cloud Scripting API で認識されないコンポーネントを含むシーンを作成できます。 これらは、シーンの Mesh Cloud Scripting DOM には存在しません。 ただし、GameObjects の完全なシーン構造は、DOM API で TransformNodes としてミラー化されます。
Unity には GameObject/コンポーネント API シェイプがあります。ただし、Mesh Cloud Scripting DOM には単一のツリー構造があります。 Mesh Cloud Scripting API の TransformNode には、他の TransformNode またはコンポーネントにマップされる他のノードである可能性がある子があります。 これは、関連付けられたゲーム オブジェクトのコンポーネントとその変換コンポーネントの子のマージされたリストと考えることができます。
Rect Transform
RectTransform (Text Mesh Pro コンポーネントなど) を使用するコンポーネントを追加した場合、ゲーム オブジェクトは Mesh Cloud Scripting シーン グラフのノードとして表示されません。 このようなコンポーネントの移動、有効化、無効化は引き続き可能ですが、これを行うには、通常の Transform コンポーネントを使用して、RectTransform を使用して別のゲーム オブジェクトでゲーム オブジェクトをラップする必要があります。
プロパティ変更イベント
階層内の任意のノードで AddPropertyChangedEventHandler
を呼び出すことで、プロパティ変更イベントをサブスクライブできます。 プロパティの名前を文字列として渡す必要があります。
DomObjectPropertyChanged
イベントをサブスクライブすることで、すべてのイベントをサブスクライブすることもできます。 これは、DOM 内の任意のプロパティが変更されたときに呼び出されます。
オブジェクトのライフサイクル
ノードは、作成時に親を解除されます。 つまり、明示的に子としてシーンまたはその子孫の 1 人として追加されるまで、シーンに表示されません。 同様に、ノードの親を null に設定すると、ノードとその子孫がシーンから削除されます。
ノードを一時的に無効にしても、シーン内のどこにあったかの記録を保持しない場合があります。 このため、各ノードには "アクティブ" フラグがあります。 false に設定すると、ノードとその子孫が無効になります。
Unity では、シーンの一部であるが無効になっているゲーム オブジェクトとコンポーネントを作成できます。 これらは Mesh Cloud Scripting シーン階層のノードとして表示されますが、アクティブフラグは false に設定されます。 アクティブフラグを true に設定すると、Unity シーンで有効になります。
複製と親の再親
Mesh Cloud Scripting API では、ノードを複製して親を変更できます。対応する Unity シーンがそれに応じて更新されます。 ノードを複製すると、そのノードとそのすべての子が複製されます (対応する Unity オブジェクトに含まれている可能性がありますが、Mesh Cloud Scripting には表示されない子も含まれます)。
Unity コンポーネントに対応するノードを複製または再親することができます。 これは、Mesh Cloud Scripting Node の表現に基づいて、これらの Unity コンポーネントを再作成することによって実装されます。 Mesh Cloud Scripting API を使用して作成できるノードのみを複製または親し直すことができます。 Unity でコンポーネントを作成し、対応する Mesh Cloud Scripting Node に反映されないフィールドを設定した場合、ノード自体が複製されている場合、これらのフィールドは既定値にリセットされます。 このため、Unity で作成されたオブジェクトを操作する場合は、Transform ノードを複製または再親することをお勧めします。 これらは常にすべての元の Unity 設定を正しく保持します。
Users
API には、User プロパティを提供するさまざまな場所があります。 User.Identifier
プロパティは、ユーザーが離れ、再参加した場合でも、ユーザーに永続的な永続的な識別子文字列です。 ユーザーの表示名には、 User.DisplayName
を使用してアクセスすることもできます。 ユーザーが接続したイベント ID には、 User.ConnectedEventId
経由でアクセスできます。
開発中は、次に示すように、Mesh Cloud Scripting コンポーネント エディターの [開発者設定] でユーザーの表示名、識別子、およびイベント ID をモックすることができます。
アバター
アバターは、シーン内のユーザーの表現です。 ユーザーを特定の場所にテレポートしたり、シーン間を移動したり、トリガー ボリュームとの衝突を検出したりするために使用できます。
情報ダイアログ
Mesh Cloud Scripting では、カスタム メッセージを含む画面空間ダイアログを Microsoft Mesh アプリケーションにポップアップ表示できます。 SceneNode には、この ShowMessageToParticipants(string message, IReadOnlyCollection<Participant> participants)
の関数が含まれています。 リッチ テキスト タグ をメッセージで使用して、テキストのプロパティ (色、太字など) を制御できます。
入力ダイアログ
Mesh Cloud Scripting では、カスタム メッセージを含む Mesh イベントの出席者にテキスト入力を要求できます。 CloudApplication
はメソッド Task<string> ShowInputDialogToParticipantAsync(string message, Participant participant, CancellationToken token)
を提供します。 リッチ テキスト タグ をメッセージで使用して、テキストのプロパティ (色や太字など) を制御できます。
クラス
CloudApplication
ICloudApplication
インターフェイスは、Mesh アプリを開発するための開始点です。 _app変数として "App.cs" で使用できます。 シーンに加えて、 ICloudApplication
には使用可能なすべての種類の関数が作成されます。 他にもさまざまな方法がありますが、内部で使用します。
InteractableNode
MeshInteractableSetup は、Mesh ツールキット パッケージの一部であるカスタム Unity コンポーネントです。 Unity でゲーム オブジェクトにアタッチすると、ユーザーがそのゲーム オブジェクトまたはその子のアクティブな衝突可能オブジェクトをクリックすると、クリック イベントが発生します。
次に、MeshInteractableSetup コンポーネントをボックス コライダーと同じゲーム オブジェクトに追加する簡単な例を示します。
WebSlateNode
WebSlate は、Mesh ツールキット パッケージの一部であるカスタム Unity コンポーネントです。 WebSlate プレハブをシーンに追加するには、メニュー バーから GameObject>Mesh Toolkit>WebSlate を選択します。 WebSlate インスタンスの URL プロパティに割り当てられている Web サイトは、このプレハブのクワッドにレンダリングされます。
WebSlate プレハブがシーンに追加され、URL が割り当てられている例を次に示します。
var webSlateNode = Root.FindFirstChild<WebSlateNode>(true);
webSlateNode.Url = new System.Uri("https://en.wikipedia.org/wiki/Color");
クリックのリッスン
クリックするたびにキューブを回転させる単純な Mesh Cloud Scripting スクリプトを次に示します。 App.cs
内のスタブ StartAsync
メソッドをこのコードに置き換えます。
private float _angle = 0;
public Task StartAsync(CancellationToken token)
{
// First we find the TransformNode that corresponds to our Cube gameobject
var transform = _app.Scene.FindFirstChild<TransformNode>();
// Then we find the InteractableNode child of that TransformNode
var sensor = transform.FindFirstChild<InteractableNode>();
// Handle a button click
sensor.Selected += (_, _) =>
{
// Update the angle on each click
_angle += MathF.PI / 8;
transform.Rotation = new Rotation { X = 1, Y = 0, Z = 0, Angle = _angle };
};
return Task.CompletedTask;
}
ヒット情報
プロパティ変更イベントの引数を見て、どのユーザーがコライダーをクリックしたかを調べることが可能です。 また、イベント引数から、クリックの連絡先の法線と位置を読み取ることもできます。 これらの座標は、InteractableNode のローカル座標空間を基準とします。
アニメーター
Unity アニメーターを作成してシーンに追加し、Mesh Cloud Scripting を使用してそれを制御できます。 Mesh ツールキット プラグインは Unity プロジェクトのアセットを調べるので、見つかった各アニメーターに対して、Mesh Cloud Scripting プロジェクトの "AnimationScripts" フォルダーにクラスが生成されます。 このクラスは AnimationNode から派生し、Mesh Cloud Scripting からアニメーターを制御するために使用できます。 Unity のゲーム オブジェクトにコンポーネントとしてアニメーターを追加すると、生成されたクラスの対応するインスタンスが、対応する TransformNode の子として見つかります。 このクラスの API を使用して、アニメーターを制御できます。
Mesh Cloud Scripting プログラミング モデルはサーバー権限を持ち、アニメーター機能のごく一部のみをサポートしています。 これは、サーバー上でアニメーターをモデル化し、すべてのクライアントがサーバー モデルと正確に同期することを想定しているためです。 このため、現在サポートされている API は次のとおりです。
- 状態の設定 (各レイヤーのクラスには、アニメーターで使用可能な状態に基づいて列挙型に設定できる対応するプロパティがあります)。 状態は遷移ではなく、すぐに設定されます。
- Float 変数の設定: Float 変数のみが公開され、アニメーターの "Motion Time" にバインドする目的でのみ公開されます。
- レイヤー速度の設定
状態内では、Unity シーンで設定できる値に制限なくアニメーション クリップを作成できます。 ループ アニメーション クリップもサポートされています。 AnimationNodes では、アニメーターの次の機能はサポートされていません。
- 切り替え: アニメーターに切り替えを追加した場合、Mesh Cloud Scripting API を使用してこれらをトリガーすることはできません (サーバーは遷移をモデル化しません)。
- 変数 (モーション時間を駆動する float 以外)。 遷移ロジックまたは速度乗数を駆動するために使用される変数はサポートされていません。
- ミラー化された状態、サイクル オフセット、およびフット IK。
遅延結合とアニメーター
クライアントが Mesh イベントに参加すると、実行中のすべてのアニメーション ノードの現在の状態とローカル時刻に同期されます。 実行時間の長いアニメーションが状態で再生されている場合、再生時間は遅延結合時のアニメーションの正しい現在の時刻に設定されます。 ただし、状態でイベントが発生した場合、遅延参加済みクライアントでは発生しません。 その他のシナリオによっては、想定どおりに動作しない場合があります。たとえば、状態の開始時に AudioSource を有効にしてサウンドをトリガーした場合、その AudioSource は遅延参加クライアントでは引き続き有効になりますが、オーディオ クリップの先頭で再生が開始されます。
アニメーターの初期状態
何もしない既定の状態を持つアニメーターを作成することをお勧めします。 Unity でシーンの再生が開始されると、すべてのアニメーターがアクティブになり、既定のアニメーションの再生が開始されます。 これは、Mesh Cloud Scripting Service 接続が発生する前に発生する可能性があります。したがって、これらの状態を同期する方法はなく、動作が望ましくない可能性があります。
アニメーターの親の再親と複製
AnimationNode は、Mesh Cloud Scripting API を使用して作成することはできません。 AnimationNode を作成する唯一の方法は、アニメーター コンポーネントを含む Unity シーンをエクスポートすることです。 AnimationNode を複製または再親しようとすると、このアクションをサポートする方法がないため、エラーが発生します。 AnimationNode の 親 を複製または再親することはできます。これは、複製および親にすることができる含まれる Unity ゲーム オブジェクトに対応するためです。
生成されたコードに関する注意事項
生成されたコードは、アニメーター、レイヤー、状態、変数の名前からスペースを削除します。たとえば、変数名 "my var" はコードの "myVar" になります。 このため、有効なコードを生成しないアニメーターを作成できます。 たとえば、"my var" と "myVar" という名前の 2 つの変数がある場合、生成中にエラーが発生し、変数の名前を変更するように求めるメッセージが表示されます。
LightNode
PointLightNode、DirectionalLightNode、および SpotLightNode はすべて Unity Light コンポーネントにマップされます (このコンポーネントの型は対応する値に設定されます)。 LightNode API を使用して、これらのライトの基本的なパラメーターを設定できます。 また、API を使用して手動で Lights を作成することもできます。 API を使用してライト ノードを作成すると、Mesh Cloud Scripting API で設定できないパラメーターは既定値のままにされます。
GeometryNode
BoxGeometryNode、SphereGeometryNode、CapsuleGeometryNode、MeshGeometryNode は、それぞれ Unity の Box コライダー コンポーネント、Sphere コライダー コンポーネント、カプセル コライダー コンポーネント、メッシュ コライダー コンポーネントにマップされます。 また、Mesh Cloud Scripting API を使用して作成することもできます。 MeshInteractableSetup がゲーム オブジェクトまたはその親のいずれかにアタッチされている場合、Geometry ノードを有効または無効にすると、ヒット候補に追加および削除されます。
API を使用してジオメトリ ノードを作成すると、Mesh API で設定できないパラメーターは既定値のままにされます (たとえば、Physics Material は none に設定され、isTrigger は false に設定されます)。
RigidBodyNode
オブジェクトに Rigidbody コンポーネントを追加すると、そのモーションは Mesh Physics のコントロールの下に配置されます。 コードを追加しないと、Rigidbody オブジェクトは重力によって下方向にプルされ、他のオブジェクトとの衝突に反応します。
注: GeometryNode.Friction
は staticFriction
を返します。 ただし、Mesh Cloud Scripting 側で設定すると、クライアントの staticFriction
と dynamicFriction
の両方が更新されます。
ボリュームをトリガーする
ジオメトリ ノードは、 IsTrigger
プロパティが true に設定されている場合に、トリガー ボリュームとして機能できます。 このフラグは Unity のコライダーの IsTrigger
プロパティに対応しており、実行時に変更することはできません。 ジオメトリがトリガーである場合は、 Entered
が生成され、アバターと重複して開始/停止するすべてのアバターに対して Exited
されます。
注: Default
レイヤーのコライダーはテレポート ビームをブロックするため、テレポート ビームが無視できるようにするには、Unity オブジェクトを TriggerVolume
レイヤーに追加する必要があります。
TextNode
TextNode は Unity の TextMeshPro コンポーネントにマップされます。 TextMeshPro コンポーネントをシーンに追加すると、Mesh Cloud Scripting シーン階層に対応する TextNode が存在します。 これにより、実行時にコンポーネントのテキストを設定できます。 TextNode API (太字、斜体、下線、取り消し線、色) を使用して、基本的なテキスト プロパティを変更することもできます。 現時点では、API を使用して TextNode を作成することはできません。Unity のシーンに追加して作成する必要があります。 また、TextNode を直接複製することはできません。代わりに TextNode の親 TranformNode を複製する必要があります。
メッシュ
メッシュは現在、Mesh Cloud Scripting API の "非表示" コンポーネントです。 これらは Unity エディターで作成でき、親ゲーム オブジェクト/変換コンポーネントを操作して操作できますが、プログラムで作成することも、Mesh API を使用して実行時にプロパティを編集することもできません。
ビジュアル スクリプト
Unity スクリプト マシンを作成してシーンに追加し、Mesh Cloud Scripting を使用してそれを制御できます。 Mesh ツールキット プラグインは Unity プロジェクト内のアセットを調べるので、見つかったスクリプト マシンごとに、Mesh Cloud Scripting プロジェクトの "VisualScripts" フォルダーにクラスが生成されます。 このクラスは VisualScriptNode から派生し、Mesh Cloud Scripting からスクリプト マシンに関連付けられている Unity 変数を操作するために使用できます。 スクリプト マシンをコンポーネントとして Unity の GameObject に追加すると、生成されたクラスの対応するインスタンスが、対応する TransformNode の子として見つかります。 このクラスの API を使用して、スクリプト マシンの変数を制御できます。
状態の同期
既定では、Mesh は、1 つのクライアント上のビジュアル スクリプトによって行われたシーン変更を、他のすべてのクライアントに自動的にレプリケートします。 Mesh Cloud Scripting がビジュアル スクリプトによって行われた変更を認識するには、次の前提条件を満たす必要があります。
- スクリプト マシン コンポーネントは、Mesh Cloud Scripting シーン ルートの子孫である GameObject 上にあります。
- Mesh Cloud Scripting コンポーネントの [Visual Scripting を有効にする] オプションが有効になっています。
上記のいずれかの条件が満たされていない場合、Mesh Visual Scripting ランタイムはシーンの変更をレプリケートし続けますが、Mesh Cloud Scripting はこれらの変更に対して気を付けなくなります。
初期状態
ビジュアル スクリプトは、起動時に共有状態を変更したり、依存したりしないことをお勧めします。 On Start イベントは、通常、Mesh Cloud Scripting Service 接続が発生する前に発生します。そのため、その時点で状態を同期する方法はなく、動作が望むものではありません。
遅延結合
クライアントが Mesh イベントに参加すると、すべての Visual Script ノードの現在の状態に同期されます。 他のクライアントで以前に発生した可能性がある State Changed イベントは、遅延参加済みクライアントでは発生。 その他のシナリオによっては、想定どおりに動作しない場合があります。たとえば、On State Changed イベントに応答して AudioSource を有効にしてサウンドをトリガーした場合、その AudioSource は遅延参加クライアントで引き続き有効になりますが、オーディオ クリップの先頭で再生が開始されます。
親の再親と複製
VisualScriptNode Mesh Cloud Scripting API を使用して作成することはできません。 VisualScriptNode を作成する唯一の方法は、スクリプト マシン コンポーネントを含む Unity シーンをエクスポートすることです。 VisualScriptNode を複製または再親しようとすると、このアクションをサポートする方法がないため、エラーが発生します。 VisualScriptNode の親を複製または親にすることも可能です。これは、複製および親にできる含まれる Unity GameObject に対応するためです。
生成されたコードに関する注意事項
生成されたコードは、スクリプト マシンと変数の名前からスペースを削除します。たとえば、変数名 "my var" はコードの "MyVar" になります。 このため、有効なコードを生成しないスクリプト マシンを作成できます。 たとえば、"my var" と "myVar" という名前の 2 つの変数がある場合、生成中にエラーが発生し、変数の名前を変更するように求めるメッセージが表示されます。
その他の Mesh クラウド スクリプトに関するトピック
Mesh Cloud Scripting Service へのリソースの追加
Mesh Cloud Scripting Service で使用するリソースを追加する必要がある場合は、埋め込みリソースとして C# プロジェクト ファイルに追加する必要があります。 これを行うには、Visual Studio のプロジェクト UI を使用するか、次の行を .csproj ファイルに直接追加します。
<EmbeddedResource Include="<my_resource_file>" CopyToOutputDirectory="PreserveNewest" />
これは scene.map のパッケージ化方法であり、参照用の .csproj ファイルで確認できます。
メッシュ物理の操作
Mesh Physics
は、クライアント間で剛体の動きを同期するように注意を払います。 Mesh Cloud Scripting TransformNode.Position
、 TransformNode.Rotation
、 RigidBody.Velocity
、 RigidBody.AngularVelocity
は、最新のシミュレーション状態では更新されません。 ただし、Mesh Cloud Scripting Service で変更が設定されている場合、クライアントは変更を適用します。 1 つのプロパティを変更すると、他のプロパティは変更されません。 たとえば、位置のみが設定されている場合、速度は変更されません。剛性ボディは新しい位置から古い速度で動き続けます。 Mesh Cloud Scripting Service が、リジット ボディの最新のモーション状態で更新されない場合は、これらを新しい剛体にのみ設定することをお勧めします。
RigidBodyNode
を含むTransformNode
が複製されると、複製された本文が登録され、クライアント間の同期のためにMesh Physics
に引き渡されます。 注: 複製された剛体は、元の剛体のシーンの先頭からの位置、回転、速度を持ちます。 これらが異なる必要がある場合は、メッシュ クラウド スクリプトで明示的に設定する必要があります。