首页 > 解决方案 > 旧生成的玩家无法更新新生成的玩家的位置,但新生成的玩家可以跟踪旧生成的玩家的更新位置

问题描述

我遇到了以下奇怪的情况,每当玩家生成时,以前的玩家都可以从服务器接收到生成事件并能够生成新玩家,但他们无法更新新玩家位置。

奇怪的是,新玩家可以追踪老玩家的位置,但老玩家无法追踪新玩家的更新位置。

我一直在调试,我注意到我在旧播放器客户端中保存“serverObjects”(播放器)的 <string, NetworkIdentity> 类型的字典不会保存新播放器,但它们可以生成新播放器。因此,我相信我无法更新其他新玩家的位置。即使我不清楚自己做错了什么......

这是 NetworkClient.cs(统一)

using System.Collections;
using System.Collections.Generic;
using UnityEngine;
using SocketIO;
using System;

public class NetworkClient : SocketIOComponent
{

    [Header("Network Client")]
    [SerializeField]
    private Transform networkContainer;
    [SerializeField]
    private GameObject playerPrefab;
    [SerializeField]
    private Dictionary<string, NetworkIdentity> serverObjects;

    public static string ClientID {get; private set;}

    


    public override void Start() {
        base.Start();
        initialize();
        SetupEvents();  
    }

    private void initialize(){
        serverObjects = new Dictionary<string, NetworkIdentity>();
    }

    public override void Update() {
        base.Update();
        On("close", (e) => {
            Debug.Log("Se ha desconectado del servidor");
        });
    }

    private Vector3 decryptPos(string pos){
        var positions = new string[3];
        positions = pos.Split(':'); 
        //Debug.Log("Soy el possss");
        Debug.Log(pos);

        float x = float.Parse(positions[0]) ;
        float y = float.Parse(positions[1]) ;
        float z = float.Parse(positions[2]) ;

        Vector3 pos3d = new Vector3(x,y,z);
        return pos3d;
    }

    private void SetupEvents() {
        On("open", (e) => {
            Debug.Log("Conexión realizada con el servidor");
        });

        On("register", (e) => {
            ClientID = e.data["id"].ToString();
            //Debug.LogFormat("Nuestro Cliente tiene ID ({0})", ClientID);
        });

        On("spawn", (e) => {

            string id = e.data["id"].ToString();
            GameObject go = Instantiate(playerPrefab, networkContainer);
            NetworkIdentity ni = go.GetComponent<NetworkIdentity>();


            if(ClientID != id){
                //En el caso de que está recibiendo el spawn de otro player

                var debug = string.Format("Otro Player ({0})", id);
                //Debug.Log(debug);
               // Debug.Log(e);

                //Debug.Log("Está spawneando otro player!!");

                
                go.name = string.Format("Other Player ({0})", id);
                

                //Getting and setting the position of the other player
                string pos = e.data["encodedPosition"].str;
                Vector3 position = decryptPos(pos);
                go.transform.position = position;
                
                ni.SetControllerID(id);
                ni.SetSocketReference(this);
                serverObjects.Add(id,ni);

                
            } else {

                //Debug.Log("Estoy espawneando :OO");
                go.name = string.Format("Player ({0})", id);

                ni.SetControllerID(id);
                ni.SetSocketReference(this);
                serverObjects.Add(id, ni);

            }

            ni = null;

            
        });

        On("updatePosition", (e) => {
            string id = e.data["id"].ToString();

            Debug.Log("SOY EL DATA QUE VIENE DEL SERVER");
            //Debug.Log(e.data["encodedPosition"]);

            var pos = e.data["encodedPosition"].str;
            var positions = new string[3];
            positions = pos.Split(':'); 

            ///Debug.Log("Soy el possss");
            //Debug.Log(positions[0] +"|||"+positions[1]+"|||"+positions[2]);

            float x = float.Parse(positions[0]) ;
            float y = float.Parse(positions[1]) ;
            float z = float.Parse(positions[2]) ;

            //Debug.Log("Soy el possss22222");
            //Debug.Log(x +"|-|-|"+y+"|-|-|"+z);

            foreach (var item in serverObjects)
            {
                Debug.Log(item);
            }

            if(!serverObjects[id]){

            } else {
                NetworkIdentity ni = serverObjects[id];


            }

            Debug.LogFormat("Server Object: {0}", serverObjects[id]);

            Vector3 posi = new Vector3(x,y,z);
            ni.transform.position = posi;

            Debug.Log("Soy el ultimate position...");
            Debug.Log(posi);

        });

        On("disconnected", (e) => {
            string id = e.data["id"].ToString();
            GameObject go = serverObjects[id].gameObject;
            Destroy(go); //Removiendo al jugador de la partida
            serverObjects.Remove(id); // Removiendolo de memoria
        });
        
    }
}

这是 NetworkIdentity.cs

using System.Collections;
using System.Collections.Generic;
using UnityEngine;
using SocketIO;

public class NetworkIdentity : MonoBehaviour
{

    [Header("Helpful Values")]
    [SerializeField]
    [GreyOut]
    private string id;
    [SerializeField]
    [GreyOut]
    private bool isControlling;

    private SocketIOComponent socket;

    void Awake()
    {
        isControlling = false;
    }

    public void SetControllerID (string ID){
        id = ID;
        isControlling = (NetworkClient.ClientID == ID) ? true: false; //Verifica si la id que viene pertenece al player o es de otro (para definir quien controla el personaje)
    }

    public void SetSocketReference(SocketIOComponent Socket){
        socket = Socket;
    }

    public string GetID(){
        return id;
    }
    
    public bool IsControlling(){
        return isControlling;
    }

    public SocketIOComponent GetSocket(){
        return socket;
    }
}

这是 NetworkTransform.cs

using System.Collections;
using System.Collections.Generic;
using UnityEngine;
using System;

[RequireComponent(typeof(NetworkIdentity))]
public class NetworkTransform : MonoBehaviour
{
    [SerializeField]
    [GreyOut]
    private Vector3 oldPosition;

    private NetworkIdentity networkIdentity;
    private Player player;

    private float stillCounter = 0f;

    void Start()
    {
       networkIdentity = GetComponent<NetworkIdentity>();
       oldPosition = transform.position;
       player = new Player(); 
       player.position = new Position();
       player.position.x = 0;
       player.position.y = 0;
       player.position.z = 0;
       player.id = networkIdentity.GetID().Trim( new Char[] { '"' } );

       if(!networkIdentity.IsControlling()){
           //enabled = false; //Turn off the script if not own player
       }
    }

    void Update()
    {
        if(networkIdentity.IsControlling()){
            if(oldPosition != transform.position){
                oldPosition = transform.position;
                stillCounter = 0f;
                sendData();
            } else {
                stillCounter += Time.deltaTime;
                if(stillCounter >= 1f){
                    stillCounter = 0f;
                    sendData();
                }
            }
        }
    }


    private void sendData(){
        //Actualiza la información del player y la manda al server
        player.position.x = (float)Math.Round(transform.position.x,3);
        player.position.y = (float)Math.Round(transform.position.y,3);
        player.position.z = (float)Math.Round(transform.position.z,3);

        player.encodePosition();
        var encodedJSONPos = player.toJSON();

        //Debug.Log("Soy la posicion del playersino: ");
        //Debug.Log(encodedJSONPos);

        networkIdentity.GetSocket().Emit("updatePosition", encodedJSONPos );
    }
 }

这是 Player.cs

using System.Collections;
using System.Collections.Generic;
using UnityEngine;
using System;

[Serializable]
public class Player
{
    public string username;
    public string id;
    public Position position;
    public EncodedPlayerMovement encodedPlayerMovement = null;

    public void encodePosition (){
            
            this.encodedPlayerMovement = new EncodedPlayerMovement();

            //Saving the id
            this.encodedPlayerMovement.id = this.id;

            //Saving the encoded position

            //var debug = string.Format("Soy la posicion antes de ser codificada: x: ({0}) y: ({1}) z: ({2}) ", position.x, position.y, position.z);
            //Debug.Log(debug);

            var encodedPos = position.x+":"+position.y+":"+position.z;
            encodedPos = encodedPos.Replace(",",".");
            this.encodedPlayerMovement.encodedPosition = encodedPos;

            //Debug.Log("Soy la posicion despues de ser codificada");
            //Debug.Log(encodedPos);
    }
        
 
    
    public JSONObject toJSON() {
        var jsonPlayer = this;
        //return  new JSONObject(JsonUtility.ToJson(this));
        return  new JSONObject(JsonUtility.ToJson(this.encodedPlayerMovement));
    }
}

[Serializable]
public class EncodedPlayerMovement {
    public string id;
    public string encodedPosition;
}

这是 PlayerManager.cs

using System.Collections;
using System.Collections.Generic;
using UnityEngine;

public class PlayerManager : MonoBehaviour
{

    [Header("Data")]
    [SerializeField]
    private float speed = 4f;

    [Header("Class Reerences")]
    [SerializeField]
    private NetworkIdentity networkIdentity;

    void Update()
    {
        if(networkIdentity.IsControlling()){
            checkMovement();
        }
    }

    private void checkMovement(){
        float horizontal = Input.GetAxis("Horizontal");
        float vertical = Input.GetAxis("Vertical");

        transform.position += new Vector3(horizontal, 0f, vertical) * speed * Time.deltaTime;
    }
}

这是nodejs中服务器代码的index.js

var io = require('socket.io')(process.env.PORT || 52300);

//Custom classes
var Player = require('./classes/Player');


console.log('Server has started');
var players = [];
var sockets = [];

io.on('connection', (socket) => {
    console.log('Conexión realizada!');


    var player = new Player();
    var thisPlayerID = player.id;

    players[thisPlayerID] = player;
    sockets[thisPlayerID] = socket;


    socket.emit('register', {id: thisPlayerID}); //Avisarle al cliente cual es su id en el servidor mediante un objeto json (no es necesario json.stringify pues se hace automatico)
    socket.emit('spawn', player) //Avisa al player actual que ha spawneado
    socket.broadcast.emit('spawn', player) //Avisa a los demas que el player actual ha spawneado (avisa a todos menos al player actual)


    //Avisar al player actual sobre todos los demas players conectados en el servidor (no se avisa sobre si mismo)
    for(var playerID in players) {
        if(playerID !== thisPlayerID){
            socket.emit('spawn', players[playerID]);
        }
    }


    //Evento de positional data from player
    socket.on('updatePosition', (data) => {
        console.log("soy el data");
        console.log(data);

        var deserializePos = data.encodedPosition;//.encodedPosition;
        var position = deserializePos.split(':');

        console.log("ANTES DE TODO: Estoy recibiendo los cambios de posición del player... El player debe emitirse a los demas jugadores...");
        console.log(position)

        var x = parseFloat(position[0]);
        var y = parseFloat(position[1]);
        var z = parseFloat(position[2]);

        console.log("ANTES DE ENCODE: Estoy recibiendo los cambios de posición del player... El player debe emitirse a los demas jugadores...");
        console.log(x,y,z)

        player.position.x = x;
        player.position.y = y;
        player.position.z = z;

        player.EncodePosition();
        console.log("DESPUES DE ENCODE: Estoy recibiendo los cambios de posición del player... El player debe emitirse a los demas jugadores...");
        console.log(player)
        //Avisarle a los demas que el player actual ha cambiado su posicion (se envia objeto player con la data)
        socket.broadcast.emit('updatePosition', player);
    });


    socket.on('disconnect', () => {
        console.log("Un jugador se ha desconectado...");
        delete players[thisPlayerID];
        delete sockets[thisPlayerID];
        socket.broadcast.emit('disconnected', player);
    });

});

最后,这是我的场景的图像...... 场景

我应该怎么做才能防止这个错误?

标签: c#node.jsunity3dnetworkingsocket.io

解决方案


问题解决了!

正如我认为这是NetworkClient.cs中的“spawn”事件中的客户端问题,事情是if(ClientID!= id)中的网络身份设置有问题,不知道为什么但是当我移动时if 语句上面的代码段字典 <string,networkIdentity> 的数组开始工作。

这很棘手,但解决问题的过程是关键,所以我将描述我是如何为那些不知道从哪里开始或如何寻求帮助的人做的,就像发生在我身上一样......

脚步:

  1. 打开多个统一编辑器以查看不同客户端的控制台日志。这可以通过这个小技巧来实现:克隆项目文件夹中的统一项目,重命名它,删除克隆项目中的资产文件夹,然后在 bash 中使用 mklink 进行硬链接,以重定向原始项目的资产文件夹进入克隆项目,这将允许使用原始项目维护每个克隆项目的更新,并避免多个代码版本以正确调试新更改。如果您不知道如何制作硬链接,只需 google 一下,这真的很简单。
  2. 公开您要调试的任何变量、结构、列表或游戏对象。有时“Debug.Log”不足以知道运行时发生了什么。在我的情况下,我使用字典来保存 serverObjects,而当您将其公开时,字典无法在统一编辑器中显示,因此我必须首先制作一个类似于字典的结构,然后制作一个类型结构的列表,然后您可以将其公开,并在统一编辑器中更清楚地看到正在发生的事情。
  3. 调试,更改,调试。有时您将不得不尝试不同的事情,但总会发现,并且对于每个调试周期,您都会更清楚地了解问题所在。

这是我解决这个棘手问题的过程,当然也可以用于调试您的棘手网络问题!


推荐阅读