2

我正在使用 Unity 5.4.2f2 Personal,并且我编写了一个类似于以下内容的 C# 脚本:

using UnityEngine;
using System;

public class Outer : MonoBehaviour {

    // Some public outer fields

    public class Inner : MonoBehaviour {
        // Some public inner fields
    }

}

我希望能够在我的场景中同时附加Outer和附加到游戏对象。Inner不幸的是Inner,即使我添加[Serializable]了它,它也不会在 Unity Inspector 中显示为可用脚本。我知道如果我试图让一个嵌套类对外界可见,很多人可能会说我的设置有问题,但是为了这个问题,我只想知道这是否可以做到。即,有没有办法使嵌套类可用作 Unity 组件?

4

5 回答 5

4

不,没有办法将嵌套类用作统一组件。要将 MonoBehaviour 类用作统一组件,类名必须与脚本的文件名相同,因此无法使用嵌套类。

如果您将外部类重命名为您想要的任何其他名称而不重命名脚本文件,您将看到也无法使用新的外部类。

[编辑]

我找到了文档。正如我所说:“类名和文件名必须相同才能使脚本组件附加到游戏对象。”

于 2016-11-09T20:12:55.260 回答
2

这个答案是错误的

至少它只是半正确的:

好的,是的,如果您的目标是通过 Inspector 的Add Component按钮使用和添加此组件,那么不需要位于具有匹配类名的单个脚本文件中!

但是,如果您仅通过脚本在运行时添加该组件,那么实际上可以这样做!

Unity 本身在Dropdown组件中执行此操作(摘自使用 Rider 反编译的源代码)

public class Dropdown : Selectable, IPointerClickHandler, ISubmitHandler, ICancelHandler
{
    protected internal class DropdownItem : MonoBehaviour, IPointerEnterHandler, ICancelHandler
    {
        ...
    }
    
    ...
}

Selectable继承自UIBehaviour哪个继承自MonoBehaviour

由于这种嵌套,它在运行时稍后在 Inspector 中看起来像这样

在此处输入图像描述

但绝对有可能!

为了证明这一点,您可以轻松地做同样的事情,例如

public class TEST : MonoBehaviour
{
    private class NESTED : MonoBehaviour
    {
        [SerializeField] private int someInt;
        [SerializeField] private Transform someReference;
    }

    [ContextMenu("Add NESTED component")]
    private void AddNested()
    {
        gameObject.AddComponent<NESTED>();
    }
}

所以你甚至可以在播放模式之外的编辑时间看到我可以通过上下文菜单简单地添加这个“隐藏”组件

在此处输入图像描述

并且它仍然是序列化的,并且在关闭并重新加载场景后仍然存在:

在此处输入图像描述

于 2021-08-10T12:41:38.347 回答
1

您不能通过统一标准菜单添加它。但是您可以通过脚本添加它。AddComponent<Outer.Inner>();

于 2021-04-23T06:03:01.080 回答
0

自从我提出这个问题以来,我学到了很多东西,所以我想我会添加更多信息。@luizcarlosfx 的答案@derHugo 的答案仍然是最正确的答案。

Unity 如何编译脚本

Unity 使用内置版本的 Mono 编译器(跨平台 C# 编译器)编译项目中的所有脚本。它为每个脚本文件(在关联.meta文件中)分配一个唯一的 GUID,就像它为每个其他资产所做的那样。这带来了一些很好的可用性改进:可以在不破坏现有脚本引用的情况下重命名类,因为 GUID 不会更改,并且脚本可以与其他相关资产一起分组在文件夹中(例如,所有“士兵”脚本/声音/纹理都可以组合在一起)。

Unity 的脚本命名限制

这种可用性的缺点是 Unity 强制执行一些命名限制:

  • 每个文件只有一个类,与文件同名,否则 Unity 将不知道在组件脚本引用中使用哪个 GUID
  • 没有嵌套类
  • TheBehaviour在名为的文件中没有命名类MyBehaviour.cs
  • 可能没有partial课程正如@derHugo 的评论中所述,这是可能的。部分声明可以在相同或不同的文件中,即使名称不同,只要其中一个文件名与类的名称匹配。

如果您在项目窗口中选择脚本资源并看到以下消息,那么您知道您正在尝试以 Unity 不支持的方式命名事物:

Unity 信息消息:文件中没有 MonoBehaviour 脚本,或者它们的名称与文件名不匹配。

但是,这些限制仅适用于从(或可能来自?)派生的公共类。MonoBehaviourUnityEngine.Object您可以在一个文件中拥有任意数量的其他 privateMonoBehaviourPOCO,因为 Unity 永远不会序列化它们,因此它们不需要自己的 GUID。标有 的公共 POCO[Serializable] 可能具有与公共 s 相同的命名限制MonoBehaviour......我没有测试过这个所以我不确定。为什么我没有测试这个?出色地...

使用托管插件避免这些限制

如果您和我一样,并且来自纯 .NET 背景,那么对于可以在哪些文件中定义哪些类的任何限制可能会让您抓狂。在这种情况下,您可以将脚本存储在 Unity 项目之外(我使用与 Unity 项目相同的存储库中的另一个文件夹),并使用 Visual Studio 或 JetBrains Rider 等 IDE 手动构建它们。然后可以将生成的程序集(.dll 和 .pdb 文件)作为托管插件复制到您的 Unity 项目中(最好通过一些自动化的构建后事件) 。然后您可以:

  • 根据需要为每个文件定义尽可能多的类
  • 使用您想要的任何命名约定
  • 使用嵌套类和partial类,随心所欲,与纯 .NET 相同
  • 为您的 POCO 编写不依赖于 Unity 或 Unity 测试框架的单元测试(它具有让您并行运行单元测试的绝佳好处;Unity 一次只能运行一个测试)
  • 您甚至可以使用您想要的任何 C# 版本(尽管某些语言功能需要 Unity 版本的 Mono 中不存在的运行时功能)。Unity 5.x 中的 C# 版本限制实际上是我最初选择此选项的原因!

不过,这绝对是一种更底层的脚本编写方法,需要更多的 C#、CLR、MSBuild 等知识。但是,如果您不怕弄脏自己的手,那么 Ashley Davis 有一篇很棒的文章,介绍了将 Visual Studio 设置为生成的托管插件,以及这种方法的优缺点。您还可以使用出色的Unity3D NuGet 包对源代码项目中的 Unity 程序集进行跨平台和面向未来的引用。

希望可以解决问题,并再次感谢以前的答案/评论!

于 2021-04-24T14:38:49.653 回答
-1

我不相信以前的答案是正确的。

您应该能够通过使用 [MenuItem] attr 创建和绑定 MonoBehaviour 的静态方法创建编辑器脚本来添加嵌套的组件。

这在 Unity 5 及更高版本中有效。

于 2018-12-10T23:03:42.827 回答