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
中的最后一个参数 transform
是 Canvas
这个脚本,因为这是一个 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);
我制作了一个简单的消息框,它应该向用户显示一条消息。它是一个预制件,可以做一些事情,主要是动画实例化。对于实例化时的 运行 代码,我使用了 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
中的最后一个参数 transform
是 Canvas
这个脚本,因为这是一个 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);