標籤:unity unity3d unity3d培訓 unity3d極致學院 unity3d遊戲開發
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 層級, 對每一個訪問的節點執行一個自訂的操作, 如果此操作返回一個非Null 參考將終止遍曆過程, 並且此返回值最終作為遍曆方法的返回值
/// /summary
/// param name="root"遍曆開始的根部 Transform 對象/param
/// param name="operate"遍曆到每一個節點時將調用此方法; 參數1: 當前訪問的對象; 參數2: 包括本層次在內的剩餘深度限制; 返回值: null 表示繼續遍曆, 非Null 參考將終止遍曆過程, 並且此返回值最終作為遍曆方法的返回值/param
/// param name="depthLimit"遍曆深度限制, 負值表示不限制, 0 表示只訪問 root 本身而不訪問其子級, 正值表示最多訪問的子級層數/param
/// returns第一次 operate 返回的非Null 參考或 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學習文章,如果有什麼內容侵犯了你的相關權益,請與官方溝通,我們會即時處理。
Unity 中實用的 C# 擴充方法