Unity NetworkTransform,强制更新每一帧?
Unity NetworkTransform, force update every Frame?
在有目的的 LAN 设置中,我希望 Unity NetworkTransform
简单地发送每一帧。 (模式是“同步变换”,不是刚体等)
我想知道如何做到这一点.. 如果您只是将发送速率设置为 0.00001,它实际上会在对象移动的每一帧都执行此操作吗?
(Inspector界面只允许最高29Hz,如果你想要更小的值,只需在代码中设置即可。)
我也在想剧本之类的东西......
void Update() { .. SetDirtyBit( ? ); }
这样行吗?
(还有,你在那里用什么作为位掩码?)
通过实验确定这种事情真的需要很长时间。很明显Unity的doco就是一个笑话。而且我无法 google 任何已经想到它的人。有这方面的经验吗?
其次...
更多信息。我们做了一些实验,如果你将它设置为一个非常小的值,它确实 似乎 同步 NetworkTransform
每一帧.
(当然,没动过就懒得发送了,下面@Programmer指出。)
H O W E V E R这个不会产生运动学对象或相机位置的平滑结果。我不知道为什么;它与更新循环以及更改发生的确切时间有关。但是你得到的是“非常好的抖动”。
第三...
我做了一个实验,简单地使用命令和 Rpcs,每帧发送一些信息(实际上是从一个客户端到另一个客户端)。
我专门使用了一个单独的以太网网络,应用程序除了每帧发送信息(即“手动”仅使用 Command/Rpc)外几乎什么都不做,即在 Update() 上。
事实上,它仍然丢了很多帧,经常不发送。 (比方说,它在 10 秒内错过了 10 或 20 个价值。)
天哪!
如果您需要“每一帧”发送一些信息,例如在 LAN 系统上,请不要费心这样做。
在Unity Docs里面写着
If sendInterval is zero, updates will be sent at the end of the frame when dirty bits are set for that script. Note that setting the value of a SyncVar will automatically set dirty bits.
因此您可以使用自己的脚本 NetworkSettings
using UnityEngine.Networking;
[NetworkSettings(channel = 1, sendInterval = 0.0f)]
class MyScript : NetworkBehaviour
{
[SyncVar]
int value;
}
但是 SyncVar
仅适用于服务器 -> 客户端。
但您可以使用SetDirtyBit手动设置脏行为。
或者您也可以使用 InvokeSyncEvent 直接同步一些值。
Here 我找到了更多关于脏位的信息。
if you just set the send rate to 0.00001 will it in fact do it every
frame that the object is moving?
是,但当对象的变换不移动或旋转时,无论 NetworkTransform.sendInterval
的值如何,它都不会通过网络更新。
I was also thinking something like on a script......
void Update() { .. SetDirtyBit( ? ); }
是。如果需要为对象发送网络更新,则需要每帧调用 SetDirtyBit
。
And, what do you use as a bitmask there?
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();
}
}
}
在有目的的 LAN 设置中,我希望 Unity NetworkTransform
简单地发送每一帧。 (模式是“同步变换”,不是刚体等)
我想知道如何做到这一点.. 如果您只是将发送速率设置为 0.00001,它实际上会在对象移动的每一帧都执行此操作吗?
(Inspector界面只允许最高29Hz,如果你想要更小的值,只需在代码中设置即可。)
我也在想剧本之类的东西......
void Update() { .. SetDirtyBit( ? ); }
这样行吗?
(还有,你在那里用什么作为位掩码?)
通过实验确定这种事情真的需要很长时间。很明显Unity的doco就是一个笑话。而且我无法 google 任何已经想到它的人。有这方面的经验吗?
其次...
更多信息。我们做了一些实验,如果你将它设置为一个非常小的值,它确实 似乎 同步 NetworkTransform
每一帧.
(当然,没动过就懒得发送了,下面@Programmer指出。)
H O W E V E R这个不会产生运动学对象或相机位置的平滑结果。我不知道为什么;它与更新循环以及更改发生的确切时间有关。但是你得到的是“非常好的抖动”。
第三...
我做了一个实验,简单地使用命令和 Rpcs,每帧发送一些信息(实际上是从一个客户端到另一个客户端)。
我专门使用了一个单独的以太网网络,应用程序除了每帧发送信息(即“手动”仅使用 Command/Rpc)外几乎什么都不做,即在 Update() 上。
事实上,它仍然丢了很多帧,经常不发送。 (比方说,它在 10 秒内错过了 10 或 20 个价值。)
天哪!
如果您需要“每一帧”发送一些信息,例如在 LAN 系统上,请不要费心这样做。
在Unity Docs里面写着
If sendInterval is zero, updates will be sent at the end of the frame when dirty bits are set for that script. Note that setting the value of a SyncVar will automatically set dirty bits.
因此您可以使用自己的脚本 NetworkSettings
using UnityEngine.Networking;
[NetworkSettings(channel = 1, sendInterval = 0.0f)]
class MyScript : NetworkBehaviour
{
[SyncVar]
int value;
}
但是 SyncVar
仅适用于服务器 -> 客户端。
但您可以使用SetDirtyBit手动设置脏行为。
或者您也可以使用 InvokeSyncEvent 直接同步一些值。
Here 我找到了更多关于脏位的信息。
if you just set the send rate to 0.00001 will it in fact do it every frame that the object is moving?
是,但当对象的变换不移动或旋转时,无论 NetworkTransform.sendInterval
的值如何,它都不会通过网络更新。
I was also thinking something like on a script......
void Update() { .. SetDirtyBit( ? ); }
是。如果需要为对象发送网络更新,则需要每帧调用 SetDirtyBit
。
And, what do you use as a bitmask there?
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();
}
}
}