Unity's NetCode multiplayer online game online battle tutorial (6)--NetworkTransform component

Preface

This tutorial mainly talks about a very important component for synchronizing the position information of two playersNetworkTransform, as well as the function and description of this component.


What is NetworkTransform

Synchronizing objects Transform is one of the most common tasks in Netcode's multiplayer games today. The concept seems simple:

  • Determine the transformation axis you want to synchronize.
  • Serialize these values.
  • Send the serialized value as a message to all other connected clients.
  • Process the message and deserialize the value.
  • Apply these values ​​to the appropriate axis.

At first glance, the tasks listed above may seem relatively simple, but when you start implementing each task, almost any experienced Netcode software engineer will agree: it can get complicated quickly.

For example, the tasks listed above do not take into account the following:

  • Who controls synchronization (i.e. each client, server, or possibly both depending on what is being synchronized)?
  • At what frequency should these values ​​be synchronized, and what should be the logic to determine when these values ​​need to be synchronized?
  • If you have a complex parent-child hierarchy (a parent transform with one or more child transforms), should you synchronize world space axis values ​​or local space axis values?
  • How to optimize the bandwidth cost of each transform update?

Fortunately, Netcode for GameObjects (NGO) provides an implementation of the NetworkTransform component that handles some of the tricky aspects of transform synchronization and can be accessed via the inspector in the editor. Easily configure the properties accessible in .


Player movement script

Package Manager --> Select the package next to the number + in the upper left cornerUnity Registry, search Cinemachine download and import a>

MovePlayerMove toScripts and add the script on the prefabPlayer



NetworkTransform field explanation

Synchronizing (“Syncing”)

This is used to specify synchronization position, rotation, and scaling. Just check which values ​​need to be synchronized.

Under normal circumstances, there is no need to synchronize all transformation values ​​​​of GameObject. For example, if the GameObject's scaling never changes, it can be disabled at Syncing Scale in the panel. Disabling synchronization saves CPU costs and network bandwidth.

Thresholds

You can use the threshold value to set a minimum threshold. This can be used to reduce the frequency of synchronized updates by only synchronizing changes greater than or equal to the threshold value (changes below the threshold will not be synchronized). For example:

IfNetworkTransform interpolation is enabled (Interpolate), you may find that you can reduce the resolution of the position threshold (increase the position threshold value) without Affects the "smoothness" of object motion, while also reducing the frequency of position updates (reducing the bandwidth cost per instance). Increasing the threshold resolution (lowering the position threshold value) increases the potential frequency with which an object's position is synchronized (potentially increasing the bandwidth cost per instance).

Threshold values ​​are not synchronized but can be updated onauthoritative instances. This should be kept in mind when using instances in Ownerauthoritative mode, as changing ownership will use whatever value is currently set on the new owner instance. If you plan to change the threshold value at runtime and plan to change ownership, you may need to synchronize the threshold value.

Local space

By default, NetworkTransform is transformed by 世界空间同步 the object. In Local SpaceConfiguration option allows you to synchronize transforms in local space instead. The child object's local space axis values ​​(mainly position and rotation) are always offsets relative to the parent transform. The world space axis value of the child object includes the axis value of the parent object.

Using local space on a parented NetworkTransform improves transform synchronization when the object is re-parented, because re-parenting does not change the object's local space transform. But it will change the world space position.

authoritative instances do synchronize changes to LocalSpace properties. Therefore, you can adjust this property on authoritative instances at runtime, while non-authoritative instances will update automatically.

Interpolation

Interpolation (·Interpolation·) is enabled by default, which is the recommended setting if you want smooth transitions between transform updates on nonauthoritative instances. Interpolation buffers incoming state updates, which may introduce a slight delay between authoritative instances and non-authoritative instances. When the interpolation property is disabled, transformation changes are immediately applied to non-authoritative instances, which may cause visual "jitter" or appear to "jump" when latency is high "Status updates to new applications.

Changing interpolated properties at runtime on an authoritative instance will be synchronized with all non-authoritative instances.

NetworkTransformThe component only interpolates on the client side. To achieve smoother movement on the host or server, users may also wish to implement interpolation on the server side. Although the server is not affected by network-induced jitter, it may still experience some stuttering locally (e.g., low physical update rate movement in FixedUpdate).

Slerp Position

When this property is set and interpolation is also enabled (Interpolation), non-authoritative instances will passSlerp instead of Lerp interpolating towards their target positions. Typically this can be used when an object follows a circular and/or spline-based motion path to preserve the curvature of that path. Since "lerp" interpolation between two points produces a linear progression on the line between the two points, in some cases the frequency of position state updates may result in a loss of the object's motion curve.

Use Quaternion Synchronization

By default, Euler angle values ​​are used to synchronize rotation increments. For many situations, using Euler angle values ​​may be sufficient. However, there are situations where synchronizing Euler angle increments can produce undesirable results. One situation is when you have complex nested NetworkTransforms where the rotation is different between the parent and child transforms. When you combine interpolation together (remember that interpolation is buffered and there is an inherent delay between the non-authoritative current rotation and the target rotation), the adjustments that happen immediately in Quaternion handle more complex transformation related issues ( Such as Jimba lock, etc.).

When Quaternion synchronization is enabled, the authoritative instance still compares the Euler axis values ​​against the threshold value to determine if the transformed rotation needs to be updated, but the entire Quaternion is updated, not just the Euler axis where the change was detected. This means that it is ensured that the correct rotation will be applied to non-authoritative instances, and that more complex issues that may arise when using Euler angles have been taken into account.

Quaternion synchronization comes at a cost. It increases the bandwidth cost by 16 bytes per instance to handle more complex rotation problems that are more common when using nested NetworkTransforms (one or more parent transforms and one or more child transforms). However, when you enable theUse Quaternion Synchronizationproperty, you will notice the Synchronize Axis Selection checkbox and a newUse Quaternion Compressionproperty appear:

When enabledUse Quaternion Synchronization, the Rotate synchronized axes checkbox is no longer available (because synchronously transformed quaternions will always update all rotation axes), whereasUse Quaternion CompressionBecome a visible option.

Use Quaternion Compression

Since synchronizing quaternions may increaseNetworkTransformrotate the bandwidth cost of state updates, there are two ways to reduce quaternion synchronization Total bandwidth cost of:

  • Quaternion compression (Quaternion Compression): This provides the highest compression ratio (reduced to 4 bytes per update), but the precision loss is slightly higher than half floating point precision.

  • Half floating point precision (Half Float Precision): When quaternion compression is enabled and quaternion compression is disabled, this provides a moderate level of alternative compression (reduced to 8 bytes per update), Less precise than a full floating point value, but more precise than quaternion compression.

Quaternion compression is based on the least-triple algorithm and can be used when rotation accuracy is less important than bandwidth cost. You may have attached objects/projectiles that require some form of rotational synchronization, but don't need to be perfectly aligned in the overall scheme of the project.

If bandwidth cost and precision are both issues, the alternative recommended compression method is half-floating point precision. Additionally, it is recommended to try different compression options, you may find that the partial loss of accuracy is perfectly acceptable for your project's needs (and can reduce the overall bandwidth cost across all instances by up to 50% without using the full accuracy).

This attribute value can be updated while the authoritative instance is running and will be synchronized to all non-authoritative instances. Reminder: Updating this value at runtime on an authoritative instance will result in a full synchronization of NetworkTransform's interpolators for all non-authoritative instances will be reset.

Use Half Float Precision

Enabling this property will convert any transform axis value from4-byte float to 2-byte half floating point number, but at the expense ofprecision loss. When this option is enabled, all transform axes marked as synchronized will use half floating point precision. However, there are some unique aspects to half-floating point precision regarding position and rotation.

Due to the loss of precision, position status updates only provide position deltas relative to the last known complete position. NetworkDeltaPositionThe serializable structure keeps track of the current delta between the last known complete position and the current delta offset from the last known complete position. Additionally, NetworkDeltaPosition automatically corrects for precision loss when sending updates. The accuracy loss from the previous update will be included in the next location update. In other words, a non-authoritative instance can potentially be associated with an authoritative instance for the duration of 1 tick period or until the next transform state update is received. Score delta from each applied update. Additionally, NetworkDeltaPosition fills the gap between the maximum half-float value and the maximum bounds of Unity's world space (global/project scaling dependent).

Recommended Unity world space units per second:
The maximum increment per update should not exceed 64 Unity world space units. If you use the default tick (30), then the object should not move at a speed equal to or exceeding 1920 Unity world space units per second (i.e. 30 x 64). For reference, the default camera's far clipping plane is 1000 Unity world space units, which means that an object moving at 1920 Unity world space units may not be visually detected in the rendering frustum, or may appear briefly in the rendering frustum. "Flashing" appears.

When enabledUse Quaternion Synchronization and Use Half Float Precision and disabledUse Quaternion Compression, quaternion values ​​are synchronized via the HalfVector4 serializable structure , where each axis value (x, y, z, and w) is stored as a half-floating point value. This means that each rotation update is reduced from 16 bytes at full precision to 8 bytes at a time. For rotations, using half floating point precision provides better accuracy than quaternion compression at twice the bandwidth cost, but only half the cost of full precision.

When enabled Use Quaternion Synchronization, Use Half Float Precision and Use Quaternion Compression, quaternion compression will be used instead of half floating point precision of rotation.

When updates are made on an authoritative instance, all of these properties will be synchronized to non-authoritative instances.

Authority modes

Server Authoritative Mode

By default, NetworkTransform runs in serverauthoritative mode. This means that the server side detects the transform axis to be synchronized (marked as synchronized) and pushes it to the connected client. This also means that any changes to the transform axis values ​​will be overwritten by theauthoritativestate (in this case the server-side transform state).

There is another concept to keep in mind regarding the transformation values ​​of axis synchronization and initial synchronization. Any axes not marked for synchronization will still be updated to the initial state of when NetworkObject is generated or the client synchronizes for the first time. authoritative

For example:
Suppose you only marked the position and rotation axes for synchronization, but excluded all scaling on the NetworkTransform component's network prefab axis. When you build an instance of a network prefab, the initial authoritative scaling value is synchronized at build time. From that point on, nonauthoritative instances (client instances in this case) will keep the same scale axis values, even if they are no longer updated.

Owner Authoritative Mode

(aka: ClientNetworkTransform)

Server-side authoritativeNetworkTransform provides a balance between synchronizing transformations and applying updates on all connected clients. However, sometimes you want a specificNetworkObject (usually a player) to have its position updated immediately on the client. The owner authority of NetworkTransform is determined by the NetworkTransform.OnIsServerAuthoritative method, which is called when the NetworkTransform component is first initialized. If the method returns true (the default), it will be initialized to the server's authoritative NetworkTransform. If false is returned, it will be initialized to the owner's (also known as ). This can be accomplished by deriving from , overriding the virtual method, and returning false as in the following code example: authoritativeNetworkTransformClientNetworkTransformNetworkTransformOnIsServerAuthoritative

using Unity.Netcode.Components;
using UnityEngine;

namespace Unity.Multiplayer.Samples.Utilities.ClientAuthority
{
    
    
    /// <summary>
    /// 用于同步客户端端的变换更改。这包括主机。不支持纯服务器作为所有者,请使用NetworkTransform。
    /// 用于那些始终由服务器拥有的Transform。
    /// </summary>
    [DisallowMultipleComponent]
    public class ClientNetworkTransform : NetworkTransform
    {
    
    
        /// <summary>
        /// Used to determine who can write to this transform. Owner client only.
        /// This imposes state to the server. This is putting trust on your clients. Make sure no security-sensitive features use this transform.
        /// </summary>
        protected override bool OnIsServerAuthoritative()
        {
    
    
            return false;
        }
    }
}

ClientNetworkTransformExample:

SelectWindow --> Package Manager to open the package manager.

Add(+) --> 从git URLAdd...

Copy and paste the following Git URL:https://github.com/Unity-Technologies/com.unity.multiplayer.samples.coop.git?path=/Packages/ com.unity.multiplayer.samples.coop#main

or modify the project'smanifest.json, add

"com.unity.multiplayer.samples.coop": "https://github.com/Unity-Technologies/com.unity.multiplayer.samples.coop.git?path=/Packages/com.unity.multiplayer.samples.coop#main"

This Transform synchronizes the owner client's position with the server and all other clients, enabling client authoritative gameplay.

Additional Virtual Methods of Interest

NetworkTransform.OnAuthorityPushTransformState: This virtual method is called when the authoritative instance is pushing a new NetworkTransformState to a non-authoritative instance. This can be used to more precisely determine updated values ​​for nonauthoritativeinstances for prediction-related tasks.

NetworkTransform.OnNetworkTransformStateUpdated: This virtual method is called when a non-authoritative instance receives a pushed update from an authoritative instance. This can be used to more precisely determine updated values ​​for noninstances for prediction-related tasks. NetworkTransformStateauthoritative

NetworkTransform.Awake: To provide the ability to customize initialization, this method has been made virtual. If you override this method, it is recommended to call base.Awake() first.

NetworkTransform.OnInitialize: This virtual method is called when the related NetworkObject is first generated and when ownership changes.

NetworkTransform.Update: To provide you with the ability to make any customizations to the derivedNetworkTransform class, this method has been made virtual. If you override this method, it is required to be called for all non-authoritative instances of base.Update(), but not required for authoritative instances.


Afterword

WithNetworkTransform this component can save a lot of effort for location synchronization. The practical application ofNetworkTransform will be discussed later

Official link

https://docs-multiplayer.unity3d.com/netcode/current/components/networktransform/

Guess you like

Origin blog.csdn.net/a924282761/article/details/134200607
Recommended