【问题标题】:Unity NetworkTransform, force update every Frame?Unity NetworkTransform,强制更新每一帧?
【发布时间】:2019-04-16 13:40:29
【问题描述】:

在有目的的 LAN 设置中,我希望 Unity 的 NetworkTransform 简单地发送每一帧。 (模式是“同步变换”,不是刚体等)

我想知道如何做到这一点.. 如果您只是将发送速率设置为 0.00001,它实际上会在对象移动的每一帧中执行吗?

(Inspector 界面只允许最高 29Hz,如果您想要更小的值,只需在代码中设置即可。)

我也在考虑类似剧本的事情......

 void Update() { .. SetDirtyBit( ? ); }

这样可以吗?

(还有,你在那里使用什么作为位掩码?)

通过实验确定这类事情确实需要很长时间。显然 Unity 的 doco 是个笑话。而且我无法用谷歌搜索任何已经想到它的人。有这方面的经验吗?


其次...

更多信息。我们做了一些实验,实际上,如果您将其设置为一个非常小的值,它确实似乎会在每一帧同步NetworkTransform

(当然,如果它没有移动,它不会打扰发送,正如@Programmer 在下面指出的那样。)

H O W E V E R不会为运动物体或相机位置产生平滑的结果。我不知道为什么;它与更新循环以及更改发生的确切时间有关。但是你得到的是“非常精细的抖动”。


第三...

我做了一个实验,只使用命令和 Rpcs,每帧发送一些信息(实际上是从一个客户端到另一个客户端)。

我专门使用了一个单独的以太网网络,应用程序除了每帧发送信息(即“手动”仅使用 Command/Rpc)(即在 Update() 上)之外几乎什么都不做。

事实上,它仍然丢了很多帧,通常没有发送出去。 (假设它在 10 秒内错过了 10 或 20 个。)

祝你好运!

如果您需要“每帧”发送一些信息,例如在 LAN 系统上,请不要这样做。

【问题讨论】:

  • Afaik NetworkTransform 如果使用 RigidBody 也会尝试在一定限度内预测运动。也许这会导致抖动?对我来说,NetworkTransform 从来没有很好地工作,我最终编写了一个带有命令、Rpcs 和位置插值的自定义。 forum.unity.com/threads/network-transform-lags.334718
  • (对,我没有使用 RigidBody。是的,他们的系统很垃圾;这更像是一个好奇心调查 :))
  • 是的,这就是为什么they start over
  • 啊我不知道that@derHugo。我是第一次听你说的! Geesh ... Unity 在网络方面的又一次尝试:/
  • 是的,我们都希望它会变得更好.. 到目前为止,我们最终使用非常低级的套接字连接编写了我们自己的完整网络(毕竟c# 仍然是c ;))

标签: unity3d unity3d-unet


【解决方案1】:

如果您只是将发送速率设置为 0.00001,它实际上会每 物体正在移动的框架?

,但是当对象的变换不移动或旋转时,无论NetworkTransform.sendInterval 的值如何,它都不会通过网络更新。

我也在考虑类似剧本的事情......

void Update() { .. SetDirtyBit( ? ); }

是的。如果您需要为对象发送网络更新,则需要每帧调用SetDirtyBit

而且,你在那里使用什么作为位掩码?

SetDirtyBit 函数在技术上是SyncVar 属性的函数版本。该参数并没有真正记录太多,但是如果更改了SyncVar 标记的变量,则其脏掩码将更改为1。这也意味着如果您希望为对象发送网络更新,您应该将1 传递给SetDirtyBit 函数。

您还应该从标有[Command] 属性的函数中使用它,而不是直接从Update 函数中使用它。如下所示:

void Update()
{
    if (isLocalPlayer)
    {
        CmdUpdateTransform();
    }
}

[Command]
void CmdUpdateTransform()
{
    SetDirtyBit(1u);
}

虽然 Unity 声称您可以通过简单地使用 SetDirtyBit 函数来更新转换。我不认为这是真的。该声明缺少大量信息。你需要OnSerialize 来序列化和发送数据,OnDeserialize 来接收和反序列化它。 SetDirtyBit 函数仅用于确定要发送哪些数据。它用于减少使用 uNET 带来的带宽问题。

下面的代码显示了SetDirtyBit 的用法应该是什么样子。它可能需要进行一些更改才能在您身边发挥作用。

public class Example : NetworkBehaviour
{
    private const uint SEND_POSITION = 1u;
    private const uint SEND_ROTATION = 2u;
    private const uint SEND_SCALE = 3u;

    void Update()
    {
        uint dirtyBit = syncVarDirtyBits;

        dirtyBit |= SEND_POSITION;
        dirtyBit |= SEND_ROTATION;
        dirtyBit |= SEND_SCALE;

        if (isLocalPlayer)
        {
            CmdUpdateTransform(dirtyBit);
        }
    }

    [Command]
    void CmdUpdateTransform(uint dirtyBit)
    {
        SetDirtyBit(dirtyBit);
    }

    public override bool OnSerialize(NetworkWriter writer, bool initialState)
    {
        if ((this.syncVarDirtyBits & SEND_POSITION) != 0u)
        {
            writer.Write(this.transform.position);
        }

        if ((this.syncVarDirtyBits & SEND_ROTATION) != 0u)
        {
            writer.Write(this.transform.rotation);
        }

        if ((this.syncVarDirtyBits & SEND_SCALE) != 0u)
        {
            writer.Write(this.transform.localScale);
        }
        return true;
    }

    public override void OnDeserialize(NetworkReader reader, bool initialState)
    {

        if ((this.syncVarDirtyBits & SEND_POSITION) != 0u)
        {
            Vector3 pos = reader.ReadVector3();
        }

        if ((this.syncVarDirtyBits & SEND_ROTATION) != 0u)
        {
            Quaternion rot = reader.ReadQuaternion();
        }

        if ((this.syncVarDirtyBits & SEND_SCALE) != 0u)
        {
            Vector3 scale = reader.ReadVector3();
        }
    }
}

【讨论】:

  • 好一个。总而言之,(1)似乎SetDirtyBit 实际上只与 SyncVars 相关?它不适用于NetworkTransform
  • SetDirtyBit 是手动发送数据的方式,而不是使用 SyncVar,当您使用 SyncVars 属性创建变量时,它将自动为您执行此操作。 SetDirtyBit 与 NetworkTransform 无关。您可以使用它通过网络发送任何类型的数据。我认为文档对此并不清楚。调用 SetDirtyBit 将导致 Unity 调用 OnSerialize() 和 OnDeserialize() ,您可以在其中添加自定义数据以发送,就像我的答案中的示例一样。例如,您可以发送对象的位置、旋转和缩放。
  • 使用它的好处是您可以决定何时更新变量,这与 SyncVar 不同,后者仅根据发送速率进行更新。这在带宽管理方面非常重要。对于您要通过网络更新的每 12 个播放器,映像有 ~12 个变量,它们被标记为SyncVar,无论发送速率设置如何,它们都会更新。您无法控制何时阻止它们通过网络进行更新。使用SetDirtyBit,您可以节省带宽和处理时间。
  • 嗯,好的。所以 SetDirtyBit 与 NetworkTransform 无关,也与 SyncVars 无关!这只是“一种发送信息的方式(使用序列化函数)”。是这样吗??!谢谢! :)
  • 是的,这是正确的,我认为文档是说如果你想手动更新转换,你应该将 sendInterval 设置为 0,调用 SetDirtyBits 然后使用 OnSerialize() 和 OnDeserialize( ) 发送变换信息。他们留下了最后一部分。
【解决方案2】:

Unity Docs上面写着

如果 sendInterval 为零,当为该脚本设置脏位时,将在帧结束时发送更新。请注意,设置 SyncVar 的值会自动设置脏位。

所以你可以使用你自己的脚本NetworkSettings

using UnityEngine.Networking;

[NetworkSettings(channel = 1, sendInterval = 0.0f)]
class MyScript : NetworkBehaviour
{
    [SyncVar]
    int value;
}

但是SyncVar 仅适用于服务器 -> 客户端。

但您可以使用SetDirtyBit 手动设置行为脏。


或者您也可以使用InvokeSyncEvent 直接同步一些值。


Here我找到了更多关于 Dirty bits 的信息。

【讨论】:

  • 我真的不知道NetworkSettingsInvokeSyncEvent!我相信虽然这些不适用于 NetworkTransform ,但只有 SyncVars ?? IDK
  • 从未尝试过,但也有可能,如果您在 Update 中调用命令,它可能真的每帧都发送,而 sendInterval 仅适用于 SyncVar。我不确定这一点。一般来说,您必须编写自己的自定义 NetworkTransform 脚本,例如使用 [SyncVar] 和 Command 的组合(可能是这样的,但也有其他示例)。不幸的是,整个 Unity 文档都集中在服务器 -> 客户端同步...
猜你喜欢
  • 2017-01-22
  • 1970-01-01
  • 1970-01-01
  • 2019-11-30
  • 2020-09-02
  • 2021-08-17
  • 2013-11-06
  • 1970-01-01
  • 1970-01-01
相关资源
最近更新 更多