3

我正在开发团队比赛游戏。每支队伍都有自己的重生点,目标是摧毁另一支队伍的重生点。spawn 以 3 个对象的形式在网络中设置 - 一个实际 spawn(稍后称为物理 spawn),仅对服务器可见,一个名为MapManager的对象存在于客户端服务器中,它充当通过Rpc 调用和一个简单的 spawn 图形(稍后称为视觉 spawn),呈现在客户端服务器的本地播放器上。

每个对象的 NetworkIdentity 设置分别为:

  • 仅服务器,
  • 本地玩家权威,
  • 无 - 是一种 MonoBehaviour。

物理 spawn判断是否对 spawn 造成了任何伤害,如果是,则将标志isHealthChanged设置true

public class SpawnerServer : NetworkBehaviour {
    //used to determine whether has the health changed
    bool isHealthChanged = false;
    //indicates the team of this spawner via enum state
    public Data.teams myTeamEnum;
    ...
    public RectTransform healthBar;

    private void OnTriggerEnter2D(Collider2D collision)
    {
        //Checking whether the bullet wll damage the spawn
        OnChangeHealth(healthPoints);
    }
    //if the health changed, change the healthbar as well
    public void OnChangeHealth(float healthPoints)
    {
        if (isServer)
        {
            ...
            isHealthChanged = true;
        }
    }
     //returns the deltaSize of the healthbar
     public Vector2 GetHealthbarSizeDelta()
    {
        return healthBar.sizeDelta;
    }
    //switches the healthChanged bool back to false. Called by the MapManager
    public void UncheckHealthChanged()
    {
        isHealthChanged = false;
    }
    //returns the state of the healthChanged bool
    public bool IsHealthChanged()
    {
        return isHealthChanged;
    }
}

MapManager在物理生成(仅在服务器上检查)和检测到检查标志的状态:

  • 将标志重置为false
  • 获取健康栏的宽度,
  • 将有关健康栏的新宽度和生成数量的信息传递给 RPC 调用RpcChangeSpawnersHealthClients(),该调用调用负责更新视觉生成的健康栏转换数据的函数。

    public class ClientSpawnControl : NetworkBehaviour {
    //the references to scripts of the server spawns, required for checking whether has
    //the state of any of the spawns changed
    public SpawnerServer serverSpawn1;
    public SpawnerServer serverSpawn2;
    //the references to spawns that belong to the clients
    public SpawnerClient clientSpawn1;
    public SpawnerClient clientSpawn2;
    
    //acts as a messenger that forces change of spawn healthbars in clients
    [ClientRpc]
    private void RpcChangeSpawnersHealthClients(int whatTeam, float healthChangeDelta)
    {
        if(clientSpawn1 != null)
        {
            if (whatTeam == (int)clientSpawn1.myTeam)
            {
                clientSpawn1.OnChangeHealth(healthChangeDelta);
                return;
            }
        }
        if(clientSpawn2 != null)
        {
            if (whatTeam == (int)clientSpawn2.myTeam)
            {
                clientSpawn2.OnChangeHealth(healthChangeDelta);
                return;
            }
        }
    }
    // Update is called once per frame
    void Update () {
        if (!isServer)
            return;
        if(serverSpawn1.IsHealthChanged())
        {
            serverSpawn1.UncheckHealthChanged();
            RpcChangeSpawnersHealthClients((int)serverSpawn1.myTeamEnum, serverSpawn1.GetHealthbarSizeDelta().x);
        }
        if (serverSpawn2.IsHealthChanged())
        {
            serverSpawn2.UncheckHealthChanged();
            RpcChangeSpawnersHealthClients((int)serverSpawn2.myTeamEnum, serverSpawn2.GetHealthbarSizeDelta().x);
        }
    
    }
    

这是引发异常的地方:“在 TeamSelector (UnityEngine.GameObject) 上未发现传入 [ClientRpc:InvokeRpcRpcChangeSpawnersHealthClients] 的行为,服务器和客户端应具有相同的 NetworkBehaviour 实例......”

该错误非常有趣,因为提到的TeamSelector实际上与生成器更新无关。一开始就是用来初始化球员的球队数据的,仅此而已。甚至更多 - 一个物理生成物也以某种方式在客户端上生成,但如果我没记错的话,仅服务器选项应该可以防止这种行为,而且我不会尝试通过网络创建对象。

早些时候,我尝试生成带有NetworkBehaviourNetworkIdentity的视觉生成物——即使我在网络管理器中注册了这些对象,甚至使用了 ClientScene.RegisterPrefab()方法,也无法在客户端生成这些对象。使这两者的每一种可能的组合 - 情况没有改变。后来我将视觉生成重新排列为它们当前的形式,并尝试在它们检测到健康变化时立即从物理生成中调用MapManager的 RPC 调用。在客户端引发了与上面引用的类似的异常,但名称为物理生成TeamSelector对象的位置。搜索解决方案没有找到任何可行的方法,例如,我没有任何具有重复名称但属于不同名称空间的方法。

我什至不知道在哪里寻找问题的根源。在与 Unity 争论超过 3 天后,我觉得它只是不想让我创建那个游戏。有谁知道什么会导致问题?

对于这篇文章的长度,我感到非常抱歉,但我不知道如何用更短的方式描述这个问题。

4

0 回答 0