Que*_*n3r 8 c# unity-game-engine
GameObjects我场景中的一些实现了交互ISaveable。在我的脚本中,我想找到所有这些接口并存储它们。稍后我可以遍历它们并调用它们的实现方法SaveData()。
我目前找到这些接口的解决方法:
List<ISaveable> saveables = new List<ISaveable>();
MonoBehaviour[] sceneObjects = FindObjectsOfType<MonoBehaviour>();
for (int i = 0; i < sceneObjects.Length; i++)
{
MonoBehaviour currentObj = sceneObjects[i];
ISaveable currentComponent = currentObj.GetComponent<ISaveable>();
if (currentComponent != null)
{
saveables.Add(currentComponent);
}
}
Run Code Online (Sandbox Code Playgroud)
代码工作正常,但有更好的方法吗?我不想在场景中搜索每个 Monobehaviour 然后尝试获取其界面组件。
您可以使用LinqOfType
ISaveable[] saveables = FindObjectsOfType<MonoBehaviour>().OfType<ISaveable>().ToArray();
Run Code Online (Sandbox Code Playgroud)
当然还是需要先找到所有的对象。
但请注意,它是FindObjectsOfType关于非活动游戏对象或禁用行为的一般限制的基础。
您可以扩展它以遍历场景的所有根级别对象。这是有效的,因为 afaikGetComponentsInChildren确实也适用于接口!
var saveables = new List<ISaveable>();
var rootObjs = SceneManager.GetActiveScene().GetRootGameObjects();
foreach(var root in rootObjs)
{
// Pass in "true" to include inactive and disabled children
saveables.AddRange(root.GetComponentsInChildren<ISaveable>(true));
}
Run Code Online (Sandbox Code Playgroud)
如果它更有效 - 是的,不,也许,我不知道 - 但它也包括非活动和禁用的对象。
是的,可以使用以下方法扩展它以遍历多个加载的场景
var saveables = new List<ISaveable>();
for(var i = 0; i < SceneManager.sceneCount; i++)
{
var rootObjs = SceneManager.GetSceneAt(i).GetRootGameObjects();
foreach(var root in rootObjs)
{
saveables.AddRange(root.GetComponentsInChildren<ISaveable>(true));
}
}
Run Code Online (Sandbox Code Playgroud)
这个替代方案有点类似于这个答案,但它有一个巨大的缺陷:你需要一个特定的接口实现才能使它工作,这使接口的整个想法无效。
所以评论中的一个大问题是:为什么要有一个界面?
如果它无论如何只用于MonoBehaviour你应该abstract class喜欢
public abstract class SaveableBehaviour : MonoBehaviour
{
// Inheritors have to implement this (just like with an interface)
public abstract void SaveData();
}
Run Code Online (Sandbox Code Playgroud)
这已经解决了FindObjectsOfType无论如何使用的整个问题,因为现在您可以简单地使用
SaveableBehaviour[] saveables = FindObjectsOfType<SaveableBehaviour>();
Run Code Online (Sandbox Code Playgroud)
但您仍然可以更进一步:为了更轻松、更有效地访问,您可以让它们完全注册自己,而无需管理器或单例模式!为什么类型不应该简单地处理它的实例本身?
public abstract class SaveableBehaviour : MonoBehaviour
{
// Inheritors have to implement this (just like with an interface)
public abstract void SaveData();
private static readonly HashSet<SaveableBehaviour> instances = new HashSet<SaveableBehaviour>();
// public read-only access to the instances by only providing a clone
// of the HashSet so nobody can remove items from the outside
public static HashSet<SaveableBehaviour> Instances => new HashSet<SaveableBehaviour>(instances);
protected virtual void Awake()
{
// simply register yourself to the existing instances
instances.Add(this);
}
protected virtual void OnDestroy()
{
// don't forget to also remove yourself at the end of your lifetime
instances.Remove(this);
}
}
Run Code Online (Sandbox Code Playgroud)
所以你可以简单地继承
public class Example : SaveableBehaviour
{
public override void SaveData()
{
// ...
}
protected override void Awake()
{
base.Awake(); // Make sure to always keep that line
// do additional stuff
}
}
Run Code Online (Sandbox Code Playgroud)
你可以通过访问该类型的所有实例
HashSet<SaveableBehaviour> saveables = SaveableBehaviour.Instances;
foreach(var saveable in saveables)
{
saveable.SaveData();
}
Run Code Online (Sandbox Code Playgroud)
拥有全局状态(也许是 的列表)ISaveable,并让每个可保存对象在 期间添加对其的引用怎么样start()?然后您可以简单地迭代数组,调用SaveData()每个ISaveable引用?
| 归档时间: |
|
| 查看次数: |
9543 次 |
| 最近记录: |