Unity NetworkTransform,是否强制更新每个Frame?

时间:2018-11-13 16:48:12

标签: unity3d unity3d-unet

在有目的的LAN设置上,我希望Unity的NetworkTransform仅发送每个帧。 (模式是“同步变换”,而不是刚体,等等。)

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

(Inspector界面最多允许29Hz,如果需要较小的值,只需在代码中进行设置即可。)

我也在想类似剧本的事情……

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

会这样做吗?

(而且,您在那里用作位掩码是什么?)

通过实验确定这种事情真的需要永远。显然Unity的doco是个玩笑。而且我无法用谷歌搜索任何已经想到的人。有经验吗?


第二 ...

更多信息。我们进行了一些实验,实际上,如果将其设置为一个很小的值,它会 似乎 同步每帧NetworkTransform

(当然,它没有移动也不会打扰,正如@Programmer指出的那样。)

HOV E V E R 不会 )对于运动物体或摄像机位置不会产生平滑的结果。我不知道为什么;它与Update循环以及更改发生的时间有关。但是您得到的是“非常好的抖动”。


第三次 ...

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

我专门使用了专用的单以太网网络,这些应用程序除了在每帧(即使用Command / Rpc进行“手动”发送)信息(即在Update()上)之外几乎没有做任何事情。

实际上,它静止会丢弃许多帧,通常不会发送。 (比方说,它在10秒内损失了10或20。)

悲痛!

如果您需要在局域网系统上说“每帧”发送一些信息,请不要打扰。

2 个答案:

答案 0 :(得分:2)

  

如果您只是将发送速率设置为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 :(得分:1)

Unity Docs中说

  

如果sendInterval为零,则为该脚本设置了脏位时,更新将在帧的末尾发送。请注意,设置SyncVar的值将自动设置脏位。

因此,您可以使用NetworkSettings

使用自己的脚本
using UnityEngine.Networking;

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

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

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


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


Here我发现了有关脏比特的更多信息。