Unity - 在实例化时传递参数

Unity - pass parameters on instantiation

我制作了一个简单的消息框,它应该向用户显示一条消息。它是一个预制件,可以做一些事情,主要是动画实例化。对于实例化时的 运行 代码,我使用了 Start() 函数。 当我已经知道要发送什么消息但我需要类似 constructor 的东西时它起作用了,在 Start() 之前 运行s 但在 instantiation 之后并且可以接受参数。 现在,我完全意识到我可以实例化、设置消息和 运行 一切——所以在我实例化它的地方使用 3 行代码,但我很好奇是否还有另一个更合适的解决方案?我在网上找到的只是实例化,然后做一些事情。

编辑:

我调用显示的消息框:

var timeBox =
    Instantiate(messageBox, penaltySpawnLoc.position, penaltyPrefab.transform.rotation, transform);
    var scr = timeBox.GetComponent<MessageBox>();
    scr.OnCreated(message);

OnCreated 进行初始化,显示动画,所以基本上一切。 但它 需要 一个 string 输入来知道要显示什么,我不想设置文本值 "on the fly" - 它会出现一些奇怪的闪烁当消息框可见但未设置文本时。

编辑2:

Instantiation 中的最后一个参数 transformCanvas 这个脚本,因为这是一个 UI 脚本。该参数意味着新实例化的 GameObject 是它的子项。

编辑3:

timeBox只是messageBox的一个实例,它们是GameObject。 一个消息框 只使用一次。 它的目的是与消息一起出现,并在大约 0.5 秒后淡出并离开。离开后它会自我毁灭。

我会为消息框使用 Factory,比如

var timebox = MessageBoxFactory.Create(message);
timebox.Show();

并在工厂中 class 进行设置并 return 消息框

public static MessageBox Create(string message) {
   var newTimeBox = Instantiate(messageBox, penaltySpawnLoc.position, penaltyPrefab.transform.rotation, transform);
   var scr = newTimeBox.GetComponent<MessageBox>();
   scr.SetMessage(message);
   return scr;

其中 Show() 是新的 OnCreated()。我发现这种模式有助于减少调用代码,如果我需要调整我想要的东西的创建方式,它与共享工厂代码都在一个地方。

您可以使用函数或扩展方法来完成此操作。

在这种情况下,扩展方法更合适。

我们将使用 Object 而不是 GameObject 创建一个扩展对象。由于 GameObject 继承自 Object,因此此扩展方法应该适用于 Object、GameObject 和 Transform。

创建一个名为 ExtensionMethod 的 class,然后将下面的所有内容粘贴到其中。

using UnityEngine;

public static class ExtensionMethod
{
    public static Object Instantiate(this Object thisObj, Object original, Vector3 position, Quaternion rotation, Transform parent, string message)
    {
        GameObject timeBox = Object.Instantiate(original, position, rotation, parent) as GameObject;
        MessageBox scr = timeBox.GetComponent<MessageBox>();
        scr.OnCreated(message);
        return timeBox;
    }
}

用法:

Start 函数中只有一行调用可以处理所有其他任务。

public class Test: MonoBehaviour
{
    GameObject messageBox = null;
    Transform penaltySpawnLoc = null;
    GameObject penaltyPrefab = null;

    void Start()
    {
        gameObject.Instantiate(messageBox, penaltySpawnLoc.position, penaltyPrefab.transform.rotation, transform, "Hello");
    }
}

今天遇到这个问题,想出了这个。这个想法是用自定义方法替换 Start() 方法并实现一个包装器,该包装器将您的预制件及其脚本的构造函数作为其(包装器)构造函数的参数,然后让包装器实例化并调用您的构造函数。您可以修改它以支持更多由 unity 提供的重载,但现在它对我来说工作得很好。

EditableGO.cs:

public class EditableGO<T>
{
    GameObject toInstantiate;
    Action<T> constructor;

    public EditableGO(Action<T> constructor, GameObject toInstantiate = null)
    {
        this.constructor = constructor;
        this.toInstantiate = toInstantiate == null? new GameObject() : toInstantiate;
    }

    public GameObject Instantiate(Vector3 position, Quaternion rotation, Transform parent = null)
    {
        GameObject instance;
        if(parent != null)
            instance = GameObject.Instantiate(toInstantiate, position, rotation, parent);
        else
            instance = GameObject.Instantiate(toInstantiate, position, rotation);

        constructor(instance.GetComponent<T>());

        return instance;
    }
}

为了将 Action<T> constructor 传递给 EditableGO 的构造函数,我所做的是实现一个静态构造函数生成器。这是一个简单的可自定义粒子示例,请注意构造函数生成器:

public class SimpleParticle : MonoBehaviour
{
    public float Duration, Distance, Speed, traveledDistance, birth;
    public Vector3 Direction, Size;

    public static Action<SimpleParticle> ConstructorGenerator(float duration, float distance, Vector3 size, float speed, Vector3 direction)
    {
        return (self) => {
            self.Duration = duration;
            self.Distance = distance;
            self.Size = size;
            self.Direction = direction;
            self.Speed = speed;
            self.Init();
        };
    }

    void Init()
    {
        birth = Time.time;
        transform.localScale = Size;
    }

    void Update()
    {
        float deltaDist =  Speed * Time.deltaTime;
        traveledDistance += deltaDist;
        transform.position += Direction * deltaDist;

        if(Time.time - birth > Duration)
            Destroy(this.gameObject);
    }
}

然后,实例化新的自定义粒子就像

一样简单
EditableGO<SimpleParticle> particle = new EditableGO<SimpleParticle>(SimpleParticle.ConstructorGenerator(duration, distance, size, speed, direction), Game.Resources.SimpleParticle);
particle.Instantiate(position, rotation);