VRChatでTimelineが使えないからUdonSharpでゴリ押ししてみた

# VRChatでTimelineが使えないからUdonSharpでゴリ押ししてみた

最終的にこんなの作りました

<blockquote class="twitter-tweet"><p lang="ja" dir="ltr">VRChatでTimeline使えないから、U#で代替できないか実験中。GameObject毎に開始時間と終了時間を設定して、経過時間で表示/非表示を切り替えるスクリプトが書けました。 <a href="https://t.co/BTqekplHGL">pic.twitter.com/BTqekplHGL</a></p>&mdash; segur(せぎゅ)@VKet4阿頼屋敷-蓮-23 (@segur_vita) <a href="https://twitter.com/segur_vita/status/1256957066393968640?ref_src=twsrc%5Etfw">May 3, 2020</a></blockquote> <script async src="https://platform.twitter.com/widgets.js" charset="utf-8"></script>



# Unity2018からVRChatでTimelineが使えなくなった

Unity2017時代のVRChatではTimelineが使えました。

パーティクルライブのように、音楽に合わせてオブジェクトの表示/非表示を切り替えるようなワールドを作るときに、Timelineは非常に有効です。

ただ、VRChatがUnity2018に移行してから、このTimelineが使えなくなってしまいました。

<blockquote class="twitter-tweet"><p lang="ja" dir="ltr">TimelineについてVRChatのDiscordで質問したら、まだホワイトリスト化されてないって回答がきました。</p>&mdash; segur(せぎゅ)@VKet4阿頼屋敷-蓮-23 (@segur_vita) <a href="https://twitter.com/segur_vita/status/1256620569065185280?ref_src=twsrc%5Etfw">May 2, 2020</a></blockquote> <script async src="https://platform.twitter.com/widgets.js" charset="utf-8"></script>



# UdonSharpでゴリ押ししてみることにした

Timelineに相当する処理を自前で実装することにしました。

ちょうどUdonSharp(U#)を勉強中だったので、U#でやってみることにしました。

U#の開発環境構築については、こちらがわかりやすかったです。

[U# 入門 ①](https://hatuxes.hatenablog.jp/entry/2020/04/05/013310)




# Udonで実装してみた

完成したコードがこちらです。

```C#
using UdonSharp;
using UnityEngine;
using UnityEngine.UI;
using VRC.SDKBase;
using VRC.Udon;

public class PseudoTimeline : UdonSharpBehaviour
{
    //ボタンラベル
    public Text buttonLabel;

    //制御対象のゲームオブジェクトのリスト
    public GameObject[] cylinder;

    //表示開始時間のリスト
    public float[] startTime;

    //再生時間のリスト
    public float[] duration;

    //経過時間
    [UdonSynced(UdonSyncMode.None)]
    private float currentTime;

    //再生中フラグ
    [UdonSynced(UdonSyncMode.None)]
    private bool isPlaying;

    void Start()
    {
        //停止中にする
        isPlaying = false;
    }

    public override void Interact()
    {
        //ボタンに対するオーナーを変更
        if (!Networking.IsOwner(Networking.LocalPlayer, this.gameObject))
        {
            Networking.SetOwner(Networking.LocalPlayer, this.gameObject);
        }

        //経過時間を初期化
        currentTime = 0.0f;

        //停止中と再生中を反転
        isPlaying = !isPlaying;
    }

    private void Update()
    {
        if (isPlaying)
        {
            //ボタンラベルを切り替え
            buttonLabel.text = "■";

            //経過時間をカウントアップ
            currentTime += Time.deltaTime;

            for (int i = 0; i < cylinder.Length; i++)
            {
                //表示開始
                if (currentTime > startTime[i])
                {
                    cylinder[i].SetActive(true);
                }

                //表示終了
                if (currentTime > startTime[i] + duration[i])
                {
                    cylinder[i].SetActive(false);
                }
            }
        }
        else
        {
            //ボタンラベルを切り替え
            buttonLabel.text = "▶";

            //すべて非表示にする
            for (int i = 0; i < cylinder.Length; i++)
            {
                cylinder[i].SetActive(false);
            }
        }
    }
}
```

適当なCubeに、 `Udon Behaviour` をアタッチして、 `Source Script` に上記のコードを設定してください。


# Public Variablesを設定する
以下の図のようにPublic Variablesを設定します。
![image.png](https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/221845/464e9623-d811-4de1-9432-1dbf65c746f7.png)

`Button Label` には適当なTextを作成して割り当ててください。再生中なら `■` 、停止中なら `▶` になります。

`Cylinder` には、表示/非表示を切り替えたいGameObject達を設定します。私は円柱のオブジェクトを5つ用意して割り当てました。

`Start Time` は、各GameObjectの表示開始時間です。 `Cylinder` と同じ数だけ必要です。

`Duration` は、各GameObjectの再生時間です。 `Cylinder` と同じ数だけ必要です。表示終了時間は表示開始時間にこの再生時間を加算した時間になります。




# 結果

以下のような簡易パーティクルライブが作成できました。

<blockquote class="twitter-tweet"><p lang="ja" dir="ltr">VRChatでTimeline使えないから、U#で代替できないか実験中。GameObject毎に開始時間と終了時間を設定して、経過時間で表示/非表示を切り替えるスクリプトが書けました。 <a href="https://t.co/BTqekplHGL">pic.twitter.com/BTqekplHGL</a></p>&mdash; segur(せぎゅ)@VKet4阿頼屋敷-蓮-23 (@segur_vita) <a href="https://twitter.com/segur_vita/status/1256957066393968640?ref_src=twsrc%5Etfw">May 3, 2020</a></blockquote> <script async src="https://platform.twitter.com/widgets.js" charset="utf-8"></script>



# UdonSyncedについて

`isPlaying` と `currentTime` のアトリビュートに `[UdonSynced(UdonSyncMode.None)]` を付けてます。

これによって、複数のユーザーが同時にパーティクルライブを視聴できるようになります。



# さいごに
本記事作成にあたり、以下の記事を参考にしました。ありがとうございました。

- [U# 入門 ①](https://hatuxes.hatenablog.jp/entry/2020/04/05/013310)
- [U# 入門 ②](https://hatuxes.hatenablog.jp/entry/2020/04/05/013323)