Unity 中实用的 C# 扩展方法

Unity 内置组件基本没有可以继承的。某些比较常用但现有 API 没有定义的功能,我们可以通过 C# 的扩展类方法来实现(注意一点,扩展方法对于值类型传递的不是引用,所以无法修改原对象、并且传递体积较大的值类型可能造成性能问题)。下面是一些比较实用的扩展方法,这些扩展方法的实现很多使用了 C# 的委托,关于委托可以参考这里:C# 中的 delegate, Lambda 和 event。扩展 Transform每一个 GameObject 都含有一个 Transform 组件(在 UGUI 里新引入的 RectTransform 继承 Transform),GameObject 的层级也是由 Transform 负责的。

/// summary/// (深度优先)遍历 Transform 层级, 对每一个访问的节点执行一个自定义的操作/// /summary/// param name="root"遍历开始的根部 Transform 对象/param/// param name="operate"遍历到每一个节点时将调用此方法; 参数1: 当前访问的对象; 参数2: 包括本层次在内的剩余深度限制/param/// param name="depthLimit"遍历深度限制, 负值表示不限制, 0 表示只访问 root 本身而不访问其子级, 正值表示最多访问的子级层数/parampublic static void TraverseHierarchy(this Transform root, ActionTransform, int operate, int depthLimit = -1){if (operate != null){operate(root, depthLimit);if (depthLimit == 0) return;for (int i = root.childCount – 1; i = 0; i–){TraverseHierarchy(root.GetChild(i), operate, depthLimit – 1);}}}/// summary/// (深度优先)遍历 Transform 层级, 对每一个访问的节点执行一个自定义的操作, 如果此操作返回一个非空引用将终止遍历过程, 并且此返回值最终作为遍历方法的返回值/// /summary/// param name="root"遍历开始的根部 Transform 对象/param/// param name="operate"遍历到每一个节点时将调用此方法; 参数1: 当前访问的对象; 参数2: 包括本层次在内的剩余深度限制; 返回值: null 表示继续遍历, 非空引用将终止遍历过程, 并且此返回值最终作为遍历方法的返回值/param/// param name="depthLimit"遍历深度限制, 负值表示不限制, 0 表示只访问 root 本身而不访问其子级, 正值表示最多访问的子级层数/param/// returns第一次 operate 返回的非空引用或 null/returnspublic static object TraverseHierarchy(this Transform root, FuncTransform, int, object operate, int depthLimit = -1){if (operate != null){object obj = operate(root, depthLimit);if (obj != null || depthLimit == 0) return obj;for (int i = root.childCount – 1; i = 0; i–){obj = TraverseHierarchy(root.GetChild(i), operate, depthLimit – 1);if (obj != null) return obj;}}return null;}

这两个扩展方法都使用了递归实现,都可以遍历所有的子物体。第一个扩展方法典型使用场景是:更改所有子物体的 Layer;第二个扩展方法带有返回值,随时可以终止遍历,典型的使用场景是:搜索特定的子物体并返回它的引用。扩展 MonoBehaviour在 Unity 里使用协程有时可以让程序更简洁。比如使用协程可以方便的延迟执行一些代码。MonoBehaviour 内置的 Invoke 仅支持字符串参数,下面这个扩展可以使用委托。

/// summary/// 延时调用指定的方法/// /summary/// param name="monoBehaviour"协程附着的脚本对象/param/// param name="seconds"延迟的秒数/param/// param name="method"延时结束调用的方法/parampublic static void Invoke(this MonoBehaviour monoBehaviour, float seconds, Action method){if (method != null){monoBehaviour.StartCoroutine(DelayCall(seconds, method));}}private static IEnumerator DelayCall(float seconds, Action method){yield return new WaitForSeconds(seconds);method();}如果你需要等待 UI 动画完成后再打开输入,以后或许可以用这个了。扩展 Camera如果你正在做 2D 游戏,可能需要清楚的了解你的Sprite 和屏幕的大小关系。下面这两个扩展可以方便的获得像素和世界单位之间互相转换的系数。/// summary/// 计算正交相机屏幕上,每像素的世界单位(单位:米)大小/// /summary/// param name="camera"正交相机对象/param/// returns每像素的世界单位大小/returnspublic static float UnitsPerPixel(this Camera camera){return camera.orthographicSize * 2 / Screen.height;}/// summary/// 计算正交相机屏幕上,每世界单位(单位:米)的像素大小/// /summary/// param name="camera"正交相机对象/param/// returns每世界单位的像素大小/returnspublic static float PixelsPerUnit(this Camera camera){return Screen.height * 0.5f / camera.orthographicSize;}

不同屏幕的像素大小差别很大,在处理触屏输入时,你可能需要把像素转换成世界大小再判断用户的操作意图。扩展反射方法Unity 可定制的编辑器为开发提高了效率,但是在使用上却经常遇到各种问题。比如编辑器类需要访问编辑对象的私有成员。下面这些反射相关方法有时可以用来解决这些问题。

/// summary/// 反射扩展/// /summarypublic static class ReflectionExtension{public static object GetPrivateField(this object instance, string fieldName){return instance.GetType().GetField(fieldName, BindingFlags.Instance | BindingFlags.NonPublic).GetValue(instance);}public static object GetPrivateProperty(this object instance, string propertyName){return instance.GetType().GetProperty(propertyName, BindingFlags.Instance | BindingFlags.NonPublic).GetValue(instance, null);}public static void SetPrivateField(this object instance, string fieldName, object value){instance.GetType().GetField(fieldName, BindingFlags.Instance | BindingFlags.NonPublic).SetValue(instance, value);}public static void SetPrivateProperty(this object instance, string propertyName, object value){instance.GetType().GetProperty(propertyName, BindingFlags.Instance | BindingFlags.NonPublic).SetValue(instance, value, null);}public static object InvokePrivateMethod(this object instance, string methodName, params object[]param){return instance.GetType().GetMethod(methodName, BindingFlags.Instance | BindingFlags.NonPublic).Invoke(instance, param);}}

声明:此篇文档时来自于【狗刨学习网】社区-unity极致学院,,是网友自行发布的Unity3D学习文章,如果有什么内容侵犯了你的相关权益,请与官方沟通,我们会即时处理。

偶尔,我一个人站在黄昏的荒野,

Unity 中实用的 C# 扩展方法

相关文章:

你感兴趣的文章:

标签云: