はじめに
この記事や、この記事で紹介されているアセットは、UdonSharpがそれなりに触れる前提で作成されています。ご了承ください。
この記事では、基本的にインスタンスの指定ができないVRCPortalMarkerを使って、任意のタイミングで指定したインスタンスへのポータルを作成する方法を解説します。
VRCPortalMarkerについて
ワールドにポータルを置くときに使います。コンポーネントです。
SDKにVRCPortalMarker.prefabという名のサンプルがあります。
詳しくは公式ドキュメントや、Merlin氏が作成したMerlinVR/UdonSharpリポジトリのWikiをご覧ください。

こんな感じです。World IDと、なんかいろいろあります。
(「なんかいろいろ」で終わらせたのは、今回は全く触らない機能だからです。)
not World ID, but Room ID
インスペクターではWorld IDと表示されるので「ワールドIDなんだろうな」と思う方がほとんどだと思いますが、実はこれ、Room IDです。U#でもroomIdでアクセスできます。

これは実は大きな違いで、Room IDはWorld IDが持っているワールドの情報に加え、インスタンスの情報を含んでいます。こいつをUdonでいい感じに作成し、いい感じに突っ込むというのがこの記事の主題です。
RoomIDのフォーマット
ここで一度RoomIDについて説明しておきます。
RoomIDは、基本的に次のフォーマットになっています。
[World ID]:[インスタンス ID]~region([リージョンコード])
| ID/コード | 説明 | 例 |
|---|---|---|
| ワールドID | ワールドURLなどにあるwrd_[UUID]形式のID。 |
wrld_beddab1e-fee1-cafe-f00d-ca7c0dd1eca7 |
| インスタンスID | インスタンスのID。オーナー情報が入ることもある。 | 12345~hidden(usr_***) |
| リージョンコード | サーバー位置コード。 | ~region(jp) |
VRChatのウェブサイトのURLはこれを利用したものが多いです。例えば:vrchat.com/home/world/wrld_beddab1e-fee1-cafe-f00d-ca7c0dd1eca7
実装にあたっての落とし穴
上記のフォーマットに基づいてRoomIDを作成し、UdonでroomIdにセットすればいいように思われますが、実は、通常の方法では、ランタイムでセットした場合インスタンスIDは無視されます。しかし、初期値は(なぜか)そのまま反映されるので、Instantiateを使用します。1ここでは、Disableしておいたポータルを複製し、Udonで有効化する手法を取ります。
U#コード
[SerializeField] private GameObject portalMarkerPrefab;
private GameObject previousPortal;
private void GenerateNewPortal(string id)
{
if (Utilities.IsValid(previousPortal))
{
GameObject.Destroy(previousPortal);
}
GameObject newPortal = GameObject.Instantiate(portalMarkerPrefab, this.gameObject.transform);
previousPortal = newPortal;
VRCPortalMarker portal = newPortal.GetComponent<VRCPortalMarker>();
portal.roomId = id;
newPortal.SetActive(true);
portal.enabled = true;
portal.RefreshPortal();
}
Instantiateの仕様上、新しくGameObjectが生成される為、それを適当な変数に保持しておいて次回作成時にDestroyします。RefreshPortal()を呼んでいますが必要かどうかは分かりません誰か教えて。
完全なソースは下のリンクからダウンロードしてご覧ください。
バグ?仕様?
紹介した手法で作成したポータルに入ると、なぜかPublicに飛ばされることがあります。
これを解決するために、記事を書き、無料配布しておりますので、もし正常動作させることができましたら、どうか積極的な情報提供をお願いします。
X(旧Twitter):https://x.com/nomlasvrc
-
Udonでは
new GameObject()は禁止されています。 ↩