Unity's NetCode multiplayer online game online battle tutorial (8)--player position synchronization

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 onMain CameraCinemachineBrain
  • Create a new empty objectCamera and add the two componentsCinemachineVirtualCamera and CinemachineCollider

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 twoNetworkcomponents

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.csthis 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

BecauseNetworkTransformdefaults 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 ofNetworkTransformthis 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

existingPlayeraddition 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. 客户端

NetworkVariableThis 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.

Guess you like

Origin blog.csdn.net/a924282761/article/details/134298180