【问题标题】:Unity - passing script by reference from editor, instantiating it on object at runtimeUnity - 从编辑器通过引用传递脚本,在运行时在对象上实例化它
【发布时间】:2019-10-21 07:49:36
【问题描述】:

所以基本上我想以几个游戏对象结束,每个对象都有几个具有单一行为的 .cs 脚本。 (每个对象上的不同脚本集)

各式各样的角色

每个角色的脚本会随时间变化

角色学习新技能/抛弃旧技能

所以当游戏开始时,我想在运行时动态地将脚本附加到对象上

基于技能树中的玩家决策

有什么方法可以在不使用反射的情况下做到这一点?

编辑:我似乎找到了如何让它在没有反射的情况下工作的解决方案

public class TestSkill : MonoBehaviour {}

public class TestFireball : TestSkill {}
public class TestMeleeAttack : TestSkill {}

public class TestSkillBook : MonoBehaviour {

    public MonoScript script;

    void Start () {

        System.Type t = script.GetClass();

        TestSkill skill = gameObject.AddComponent(t) as TestSkill;

    }

}

【问题讨论】:

  • 我很难理解您的问题。您能否尝试更清楚地重写它? (粗体和斜体目前也无助于使任何内容更清晰。)
  • 问题在我这边,我不太擅长解释:) 基本上,我想将脚本动态附加到对象,但我事先不知道我会附加哪些脚本。
  • 你现在明白还是我应该澄清更多?
  • 恐怕不是。用代码给出一个具体的例子会有很大帮助。
  • 我的代码有数千行。但我会从不同的角度尝试。我知道如何使用游戏对象变量创建一个类,将其放在预制件上,在统一编辑器中填充变量,然后将其传递给另一个脚本运行时。我想对脚本类型做同样的事情。

标签: c# unity3d


【解决方案1】:

我想在运行时动态地将脚本附加到对象上。

AddComponent 函数用于将脚本附加到游戏对象。

你的对象

public GameObject yourgameObject;

附加脚本:

yourgameObject.AddComponent<YourScript>();

编辑:

问题是,我不知道它是 MyScript1 还是 MyScript2。我 不希望它被硬编码,但可以通过编辑器/游戏 UI 进行修改。

我认为您正在寻找可以将string 作为参数的AddComponent。 曾经有一个像this

public Component AddComponent(string className);

但它在几年前已被弃用。我去年做了一个名为AddComponentExt的新扩展方法,你可以得到它here。可以这样使用:

yourgameObject.AddComponentExt<"YourScript">();

即使脚本尚不存在,您也可以添加它。在这种情况下,您将得到运行时错误而不是编译时错误。

有什么方法可以在不使用反射的情况下做到这一点?

,你不能在没有反射的情况下做到这一点,因为它还不存在。这就是反射的用途。

【讨论】:

  • 是的,但是我如何获得对 MyScript 的引用?
  • 假设你的脚本被称为YourScript,你用yourgameObject.AddComponent&lt;YourScript&gt;();将它附加到你的游戏对象上。哪一部分让您感到困惑?
  • 问题是,我不知道是MyScript1 还是MyScript2。我不希望它被硬编码,但可以通过编辑器/游戏 UI 进行修改。
  • 我还没有找到像其他变量类型一样传递它的方法
  • 感谢您的扩展方法。请澄清一下:为什么可以通过带有某个类的游戏对象将变量从编辑器传递到运行时,但我不能与脚本一样?就像通过 MonobehaviorScript 变量这样的东西传递它?
【解决方案2】:

由于这不适合程序员回答的 cmets,所以举一些例子并澄清您可以/必须做什么:

// The component to add
public class B : MonoBehaviour
{
    public void TestCall()
    {
        Debug.Log("Success");
    }
}




public class A : MonoBehaviour
{
    public string ToAddName = "B";

    private void Start()
    {
        System.Type t = System.Type.GetType(ToAddName);
        AddComponent(t);    // This does successfully add the component (assuming it exists)

        Debug.Log(t.GetType());    // This will give out "System.MonoType"

        // This doesn't work since it is not known that this is actually "B", not "MonoScript"
        GetComponent(t).TestCall();

        // What is possible is this, requires hardcoding the method name though:
        System.Reflection.MethodInfo mI = t.GetMethod("TestCall");
        var c = GetComponent(t);
        mI.Invoke(c, null);    // null because "TestCall" doesn't take params
    }
}

这并不意味着是一个实际的解决方案,我宁愿说可能有一种(更好的)方法来设置你的整个构造,这样你根本就不会遇到这个问题。

【讨论】:

  • 适用于自定义类,但不适用于 AudioSource 等内置类。 string ToAddName = "AudioSource"; 会失败
  • @PerformanceFreak 这并不是一个实际的答案,但是一些引用程序员答案的 cmets 的示例代码应该是这样写的。否则 OP 似乎只想添加他的自定义组件(或者至少那些是有问题的组件)。
  • @GunnarB。看来我找到了不需要反思的解决方案。检查我的编辑。
  • @Colp 这是我在程序员的 cmets 中提到的解决方案:casting。
猜你喜欢
  • 1970-01-01
  • 1970-01-01
  • 1970-01-01
  • 1970-01-01
  • 2017-12-07
  • 2018-05-07
  • 1970-01-01
  • 2016-04-01
  • 1970-01-01
相关资源
最近更新 更多