C# 当所有玩家都有相同的名字时查找localPlayer
当涉及到将玩家引用到另一个对象的脚本时,Unity让我感到困惑。我使用了几种方法来引用localPlayer对象:C# 当所有玩家都有相同的名字时查找localPlayer,c#,unity3d,networking,reference,C#,Unity3d,Networking,Reference,当涉及到将玩家引用到另一个对象的脚本时,Unity让我感到困惑。我使用了几种方法来引用localPlayer对象: 比较标记(在某些情况下不太好) gameObject.Name(从未使用过,但也不可靠) 分配公共游戏对象玩家在inspector中拖放(当玩家是预制玩家时面临问题) 制作公共静态[PlayerControllerClass]实例并在void Start()函数中设置instance=this 是否有其他合适的方法来引用玩家 注意:我知道我的问题可能与具体问题无关,但如果有人愿意帮
gameObject.Name
(从未使用过,但也不可靠)公共游戏对象玩家代码>在inspector中拖放(当玩家是预制玩家时面临问题)
公共静态[PlayerControllerClass]实例
并在void Start()
函数中设置instance=this
代码>localPlayer
,其中所有玩家都有相同的名字、相同的标签,但只有一个玩家是localPlayer。我可以从另一个脚本访问localPlayer
Edit2:我接受的答案是我感觉最好的答案。我将使用预览localPlayer
的score text
中提供的答案,通过从一组玩家访问它[localPlayer
]
我推荐单例模式。我在几乎所有的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();
}
在编辑之前,你的问题并不清楚,然后我意识到这是一个网络问题 我需要在网络游戏中找到所有玩家都拥有的本地玩家 相同的名字,相同的标签,但只有一个玩家是本地玩家,我可以访问 来自另一个脚本的localPlayer 您可以找到具有
NetworkConnection.playerControllers
的玩家,该玩家将返回PlayerController
的列表,然后在其上循环并检查其是否有效。之后,从中获取NetworkBehavior并检查IsLocalLayer属性。就是这样
大概是这样的:
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;
}
您可能需要的其他有用的播放器操作:
查找所有玩家:
让我们将Canvas
脚本附件引用到“Canvas”游戏对象:
GameObject canvasObj = GameObject.Find("Canvas");
Canvas canvas = canvasObj.GetComponent<Canvas>();
GameObject prefab = Resources.Load<GameObject>("Capsule");
要使用它,您必须实例化它:
GameObject instance = Instantiate(prefab);
只有在实例化组件之后,才能在预制件上获取组件:
CapsuleCollider cc = instance.GetComponent<CapsuleCollider>();
CapsuleCollider cc=instance.GetComponent();
当我需要多个引用时,我总是寻求使用,或者当我只需要系统中可用的特定游戏对象的一个引用时,使用GameObject.FindWithTag
要引用上述游戏对象上的脚本(使用上面的API引用找到),只需使用API引用中描述的``
一个完整的例子是:
PlayerA
gameobjectplayer=GameObject.FindWithTag(“PlayerA”)代码>
PlayerScript PlayerScript=player.GetComponent()代码>
x
玩家的数量太普通,无法分配标签
解决方案:如果您有一组50名玩家:
ParentPlayer
你的意思是在场景和层次选项卡中引用对象?是的,我的意思是我想通过使用GameObject.Find()来访问其他对象,如预设(预设,UI,…),如果对象有唯一的名称:)有
FindObjectOfType
,然后可以使用。GameObject
打开。对于localPlayer
部分,您的网络使用什么NetworkBehavior
具有IsLocalLayer
属性(其他如OnStartLocalPlayer
,请参阅我将要搜索的关于Singleton
的文档我已经看过多次但没有深入研究过这个词。它不适合所有场景,但它确实使处理GameManager、InventoryManager等类时的工作变得更轻松。这些类都不应该有超过1个实例。请随意使用我文章中的第一个代码片段。它已经可以使用了。谢谢你的回答,你已经接近我所需要的了,但是我需要知道一些事情。是否可以让每个标签都有50个标签,每个标签旁边都有玩家字母,每个玩家的标签都不同于其他人。我不认为这是解决方案。这是真的y视情况而定。如果你有一组50名玩家,我会将他们分组在一个父游戏对象下,给该父游戏对象一个标记,例如ParentPlayer
,然后使用引用。好的,现在根据我的理解,我必须实例化父游戏对象中的所有玩家(EmptyGameObject
)然后浏览这些游戏对象,以了解哪一个是本地玩家?您是否假设只有一个名为localPlayer
?谢谢这解释了很多。为回答干杯!对于旧答案:我不擅长编码,但我得到的方式是,从资源文件夹加载预制并不总是最好的方式继续,特别是对于大型预制件(Resource.Load从磁盘加载预制件)。顺便说一句,由于编辑器在内存中加载资源文件夹,所以在编辑器中不会注意到这种减速。如果在inspector中直接引用预制件,unity将创建一个原型实例,并在实例化时从中“加载”(ofc价格是原型占用的内存)。@Nikaas是的,没错。使用。新用户使用AssetBundle的过程有点复杂,但更好。
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 canvasObj = GameObject.Find("Canvas");
GameObject canvasObj = GameObject.Find("Canvas");
Canvas canvas = canvasObj.GetComponent<Canvas>();
GameObject prefab = Resources.Load<GameObject>("Capsule");
GameObject instance = Instantiate(prefab);
CapsuleCollider cc = instance.GetComponent<CapsuleCollider>();