我需要将事件从一个UnityEvent复制到另一个UnityEvent,因为一旦我弄清楚了这一点,我将在运行时将目标切换到另一个对象,到目前为止我所拥有的是:
MethodInfo info = UnityEventBase.GetValidMethodInfo (event1.GetPersistentTarget (i), event1.GetPersistentMethodName (i), Type.EmptyTypes);
UnityAction action = Delegate.CreateDelegate (typeof (UnityAction), info) as UnityAction;
event2.AddListener (action);
我得到ArgumentNullException: Argument cannot be null.
,如果我把Type.EmptyTypes
变成new Type[] { typeof (float) }
,我得到ArgumentException: method argument length mismatch
。
问题是,我不知道在那里放什么,因为我不知道类型是什么(因为Unity Events可以发送bool, float等)
Unity文档没有涉及到这一点,所以希望其他人在过去已经取得了成功。
这可以通过反射和递归复制UnityEvent类的每个值字段来实现。由于性能影响,我不会在运行时使用它,但对于编辑器来说,它非常有用。我使用一个静态助手类和一个扩展来克隆列表。
ReflectionHelper.cs
using System;
using System.Reflection;
using System.Collections;
using System.Collections.Generic;
namespace CEUtilities.Helpers
{
public static class ReflectionHelper
{
/// <summary>
/// Gets all fields from an object and its hierarchy inheritance.
/// </summary>
/// <param name="type">The type.</param>
/// <param name="flags">The flags.</param>
/// <returns>All fields of the type.</returns>
public static List<FieldInfo> GetAllFields(this Type type, BindingFlags flags)
{
// Early exit if Object type
if (type == typeof(System.Object))
{
return new List<FieldInfo>();
}
// Recursive call
var fields = type.BaseType.GetAllFields(flags);
fields.AddRange(type.GetFields(flags | BindingFlags.DeclaredOnly));
return fields;
}
/// <summary>
/// Perform a deep copy of the class.
/// </summary>
/// <typeparam name="T"></typeparam>
/// <param name="obj">The object.</param>
/// <returns>A deep copy of obj.</returns>
/// <exception cref="System.ArgumentNullException">Object cannot be null</exception>
public static T DeepCopy<T>(T obj)
{
if (obj == null)
{
throw new ArgumentNullException("Object cannot be null");
}
return (T)DoCopy(obj);
}
/// <summary>
/// Does the copy.
/// </summary>
/// <param name="obj">The object.</param>
/// <returns></returns>
/// <exception cref="System.ArgumentException">Unknown type</exception>
private static object DoCopy(object obj)
{
if (obj == null)
{
return null;
}
// Value type
var type = obj.GetType();
if (type.IsValueType || type == typeof(string))
{
return obj;
}
// Array
else if (type.IsArray)
{
Type elementType = type.GetElementType();
var array = obj as Array;
Array copied = Array.CreateInstance(elementType, array.Length);
for (int i = 0; i < array.Length; i++)
{
copied.SetValue(DoCopy(array.GetValue(i)), i);
}
return Convert.ChangeType(copied, obj.GetType());
}
// Unity Object
else if (typeof(UnityEngine.Object).IsAssignableFrom(type))
{
return obj;
}
// Class -> Recursion
else if (type.IsClass)
{
var copy = Activator.CreateInstance(obj.GetType());
var fields = type.GetAllFields(BindingFlags.Public | BindingFlags.NonPublic | BindingFlags.Instance);
foreach (FieldInfo field in fields)
{
var fieldValue = field.GetValue(obj);
if (fieldValue != null)
{
field.SetValue(copy, DoCopy(fieldValue));
}
}
return copy;
}
// Fallback
else
{
throw new ArgumentException("Unknown type");
}
}
}
}
UnityEventExtension.cs
using UnityEngine.Events;
using CEUtilities.Helpers;
namespace UnityEngine
{
public static class UnityEventExtension
{
/// <summary>
/// Clones the specified unity event list.
/// </summary>
/// <param name="ev">The unity event.</param>
/// <returns>Cloned UnityEvent</returns>
public static T Clone<T>(this T ev) where T : UnityEventBase
{
return ReflectionHelper.DeepCopy(ev);
}
}
}
然后可以这样使用
this.OnStart = target.OnStart.Clone();
我知道这是旧的,但我花了大部分时间在网上搜索,以帮助我写一些东西。最后我得到了这个简单的函数。这只会在编辑器中起作用(但话又说回来,你什么时候会想要这样做呢?)。
只要这是一个UnityEvent,它就会将unity事件及其参数值(对象,字符串,整数,浮点数,void和bool)从一个目标UnityEvent复制到另一个不同或相同组件上的UnityEvent。
如果你愿意,欢迎每个人下载它并在此基础上构建。点击这里查看:https://gist.github.com/wesleywh/1c56d880c0289371ea2dc47661a0cdaf
对于将来偶然发现这个的人来说,这是有效的:
MethodInfo info = UnityEventBase.GetValidMethodInfo (event1.GetPersistentTarget (i), event1.GetPersistentMethodName (i), new Type[] { typeof (float) });
UnityAction execute = () => info.Invoke (event1.GetPersistentTarget (i), new object[] { 180f });
event2.AddListener (execute);
它只是没有在检查器中暴露复制的侦听器,所以仍在寻找一个完美的解决方案。