Unity - 在实例化时传递参数

时间:2017-02-11 18:44:21

标签: c# unity3d instantiation

我制作了一个简单的消息框,它应该向用户显示一条消息。这是一个预制件并做了几件事,主要是动画在实例化时。为了在实例化时运行代码,我使用了Start()函数。 当我已经知道要发送消息但我需要constructor之类的内容时,它会在Start()之前运行,但在instantiation之后可以使用参数。 现在,我完全知道我可以实例化,设置消息并运行所有内容 - 所以使用3行代码我实例化它,但我很好奇是否有另一个更合适的解决方案?我在网上找到的只是实例化,然后做点什么。

修改

我打电话给消息框显示:

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

OnCreated进行初始化,显示动画,基本上都是如此。 但它需要一个string输入来知道要显示什么,我不想“动态”设置文本值 - 当消息框出现时会出现一些奇怪的闪烁是可见的但文本未设置。

EDIT2:

transform中的最后一个参数Instantiation是此脚本所在的Canvas,因为这是一个UI脚本。该参数意味着新近实例化的GameObject是其中的孩子。

EDIT3:

timeBox只是messageBox的一个实例,它们是GameObject个。 一个消息框仅使用一次。其目的是显示消息,然后在0.5秒后淡出并移开。离开后它会摧毁自己。

3 个答案:

答案 0 :(得分:4)

您可以使用函数或扩展方法执行此操作。

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

我们将使用Object而不是GameObject制作扩展程序对象。由于GameObject继承自Object,因此该扩展方法应该适用于Object,GameObject和Transform。

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

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");
    }
}

答案 1 :(得分:1)

我在消息框中使用Factory,所以像

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

并在工厂类中进行设置并返回消息框

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()。我发现这种模式有助于减少调用代码,如果我需要调整我想要的东西如何被创建,它就在一个地方,共享工厂代码。

答案 2 :(得分:1)

今天遇到了这个问题,并提出了解决方案。这个想法是用自定义方法替换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);