【问题标题】:Unity - pass parameters on instantiationUnity - 在实例化时传递参数
【发布时间】:2018-12-31 09:41:29
【问题描述】:

我制作了一个简单的消息框,它应该向用户显示一条消息。它是一个预制件,做了几件事,主要是实例化时的动画。为了在实例化时运行代码,我使用了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:

Instantiation 中的最后一个参数transformCanvas,因为这是一个 UI 脚本,所以此脚本已启用。该参数意味着新实例化的GameObject 是它的子节点。

EDIT3:

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

【问题讨论】:

  • 显示要简化的三行代码会很有意义。
  • 很公平,马上编辑。
  • 抱歉是 4 行,我断了一行。
  • 没关系。最后一个参数说“转换”。那是什么,是什么类型?
  • 再次编辑:D我真的应该学会第一次表达自己

标签: c# unity3d instantiation


【解决方案1】:

您可以使用函数或扩展方法来做到这一点。

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

我们将使用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");
    }
}

【讨论】:

  • 所以基本上把它包起来。好方法,因为我可能会通过复制粘贴 3 行来犯一些错误(而且我真的很讨厌复制粘贴)。谢谢!
  • 是的。您不需要复制它,它现在是 GameObject/Transform 类的一部分。从项目中的任何脚本中,您可以执行 gameObject.Instantiate(messageBox, penaltySpawnLoc.position, penaltyPrefab.transform.rotation, transform, "Hello");transform.Instantiate(messageBox, penaltySpawnLoc.position, penaltyPrefab.transform.rotation, transform, "Hello"); 而不是执行 YourOtherClass.Instantiate...
  • 我会在这里使用GameObject而不是Object,因为Instantiate只能在GameObjects上调用
【解决方案2】:

我会为消息框使用工厂,比如

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

【讨论】:

    【解决方案3】:

    今天遇到这个问题并想出了这个。这个想法是用自定义方法替换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&lt;T&gt; 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);
    

    【讨论】:

      猜你喜欢
      • 1970-01-01
      • 1970-01-01
      • 1970-01-01
      • 2015-08-29
      • 1970-01-01
      • 2014-11-24
      • 2016-02-13
      • 1970-01-01
      • 1970-01-01
      相关资源
      最近更新 更多