代码之家  ›  专栏  ›  技术社区  ›  Bak Stak

当所有玩家同名时查找localPlayer

  •  2
  • Bak Stak  · 技术社区  · 8 年前

    当谈到将玩家引用到另一个对象的脚本时,Unity让我感到困惑。我使用了几种方法来引用localPlayer对象:

    1. 比较标记(在某些情况下不太好)
    2. gameObject.Name (从未使用过,但也不可靠)
    3. 分配 public GameObject Player; 在督察中 拖放 (当玩家是预制的时候会遇到问题)
    4. 制作 public static [PlayerControllerClass] instance; 和设置 instance = this 在里面 void Start() 函数。以便访问 playerSpeed 从另一个剧本 PlayerControllerClass.instance.playerSpeed = 10;

    有没有其他的解决方案,以一个适当的方式参考球员。

    笔记 我知道我的问题可能与某个具体问题无关,但如果有人愿意帮忙,我可以解释更多。

    编辑1: 例如我想找到 localPlayer 在网络游戏中,所有玩家都有相同的名字,相同的标签,但只有一个玩家是本地玩家。我能进入 本地播放器 从另一个剧本?

    编辑2: 我接受的答案是我感觉最好的。我将使用预览中提供的答案 score text 本地播放器 从一组玩家那里访问[ 本地播放器 ]

    3 回复  |  直到 8 年前
        1
  •  4
  •   Programmer    8 年前

    你的问题直到你的编辑才弄清楚,然后我才意识到这是一个网络问题。

    我需要在所有玩家都有 相同的名称,相同的标记,但只有一个播放器是本地播放器我可以访问 另一个脚本中的本地播放器?

    你可以找到玩家 NetworkConnection.playerControllers 哪一个重述了 PlayerController 然后循环检查它是否有效。之后,从中获取networkbehavior检查isLocalPlayer属性。就这样。

    像这样的:

    GameObject FindLocalNetworkPlayer()
    {
        NetworkManager networkManager = NetworkManager.singleton;
        List<PlayerController> pc = networkManager.client.connection.playerControllers;
    
        for (int i = 0; i < pc.Count; i++)
        {
            GameObject obj = pc[i].gameObject;
            NetworkBehaviour netBev = obj.GetComponent<NetworkBehaviour>();
    
            if (pc[i].IsValid && netBev != null && netBev.isLocalPlayer)
            {
                return pc[i].gameObject;
            }
        }
        return null;
    }
    

    如果你有 NetworkIdentity 连接到播放器而不是 NetworkBehaviour ,只需获取 网络标识 并检查 isLocalPlayer 财产。你也可以找到游戏对象然后检查 网络标识 以及 岛礁层 财产。

    if (obj.GetComponent<NetworkIdentity>().isLocalPlayer){}
    

    您可能需要的其他有用的播放器操作:

    找到所有玩家 :

    List<GameObject> ListPlayers()
    {
        NetworkManager networkManager = NetworkManager.singleton;
        List<PlayerController> pc = networkManager.client.connection.playerControllers;
    
        List<GameObject> players = new List<GameObject>();
        for (int i = 0; i < pc.Count; i++)
        {
            if (pc[i].IsValid)
                players.Add(pc[i].gameObject);
        }
        return players;
    }
    

    按名称查找播放器(也可以更改为按标记或层) :

    GameObject FindNetworkPlayer(string name)
    {
        NetworkManager networkManager = NetworkManager.singleton;
        List<PlayerController> pc = networkManager.client.connection.playerControllers;
    
        for (int i = 0; i < pc.Count; i++)
        {
            if ((pc[i].IsValid) && (name == pc[i].gameObject.name))
                return pc[i].gameObject;
        }
        return null;
    }
    

    编辑前的旧答案:

    有没有其他的解决方案,以一个适当的方式参考球员。

    是的,你发现游戏对象 GameObject.Find ,之后,您可以使用 GetComponent 函数获取附加到它的脚本。

    我注意到你提到过你也要参考场景中的预制件。预设和场景中已有的对象之间存在差异,它们都有不同的引用方式。

    下面是场景中已存在对象的示例。你可以在 等级制度 tab:

    enter image description here

    让我们通过 名称 :

    GameObject canvasObj = GameObject.Find("Canvas");
    

    让我们参考一下 Canvas “画布”游戏对象的脚本附件:

    GameObject canvasObj = GameObject.Find("Canvas");
    Canvas canvas = canvasObj.GetComponent<Canvas>();
    

    预制件:

    以下是“项目”选项卡中预制的示例:

    enter image description here

    把预制件放在一个名为“Resources”的文件夹中。你必须这样你才能用 Resources 应用程序接口

    让我们参考“胶囊”预制游戏对象:

    GameObject prefab = Resources.Load<GameObject>("Capsule");
    

    要使用它,必须实例化它:

    GameObject instance = Instantiate(prefab);
    

    只有在预设组件被实例化之后,才能获取这些组件:

    CapsuleCollider cc = instance.GetComponent<CapsuleCollider>();
    
        2
  •  2
  •   Immorality    8 年前

    我推荐单例模式。我在几乎所有的Unity项目中都实现了它,对象只有一个类,但它是单行为的。

    using UnityEngine;
    
    
    public abstract class SingletonBehaviour<T> : MonoBehaviour where T : MonoBehaviour
    {
        public bool dontDestroyOnLoad = true;
        private bool isInitialized = false;
    
        private static T instance;
        public static T Instance
        {
            get
            {
                if (instance == null)
                {
                    instance = FindObjectOfType<T>();
                    if (instance == null)
                    {
                        var obj = new GameObject
                        {
                            name = typeof(T).Name
                        };
                        instance = obj.AddComponent<T>();
                    }
                }
    
                return instance;
            }
        }
    
        protected virtual void Awake()
        {
            if (instance == null)
            {
                instance = this as T;
    
                if (dontDestroyOnLoad)
                {
                    DontDestroyOnLoad(this.transform.root.gameObject);
                }
            }
            else if (instance != this)
            {
                Destroy(gameObject);
            }
        }
    
    
        private void OnEnable()
        {
            if (!isInitialized)
            {
                OnInitialize();
                isInitialized = true;
            }
        }
    
        public abstract void OnInitialize();
    }
    

    然后可以创建一个类,如下所示:

    public class MyClass : SingletonBehaviour<MyClass>
    {
        public void OnInitialize()
        {
            // You can use this instead of awake or start
        }
    
        public void DoStuff();
    }
    

    这样称呼:

    MyClass.Instance.DoStuff()
    
        3
  •  1
  •   Koshux    8 年前

    我一直在寻求 GameObject.FindGameObjectsWithTag 当我需要多个引用或者GameObject.FindWithTag当我只需要一个对系统中可用的特定GameObject的引用时。

    要引用上述GameObject上的脚本(可以使用上面的API引用找到),只需使用 GameObject.GetComponent API参考。

    一个完整的例子是:

    1. 为玩家的游戏对象分配一个标签,例如。 PlayerA .
    2. GameObject player = GameObject.FindWithTag("PlayerA");
    3. PlayerScript playerScript = player.GetComponent<PlayerScript>();

    我希望这有帮助,如果你需要进一步澄清,我将非常乐意帮助。

    编辑:另一个解决方案:

    关注:50或 x 玩家数量太多,无法分配标签。

    解决方案:如果您有一组50名玩家:

    1. 我会将它们分组到父游戏对象下。
    2. 给父游戏对象分配一个标签,例如。 ParentPlayer
    3. 使用 GetComponentsInChildren 参考资料。