Skip to main content

PlayerObject

PlayerObject 允许您自动为每个加入世界的玩家提供一个 GameObject 副本,例如手电筒、生命条或剑。

  • VRChat 在每个玩家加入世界时自动生成该 GameObject 的副本。
  • 副本包括所有组件和子 GameObject。
  • 副本以与原始PlayerObject 模板相同的位置、旋转、缩放和父级生成。

设置​

按照以下说明创建一个简单的 PlayerObject。当玩家加入实例时,VRChat 会为他们生成 PlayerObject。

  1. 在场景层级中创建 GameObject。
  2. 添加 VRCPlayerObject 组件。
    • 这将把你的 GameObject 变成 PlayerObject 模板。
  3. (可选)向 GameObject(或其子级之一)添加 UdonBehaviour 组件。
  4. (可选)如果你希望同步变量持久化,向与 UdonBehaviour 相同的 GameObject 添加 VRCEnablePersistence。

加载持久用户数据​

VRChat 自动加载满足以下条件的 PlayerObject 上的持久用户数据:

  • PlayerObject(或子 GameObject)具有 UdonBehaviour 组件。
  • UdonBehaviour 具有同步变量。
  • UdonBehaviour 的 GameObject 也具有 VRCEnablePersistence 组件。

使用 OnPlayerRestored 检测 PlayerObject 已完成加载用户数据。此事件为实例中的每个玩家执行一次,包括 PlayerObject 的拥有者。

OnPlayerRestored 包含对刚刚恢复数据的玩家的引用。你可以使用此引用来使 GameObject 的拥有者初始化变量或执行事件。

在 Start 和 OnDeserialization 事件中,所有权保证正确。但是,在 OnPlayerRestored 事件之前,应避免读取或写入 PlayerObject 的用户数据。你可能会意外读取或写入过时的用户数据,并且当从 VRChat 服务器接收到用户数据时,你的更改可能会被覆盖。

所有权​

当玩家拥有 PlayerObject 时,他们也拥有其 PlayerObject 内所有具有同步 UdonBehaviour 的 GameObject。他们不能将所有权转移给任何人。

这方便为玩家提供永远不会被其他玩家"偷走"的工具或拾取物。你可以保证他们始终拥有自己的 PlayerObject。

PlayerObject 模板​

PlayerObject 模板是通过在编辑器中添加 VRCPlayerObject 创建的原始 GameObject。VRChat 复制你的模板来生成 PlayerObject。

模板和 PlayerObject 上的组件可以包含对其他组件的引用:

  • 模板可以引用自己的组件或子组件。
  • 模板可以引用场景中的其他组件。
  • 场景中的组件不能引用模板。
    • 相反,场景对象必须使用直接引用已生成的 PlayerObject。
    • 模板由 VRChat 自动禁用,但仍存在于场景中。
    • 不要在模板被禁用后修改、销毁或编辑它!这可能导致错误或意外行为。

在你的脚本中使用以下方法查找 PlayerObjects 及其组件的引用:

  • 使用 Networking.GetPlayerObjects 获取与玩家关联的所有 PlayerObjects,然后遍历该数组并找到你正在寻找的特定内容。
  • 使用 Networking.FindComponentInPlayerObjects 将 PlayerObject 模板中的引用转换为特定玩家的 PlayerObject。
  • 参见下面的示例。

事件​

以下事件与 PlayerObjects 相关:

事件输出说明
OnPlayerRestoredVRCPlayerApi player在 VRChat 玩家的所有持久数据加载完成后触发。
OnPersistenceUsageUpdatedVRCPlayerApi player当 VRChat 玩家的持久化使用量更新时触发。
OnPlayerObjectStorageExceededVRCPlayerApi player当 VRChat 玩家的 Player Object 使用量超过允许存储限制时触发。
OnPlayerObjectStorageWarningVRCPlayerApi player当 VRChat 玩家的 Player Object 使用量接近允许存储限制时触发。

方法​

PlayerObject 方法位于 VRC.SDKBase.Networking 命名空间中。

函数输入输出说明
GetPlayerObjectsVRCPlayerApi targetGameObject[] objects返回与提供的玩家关联的所有 PlayerObjects 数组
FindComponentInPlayerObjectsVRCPlayerApi player, Component referenceComponentComponent使用 referenceComponent(必须是 PlayerObject 模板的子对象),此函数返回与提供的玩家对应的组件。
GetPlayerObjectStorageLimitint返回 Player Object 的存储限制,单位为字节。
GetPlayerObjectStorageUsageVRCPlayerApi targetint返回目标玩家上次计算的 Player Object 存储使用量。
RequestStorageUsageUpdatevoid请求计算本地玩家的 PlayerData 和 PlayerObject 存储使用量;结果通过 OnPersistenceUsageUpdated 到达

请注意,存储信息可能随时间推移而过时,可能需要更新。请避免频繁调用 RequestStorageUsageUpdate。

这些方法的实用包装器可以在 VRCPlayerApi 类上找到。

函数输入输出说明
GetPlayerObjectsGameObject[] objects返回与提供的玩家关联的所有 PlayerObjects 数组。

示例​

在 PlayerObject 上查找自定义脚本​

此示例自动遍历所有 PlayerObjects 并找到您正在寻找的特定组件。将 CustomPlayerObjectScript 替换为您要查找的组件类型。

public CustomPlayerObjectScript Find(VRCPlayerApi player)
{
var objects = Networking.GetPlayerObjects(player);
for (int i = 0; i < objects.Length; i++)
{
if (!Utilities.IsValid(objects[i])) continue;
CustomPlayerObjectScript foundScript = objects[i].GetComponentInChildren<CustomPlayerObjectScript>();
if (Utilities.IsValid(foundScript)) return foundScript;
}
return null;
}

在 PlayerObject 上查找组件​

此示例使用 FindComponentInPlayerObjects 函数将 PlayerObject 模板中的引用转换为特定玩家的 PlayerObject 中的引用。

public Transform referenceChildTransform; // 对 PlayerObject 或 PlayerObject 子对象上 Transform 的引用

public void Find(VRCPlayerApi targetPlayer)
{
Component foundComponent = Networking.FindComponentInPlayerObjects(targetPlayer, referenceChildTransform);
// foundComponent 将是 Transform 类型,对应于与引用匹配的 targetPlayer 的 PlayerObject。
}