Article directory
Preface
Continuing from the previous article, after adding the movement script on the Player, the position of each player must be synchronized.
add camera
- Add a component on
Main Camera
CinemachineBrain
- Create a new empty object
Camera
and add the two componentsCinemachineVirtualCamera
andCinemachineCollider
Don’t bind the player manually first, and use the script to control the camera’s following object later.
Players add corresponding components
- Make sure the player's prefab is added
碰撞体
with the other twoNetwork
components
Select the axis to be synchronized on theNetworkTransform
component. Here I only choose to synchronize Position
and Rotation
a>XYZAxis
server authoritative
Up to the current position, the player's position has been indeed synchronized, but another point is that when you move, all characters with PlayerMove
scripts will be moved. The following should be focused on yourself. The character moves. So I have to modifyPlayerMove.cs
this script
using System;
using Cinemachine;
using Cinemachine.Utility;
using UnityEngine;
using Unity.Netcode;
public class PlayerMove : NetworkBehaviour
{
public float Speed;
public float VelocityDamping;
public float JumpTime;
public enum ForwardMode
{
Camera,
Player,
World
};
public ForwardMode InputForward;
public bool RotatePlayer = true;
public Action SpaceAction;
public Action EnterAction;
Vector3 m_currentVleocity;
float m_currentJumpSpeed;
float m_restY;
private void Start()
{
if (IsOwner)
{
GameObject.Find("===Camera===/Camera").GetComponent<CinemachineVirtualCamera>().Follow = transform;
}
}
private void Reset()
{
Speed = 5;
InputForward = ForwardMode.Camera;
RotatePlayer = true;
VelocityDamping = 0.5f;
m_currentVleocity = Vector3.zero;
JumpTime = 1;
m_currentJumpSpeed = 0;
}
private void OnEnable()
{
m_currentJumpSpeed = 0;
m_restY = transform.position.y;
SpaceAction -= Jump;
SpaceAction += Jump;
}
void Update()
{
if (!IsOwner) return;
#if ENABLE_LEGACY_INPUT_MANAGER
Vector3 fwd;
switch (InputForward)
{
case ForwardMode.Camera:
fwd = Camera.main.transform.forward;
break;
case ForwardMode.Player:
fwd = transform.forward;
break;
case ForwardMode.World:
default:
fwd = Vector3.forward;
break;
}
fwd.y = 0;
fwd = fwd.normalized;
if (fwd.sqrMagnitude < 0.01f)
return;
Quaternion inputFrame = Quaternion.LookRotation(fwd, Vector3.up);
Vector3 input = new Vector3(Input.GetAxis("Horizontal"), 0, Input.GetAxis("Vertical"));
input = inputFrame * input;
var dt = Time.deltaTime;
var desiredVelocity = input * Speed;
var deltaVel = desiredVelocity - m_currentVleocity;
m_currentVleocity += Damper.Damp(deltaVel, VelocityDamping, dt);
transform.position += m_currentVleocity * dt;
if (RotatePlayer && m_currentVleocity.sqrMagnitude > 0.01f)
{
var qA = transform.rotation;
var qB = Quaternion.LookRotation(
(InputForward == ForwardMode.Player && Vector3.Dot(fwd, m_currentVleocity) < 0)
? -m_currentVleocity
: m_currentVleocity);
transform.rotation = Quaternion.Slerp(qA, qB, Damper.Damp(1, VelocityDamping, dt));
}
// Process jump
if (m_currentJumpSpeed != 0)
m_currentJumpSpeed -= 10 * dt;
var p = transform.position;
p.y += m_currentJumpSpeed * dt;
if (p.y < m_restY)
{
p.y = m_restY;
m_currentJumpSpeed = 0;
}
transform.position = p;
if (Input.GetKeyDown(KeyCode.Space) && SpaceAction != null)
SpaceAction();
if (Input.GetKeyDown(KeyCode.Return) && EnterAction != null)
EnterAction();
#else
InputSystemHelper.EnableBackendsWarningMessage();
#endif
}
public void Jump()
{
m_currentJumpSpeed += 10 * JumpTime * 0.5f;
}
}
After was compiled and built, it was found that it can be used normally, but there is another problem: only the Server
side can be moved, but the Client
side cannot be moved. Is this a BUG? Obviously not.
client authoritative
BecauseNetworkTransform
defaults to the authoritative verification of the server, the client cannot update its location.It can only inform the server that my location has been updated. , and then the server tells others that his location has been updated.
If you want to use客户端权威
, you need to addClientNetworkTransform
instead ofNetworkTransform
this component
Go to the package manager to add theGit URL
package,https://github.com/Unity-Technologies/com.unity.multiplayer.samples. coop.git?path=/Packages/com.unity.multiplayer.samples.coop#main
existingPlayer
addition aboveClientNetworkTransform
, removalNetworkTransform
Keep everything else unchanged, compile and run to move the client.
Server sync location
Create a new scriptPlayerTransformSync.cs
and mount it onPlayer
. RemoveClientNetworkTransform
PlayerTransformSync.cs
:
using Unity.Netcode;
using UnityEngine;
public class PlayerTransformSync : NetworkBehaviour
{
private NetworkVariable<Vector3> _syncPos = new();
private NetworkVariable<Quaternion> _syncRota = new();
private void Update()
{
if (IsLocalPlayer)
{
UploadTransform();
}
}
private void FixedUpdate()
{
if (!IsLocalPlayer)
{
SyncTransform();
}
}
private void SyncTransform()
{
transform.position = _syncPos.Value;
transform.rotation = _syncRota.Value;
}
private void UploadTransform()
{
if (IsServer)
{
_syncPos.Value = transform.position;
_syncRota.Value = transform.rotation;
}
else
{
UploadTransformServerRpc(transform.position, transform.rotation);
}
}
[ServerRpc]
private void UploadTransformServerRpc(Vector3 position, Quaternion rotation)
{
_syncPos.Value = position;
_syncRota.Value = rotation;
}
}
Generally, this method is usedServer authorityLocation synchronization a>.
Reading and ComprehensionPlayerTransformSync.cs
Script can be separatedFour partsLeft understanding:
- Create network sync fields
- If it is the host, there is no need to send information to
Server
but Direct synchronization - If it is a customer, you need to send a request for information to
Server
Sync - Sync other people’s locations
NetworkVariable
Create two network synchronized fields viaNetworkVariable
, one synchronizedposition
and the other synchronizedrotation
private NetworkVariable<Vector3> _syncPos = new();
private NetworkVariable<Quaternion> _syncRota = new();
Then local players upload their location information through theUploadTransform
method. There are two situations here
- 为Main machinetime
- 为客户时
UploadTransform
When ishost, just synchronizeTransform
directly
When is client, send information to the server and request synchronizationTransform
private void UploadTransform()
{
if (IsServer)
{
_syncPos.Value = transform.position;
_syncRota.Value = transform.rotation;
}
else
{
UploadTransformServerRpc(transform.position, transform.rotation);
}
}
[ServerRpc]
private void UploadTransformServerRpc(Vector3 position, Quaternion rotation)
{
_syncPos.Value = position;
_syncRota.Value = rotation;
}
SyncTransform
When I upload my location, I am synchronizing it, and others synchronize the location information to transform.
inUpdate()
and FixedUpdate()
can ensure priority, synchronize your own first, and then synchronize others.
private void Update()
{
if (IsLocalPlayer)
{
UploadTransform();
}
}
private void FixedUpdate()
{
if (!IsLocalPlayer)
{
SyncTransform();
}
}
private void SyncTransform()
{
transform.position = _syncPos.Value;
transform.rotation = _syncRota.Value;
}
Afterword
This location synchronization tutorial is about direct basic communication between 服务端
and , need to know how to use it, and also need to understand theserverandclientThe logic between them is the biggest focus of this tutorial. 客户端
NetworkVariable
This is very helpful for field network synchronization. The communication between [ServerRpc]
and [ClientRpc]
will be often used in the future. The following blog posts will continue to go in depth. explain.