为了账号安全,请及时绑定邮箱和手机立即绑定

当所有玩家的名字都相同时,查找 localPlayer

当所有玩家的名字都相同时,查找 localPlayer

C#
慕神8447489 2021-10-24 19:13:44
当涉及到将玩家引用到另一个对象的脚本时,Unity 让我感到困惑。我使用了几种方法来引用 localPlayer 对象:比较标签(在某些情况下不太好)gameObject.Name(没用过但也不靠谱)public GameObject Player;在检查器拖放中分配(当播放器是预制件时会遇到问题)在函数中制作public static [PlayerControllerClass] instance;和设置instance = this。void Start()为了playerSpeed从另一个脚本访问我做PlayerControllerClass.instance.playerSpeed = 10;是否有其他解决方案可以以适当的方式引用玩家。注意:我知道我的问题可能与特定问题无关,但如果有人会提供帮助,我可以解释更多。Edit1:例如我想localPlayer在一个 NetworkGame 中找到所有玩家都具有相同名称、相同标签但只有一个玩家是 localPlayer 的。我可以localPlayer从另一个脚本访问吗?Edit2:我接受的答案是我感觉最好的答案。我将使用预览score text中提供的答案,方法是localPlayer从一组玩家 [ localPlayer]
查看完整描述

3 回答

?
神不在的星期二

TA贡献1963条经验 获得超6个赞

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


我需要在 NetworkGame 中找到 localPlayer,其中所有玩家都具有相同的名称、相同的标签但只有一个玩家是 localPlayer 我可以从另一个脚本访问 localPlayer 吗?


您可以找到使用NetworkConnection.playerControllers哪些 retruens List of PlayerControllerthen 循环遍历它并检查它是否有效的玩家。之后,从中获取 NetworkBehaviour 检查 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,只需获取NetworkIdentity并检查isLocalPlayer属性。您还可以找到 GameObject 然后检查NetworkIdentity和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可以使用找到 GameObject ,然后,您可以使用该GetComponent函数来获取附加到它的脚本。


我注意到你提到你也想在场景中引用预制件。预制件和已经出现在场景中的对象之间存在差异,并且它们都有不同的引用方式。


这是场景中对象的示例。您可以在“层次结构”选项卡中看到它们:

//img1.sycdn.imooc.com//617540150001b1d002750291.jpg

让我们按名称引用“画布”游戏对象:


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

让我们参考Canvas附加到“画布”游戏对象的脚本:


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

Canvas canvas = canvasObj.GetComponent<Canvas>();

预制件:


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

//img1.sycdn.imooc.com//617540220001431704640243.jpg

将预制件放在名为“Resources”的文件夹中。您必须这样才能使用ResourcesAPI引用它们。

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

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

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

GameObject instance = Instantiate(prefab);

您只能在实例化后在预制件上获取组件:

CapsuleCollider cc = instance.GetComponent<CapsuleCollider>();


查看完整回答
反对 回复 2021-10-24
?
沧海一幻觉

TA贡献1824条经验 获得超5个赞

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

要在所述游戏对象上引用脚本(使用上面的 API 参考找到),您只需使用 `` 如GameObject.GetComponent API 参考中所述。

一个完整的例子是:

  1. 为您的玩家游戏对象分配一个标签,例如PlayerA

  2. GameObject player = GameObject.FindWithTag("PlayerA");

  3. PlayerScript playerScript = player.GetComponent<PlayerScript>();

我希望这会有所帮助,如果您需要进一步说明,我将非常乐意提供帮助。

编辑:另一个解决方案:

关注点:50 或 50x名玩家太普通而无法分配标签。

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

  1. 我会将它们分组在父游戏对象下。

  2. 为父游戏对象分配一个标签,例如 ParentPlayer

  3. 使用GetComponentsInChildren参考。


查看完整回答
反对 回复 2021-10-24
?
慕桂英3389331

TA贡献2036条经验 获得超8个赞

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


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()


查看完整回答
反对 回复 2021-10-24
  • 3 回答
  • 0 关注
  • 230 浏览

添加回答

举报

0/150
提交
取消
意见反馈 帮助中心 APP下载
官方微信