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函数来获取附加到它的脚本。
我注意到你提到你也想在场景中引用预制件。预制件和已经出现在场景中的对象之间存在差异,并且它们都有不同的引用方式。
这是场景中对象的示例。您可以在“层次结构”选项卡中看到它们:
让我们按名称引用“画布”游戏对象:
GameObject canvasObj = GameObject.Find("Canvas");
让我们参考Canvas附加到“画布”游戏对象的脚本:
GameObject canvasObj = GameObject.Find("Canvas");
Canvas canvas = canvasObj.GetComponent<Canvas>();
预制件:
以下是“项目”选项卡中的预制件示例:
将预制件放在名为“Resources”的文件夹中。您必须这样才能使用Resources
API引用它们。
让我们参考“Capsule”预制游戏对象:
GameObject prefab = Resources.Load<GameObject>("Capsule");
要使用它,您必须实例化它:
GameObject instance = Instantiate(prefab);
您只能在实例化后在预制件上获取组件:
CapsuleCollider cc = instance.GetComponent<CapsuleCollider>();
TA贡献1824条经验 获得超5个赞
当我需要多个引用时,我一直在寻求使用GameObject.FindGameObjectsWithTag,或者当我只需要对系统中可用的特定游戏对象的一个引用时,使用 GameObject.FindWithTag。
要在所述游戏对象上引用脚本(使用上面的 API 参考找到),您只需使用 `` 如GameObject.GetComponent API 参考中所述。
一个完整的例子是:
为您的玩家游戏对象分配一个标签,例如
PlayerA
。GameObject player = GameObject.FindWithTag("PlayerA");
PlayerScript playerScript = player.GetComponent<PlayerScript>();
我希望这会有所帮助,如果您需要进一步说明,我将非常乐意提供帮助。
编辑:另一个解决方案:
关注点:50 或 50x
名玩家太普通而无法分配标签。
解决方案:如果您有一组 50 名玩家:
我会将它们分组在父游戏对象下。
为父游戏对象分配一个标签,例如
ParentPlayer
使用GetComponentsInChildren参考。
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()
- 3 回答
- 0 关注
- 230 浏览
添加回答
举报