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 本身而不访问其子级, 正值表示最多访问的子级层数/param

public 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/returns

public 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"延时结束调用的方法/param

public 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每像素的世界单位大小/returns

public static float UnitsPerPixel(this Camera camera)

{

return camera.orthographicSize * 2 / Screen.height;

}

/// summary

/// 计算正交相机屏幕上,每世界单位(单位:米)的像素大小

/// /summary

/// param name="camera"正交相机对象/param

/// returns每世界单位的像素大小/returns

public static float PixelsPerUnit(this Camera camera)

{

return Screen.height * 0.5f / camera.orthographicSize;

}

不同屏幕的像素大小差别很大,在处理触屏输入时,你可能需要把像素转换成世界大小再判断用户的操作意图。

扩展反射方法

Unity 可定制的编辑器为开发提高了效率,但是在使用上却经常遇到各种问题。比如编辑器类需要访问编辑对象的私有成员。下面这些反射相关方法有时可以用来解决这些问题。

/// summary

/// 反射扩展

/// /summary

public 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学习文章,如果有什么内容侵犯了你的相关权益,请与官方沟通,我们会即时处理。

时间: 2024-12-07 23:46:45

Unity 中实用的 C# 扩展方法的相关文章

C#中的反射和扩展方法的运用

前段时间做了一个练手的小项目,名叫Book_Bar,用来卖书的,采用的是三层架构,也就是Models,IDAL,DAL,BLL 和 Web , 在DAL层中各个类中有一个方法比较常用,那就是 RowToClass ,顾名思义,也就是将 DataTable 中的数据封装到 Models 中.结果导致在DAL各个类中写了很多类似的方法,后来就直接把它抽取出来做成了 DataTable和 DataRow的扩展方法, 下面是代码: using System; using System.Collectio

在MVC中My97date应用C#扩展方法

项目中用的my97date,其他字段是用 @Html.EditorFor(model => model.字段)绑定的,但日历控件是用<input />绑定的,但这样写并不是特别好. 为了也能用@HTML绑定属性,用了扩展方法.代码如下: public static class My97DatePicker { private static string defaultFormat = "yyyy-MM-dd"; /// <summary> /// 使用特定

项目中常用的C# 扩展方法

///我们经常使用一些匿名委托来处理一些逻辑///但是在某些情况下,有可能委托是null,要是直接执行可能会抛异常///所以提供此扩展方法,直接可以使用例如 action.Execute() 来执行 namespace System { public static class ActionExtension { public static void Execute(this Action action) { if (action != null) { action(); } } public s

PHP中安装soap模块 扩展 方法

PHP中安装soap模块方法 一.Linux下安装soap模块 安装完php后最好保留当时安装的文件,比如usr/local/php-5.3.2 查看soap模块是否安装的办法:在php的安装目录下运行php -m来查看 如:/usr/local/php/bin/php -m |grep 'soap' 如果没有安装,则进入php的安装源文件夹 cd php-5.3.2/ext/soap 进入后在此运行phpize命令 /usr/local/php/bin/phpize 查看信息是否有出错,没有出

Unity中的物体移动-Rigidbody方法

为游戏对象添加刚体Rigidbody组件后,通过设置velocity和调用AddForce方法的方式可实现位移. 首先需要在开始方法中获取刚体组件 rigid = GetComponent<Rigidbody> (); 1. velocity float input_H = Input.GetAxisRaw ("Horizontal"); float input_V = Input.GetAxisRaw ("Vertical"); Vector3 v =

EasyUI中对datagrid的扩展方法

以下是给datagrid扩展一个方法的demo 1.给datagrid添加一个属性 $.extend($.fn.datagrid.defaults, { demo: "demo1" }); 2.给datagrid添加一个方法 $.extend($.fn.datagrid.methods, { test1: function (jq, param) { alert(“ok”); } }); 3.调用方法 $('#dg').datagrid('options').demo;//这里取新加的

Unity中UI界面颤抖解决方法

将Render Mode中属性改为Screen Space - Camera 摄像机挂在Canvas属性下会出现UI界面颤抖的效果. UI界面颤抖解决方式:将Render Mode中属性改为Screen Space - Overlay,如下图所示:

C#中的扩展方法

在java中没有这样的东西,一个类一旦是 final的 ,这个类就不能再被添加方法, 但是C#能够做到,可以给 sealed 类添加新的方法,这点我还是比较喜欢c#的. 这就是C#中的扩展方法. 那么什么情况下我们才需要去给一个类写扩展方法呢? 系统自带的类型,我们无法去修改: 修改源代码需要较大的精力,而且可能会带来错误: 我们只是需要一个或者较少的几个方法,修改源代码费时费力: 被扩展的类是sealed的,不能被继承:(就算不是sealed的,我们也不能因为需要一个方法而去写一个子类,这样不

.NET中那些所谓的新语法之二:匿名类、匿名方法与扩展方法

开篇:在上一篇中,我们了解了自动属性.隐式类型.自动初始化器等所谓的新语法,这一篇我们继续征程,看看匿名类.匿名方法以及常用的扩展方法.虽然,都是很常见的东西,但是未必我们都明白其中蕴含的奥妙.所以,跟着本篇的步伐,继续来围观. /* 新语法索引 */ 1.自动属性 Auto-Implemented Properties 2.隐式类型 var 3.参数默认值 和 命名参数 4.对象初始化器 与 集合初始化器 { } 5.匿名类 & 匿名方法 6.扩展方法 7.系统内置委托 Func / Acti