Udon 视频同步播放器

概述
让人们一起观看视频需要同步两个主要内容——要观看的视频 URL 和播放时间,以便人们同时观看。为了理解如何为所有人(包括后来加入的人)同步这两个项目,让我们看一个使用此程序的场景。
某人输入 URL 的流程: 成为 UdonSyncPlayer 对象的所有者 ▸ 发送新 url ▸ 尝试加载和播放 URL ▸ 视频开始时发送同步信息 ▸ 每 syncFrequency 秒发送新的同步信息
其他人的流程: 接收新的 url 值 ▸ 尝试加载和播放 URL ▸ 接收同步信息 ▸ 跳转到同步时间
有人加载 URL
当假设的场景加载时,假设还没有视频播放,房间里有两个人。有人将新 URL 粘贴到输入字段中,触发 UI 中连接的 OnURLChanged 事件。
这里有一些 'IsValid' 调用,用于确保我们没有尝试在已销毁或设置不当的对象上调用方法。为简化说明,我们将在本示例的其余部分跳过描述这些。
本地玩家刚刚输入了新 URL,因此我们让他们成为程序的所有者,以便控制其变量。我们从 InputField 获取 URL,然后在 url 符号上调用 SetProgramVariable 使用此新值。这与启用 "sendChange" 的 set url 调用方式相同,只是另一种方式,如果您想在另一个 UdonBehaviour 上更改变量,了解这一点很有用。更新此变量后,我们调用 RequestSerialization 请求 Udon 为世界中的其他人更新 url 的值。
用户获取新 URL
由于我们在图表中为 url 设置了变量更改事件,只要 URL 更新就会触发此事件,然后尝试播放 URL。
视频开始

此事件在视频实际开始播放时在本地触发。我们为所有者和其他所有人调用相同的事件——不同的逻辑在 UpdateTimeAndOffset 中处理。
更新时间与偏移

首先,此逻辑检查是否在对象的所有者上运行。如果不是,则运行 Resync 事件。如果是在所有者上,则我们想同步我们在视频中的_位置_和我们在那里的_时间_。由于这是逻辑第一次运行,我们应该在视频的最开始,但通过保存这两个值,我们也可以将其用于未来的同步更新。
我们想向其他人同步两个数字,这两个数字密切相关,因此我们将它们组合成一个 Vector2 变量,以便保持在一起并简化一些同步逻辑。我们构造一个 Vector2,其中 'x' 是视频的当前时间,'y' 是所有者在该视频时间时观察到的服务器时间。有了这些信息,其他人可以将自己设置为匹配的时间——请参阅下面的重新同步。
在对此同步变量请求序列化后,所有者调用 SendCustomEventDelayedSeconds 再次更新此值。他们使用变量 syncFrequency 确定多久更新一次值。对于_非常_简单的方法,如果所有者从不暂停、回放或快进视频,此变量可以保持为 0,每个人都可以从视频的开始时间同步,而不是时不时更新 timeAndOffset。
重新同步

当非所有 者开始播放视频或收到 timeAndOffset 变量的更新时,他们可以使用数据来确定跳转到视频中的哪个位置。
举个简单的例子,假设所有者在服务器时间 1000 时在视频时间 0 处。
- 所有者将 timeAndOffset 设置为 (0,1000)。
- 您 45 秒后加入并获取此值。您自己的服务器时间是 1045,因此您通过计算服务器时间的差异(45 秒)并加上视频时间(0 秒)跳转到视频的 00:45。
改进与增强

我们保持此示例相当简单,以便易于理解和升级。您可以做很多改进并与他人分享您的更改!以下是一些想法:
- 让非所有者等待从所有者收到信息后再播放视频
- 检测流 URL 与视频并关闭同步
- 处理视频错误事件并为用户提供有用的提示
- 只允许特定玩家更改视频
- 创建视频播放列表
- 创建视频排队系统