【问题标题】:Exception in OnStartServer:Object reference not set to an instance of an objectOnStartServer 中的异常:对象引用未设置为对象的实例
【发布时间】:2020-09-10 22:25:00
【问题描述】:
 public class GameControl : NetworkBehaviour {
 
     public GameObject localPlayer;
 
     [TargetRpc]
     public void TargetGetLocalPlayer(NetworkConnection conn)
     {
         localPlayer = GameObject.Find("Local");
       
     }
      public override void OnStartServer()
     {
        base.OnStartServer();
        TargetGetLocalPlayer(connectionToClient);
        
      }
   
 }

我有一个附加到服务器对象的脚本,它应该能够从客户端抓取本地玩家游戏对象(我通过在另一个脚本中生成后将其名称更改为“本地”来表示)但是当我尝试调用TargetGetLocalPlayer ,我收到以下错误:

 Exception in OnStartServer:Object reference not set to an instance of an object   at 
 UnityEngine.Networking.NetworkBehaviour.SendTargetRPCInternal 
 (UnityEngine.Networking.NetworkConnection conn, UnityEngine.Networking.NetworkWriter writer, 
 System.Int32 channelId, System.String rpcName) [0x0002e]

我对统一网络完全陌生,我觉得我应该使用 photon 而不是 unet,似乎没有人再对 unet 感兴趣,而且文档不擅长解释任何事情,如果有人我将非常感激可以回答我,提前谢谢

【问题讨论】:

  • 至于it seems like no one is interested in unet anymore: UNet is deprecated .. Photon 目前是最好的选择

标签: unity3d unity3d-unet


【解决方案1】:

我认为更好的解决方案是为每个玩家附加一个脚本。并使其在“新”玩家加入时运行 GameControl 中的方法以将玩家添加到玩家列表中。像这样:

    //this is on your gameControl.
    public List<Player> players;

    public void AddPlayer(Player player)
    {
       players.Add(player);
    }

如果您将 GameControl 作为单例,则此方法有效。如果您不知道该怎么做,请检查最后一段代码。 //这是在您的播放器脚本上,称为播放器(如果您有其他名称,请全部更改 //播放器脚本在此处以该名称命名

      public void Start()
   {
       GameControl.AddPlayer(this);
   }

或者

您可以将其设置为字典,并为每个加入的玩家创建一个密钥,以使其更易于访问,而不是让玩家列表成为一个列表。

如何使脚本成为单例以及为什么

为什么

如果您有一个管理器类/脚本,您总是希望只有 ONE 个实例,这样您就可以轻松地调用其方法而不会出现问题。

如何:

基本上你这样做是为了只有这个脚本可以更改管理器中的值和变量,而其他脚本可以获取/调用方法和函数。这使它易于访问,您将遇到更少的问题。

私有静态GameControl_GameControl;

  private Player player;
public static GameControl gameControl
{
    get
    {
        if(_GameControl == null)
        {
            Debug.LogError("Game Control is null");
            
        }

        return _GameControl;
    }
}


    void Awake()
   {
       _GameControl = this;
       player = GameObject.Find("Player").GetComponent<Player>();
    }

【讨论】:

  • 有没有办法判断列表中的哪些玩家是控制客户端的玩家?这是主要问题。
  • 好吧,如果有输入,您可以作为控制播放器获得它。但是如果你有更多的玩家,你会得到更多的输入。
  • 但是你能澄清你的问题的意思吗
  • 我需要知道玩家列表中的哪个玩家是由客户端控制的玩家 = 客户端上的当前本地玩家(并且服务器上的玩家不止一个,但是只有一个玩家控制每个客户端)
  • 你能澄清一下你的客户是什么。我不明白,因为玩家应该是玩家预制件的一个实例。
【解决方案2】:

嗯,我明白你的意思了,创建一个可以由任何脚本(如单例)运行的方法。然后你传入你想要添加的游戏对象,如下所示:

public class GameManager
{

    public GameObject _player;

    //this is a singleton.
    private static GameManager _gm;
    public static GameManager gameManager
    {
        get
        {
            if(_gm == null)
            {
                Debug.LogError("Game manager is null");
            }

            return _gm;
        }
    }


    void awake()
    {
        _gm = this;
    }


    void GetPlayer(GameObject player)
    {
        _player = player;
    }

    void AddPlayer(GameObject player)
    {
        //add it to whatever you want to.
    }
}

这样调用方法:

public class Player : MonoBehaviour
{
    // Start is called before the first frame update
    void Start()
    {
        GameManager.gameManager.GetPlayer(this.gameObject);
    }

   
}

【讨论】:

  • @JadonWolfgand 我试过你说的,但我想知道这个单身人士是否对所有客户(包括主机)都一样
  • 它是静态类型,所以是的。每个客户都是一样的
  • 嗯,客户端上所有游戏对象都是同一个实例,但其他客户端不一样,你确定应该是一样的吗?
  • 为什么会有多个游戏管理员???这只会带来麻烦,但如果你这样做,你将需要有 1 个静态类来共享所有类
猜你喜欢
  • 1970-01-01
  • 2012-08-04
  • 1970-01-01
  • 1970-01-01
  • 1970-01-01
  • 2012-08-08
  • 1970-01-01
  • 2013-12-30
  • 2014-06-25
相关资源
最近更新 更多