在Unity中定義統一的對象搜索接口
來源:程序員人生 發布時間:2014-12-23 09:04:31 閱讀次數:2602次
我們常常要在Unity中以各種方式搜索對象。比如按名字搜索、按tag、layer或是查找名字為xxx開頭的對象。
本文是介紹以1種統1的接口來搜索對象。
1、定義統1的搜索接口
/// <summary>
/// 游戲對象搜索接口
/// </summary>
public interface IGameObjectFinder
{
/// <summary>
/// 搜索
/// </summary>
/// <param name="root">搜索的開始位置/根節點</param>
/// <param name="findResult">搜索寄存的結果</param>
void Find(Transform root, List<Transform> findResult);
}
2、定義1個使用上面搜索接口的方法
public class Finder{
/// <summary>
/// 查找指定根節點下符合指定的查找器的Transform并保持到findResult中
/// </summary>
/// <param name="root"></param>
/// <param name="findResult"></param>
/// <param name="finder"></param>
public static void Find(Transform root, List<Transform> findResult, IGameObjectFinder finder)
{
if (root == null)
{
throw new Exception("root can not be null, it defines the starting point of the find path");
}
if (findResult == null)
{
throw new Exception("findResult can not be null, it used to collect the find result");
}
if (finder == null)
{
throw new Exception("finder can not be null, it defines how to find transform");
}
finder.Find(root, findResult);
}
}
可以看到,2步驟只是簡單調用1的接口進行搜索。但是1只是接口,有啥用?接著看。
3、實現1個查找某個組件的接口
/// <summary>
/// 根據組件搜索
/// </summary>
/// <typeparam name="T"></typeparam>
public class GameObjectFinderByComponent<T> : IGameObjectFinder where T : Component
{
public void Find(Transform root, List<Transform> findResult)
{
foreach (var componentsInChild in root.GetComponentsInChildren<T>())
{
findResult.Add(componentsInChild.transform);
}
}
}
可以看到只要實現IGameObjectFinder就能夠了。那末如果這時候候想調用,應當怎樣調用呢?
比如想查找transform下面的剛體組件,然后保存到result里面。只要:
Finder.Find(transform, result, new GameObjectFinderByComponent<Rigidbody>());
甚么?看起來好像有點小題大作,直接用GetComponentsInChildren不就好嗎?
先不急。我們繼續看看其它查找需求。比如我想查找名字為xxx的對象。
4、實現1個迭代查找
首先,要查找指定節點下的某個名字的所有節點(不管深度多少),這個需要遍歷。那末,我們可以先抽象出1個遍歷的接口。
為了保證搜索的統1,那末我們還是從IGameObjectFinder中繼承。
/// <summary>
/// 迭代遍歷搜索
/// </summary>
public class GameObjectFinderByIteration : IGameObjectFinder
{
private IGameObjectFinderForIteration finderForIteration;
public GameObjectFinderByIteration(IGameObjectFinderForIteration finderForIteration)
{
this.finderForIteration = finderForIteration;
}
public void Find(Transform root, List<Transform> findResult)
{
for (int i = 0, childCount = root.childCount; i < childCount; i++)
{
Transform t = root.GetChild(i);
if (finderForIteration.isVaild(t))
{
findResult.Add(t);
}
Find(t, findResult);
}
}
}
這個代碼的意思就是:我先把開始節點下面的每一個子節點通過另外一個接口IGameObjectFinderForIteration來判斷是不是符合要求,是的話則加入結果列表。然后繼續查找這個子結點下的其他子節點。(該搜索是不包括第1個開始節點的)
IGameObjectFinderForIteration的接口也很簡單:
/// <summary>
/// 迭代搜索判斷
/// </summary>
public interface IGameObjectFinderForIteration
{
/// <summary>
/// 指定節點是不是合法
/// </summary>
/// <param name="node"></param>
/// <returns></returns>
bool isVaild(Transform node);
}
好的,這樣就意味著我們要想查找某個根節點下的所有子節點(包括直接和間接的),只要實現1個IGameObjectFinderForIteration。那末OK。看看怎樣按名字搜索。
/// <summary>
/// 迭代遍歷按名字搜索
/// </summary>
public class FinderForIterationByName : IGameObjectFinderForIteration
{
protected readonly string NAME;
public FinderForIterationByName(string name)
{
NAME = name;
}
public bool isVaild(Transform getChild)
{
return getChild.gameObject.name.Equals(NAME);
}
}
使用也很簡單,加入想找transform節點下,名字為“abc”的對象,并保存在result列表里面。只要這樣:
Finder.Find(transform, result, new GameObjectFinderByIteration(new FinderForIterationByName("abc")));
5、有甚么用?
很多人可能還不明白有甚么用,通過上面的抽象。你可以發現我們把搜索全部統1為:
Finder.Find(transform, result, objectFinderImpl);
1、代碼是統1的,不管你的搜索條件有多復雜。便于代碼管理、保護、拓展。
2、可配置,你可以簡單通過數字關聯不同的搜索器的實現,然后通過附帶的參數傳遞給具體的搜索器,來實現通過配置文本采取不同的搜索器進行搜索。這個在你做新手引導的時候很好用,由于,策劃可能有時候要把1個xxx手指放到甚么圖標、甚么按鈕那里。那你就能夠把這些查找交給策劃來配置了~
3、如果還沒明白有甚么用,那就疏忽吧。總有1天你還會回來的。
生活不易,碼農辛苦
如果您覺得本網站對您的學習有所幫助,可以手機掃描二維碼進行捐贈