查看: 1202|回复: 2
打印 上一主题 下一主题

[经验分享] 在Unity中定义统一的对象搜索接口

[复制链接]

100

主题

3

听众

7683

积分

高级设计师

Rank: 6Rank: 6

纳金币
2378
精华
0

最佳新人 活跃会员 热心会员 灌水之王 突出贡献

跳转到指定楼层
楼主
发表于 2015-2-5 22:19:36 |只看该作者 |倒序浏览

我们经常要在unity中以各种方式搜索对象。比如按名字搜索、按tag、layer或者是查找名字为xxx开头的对象。

本文是介绍以一种统一的接口来搜索对象。


1、定义统一的搜索接口
/// <summary>
/// 游戏对象搜索接口
/// </summary>
public interface IGameObjectFinder
{
    /// <summary>
    /// 搜索
    /// </summary>
    /// <param name="root">搜索的开始位置/根节点</param>
    /// <param name="findResult">搜索存放的结果</param>
    void Find(Transform root, List<Transform> findResult);
}

2、定义一个使用上面搜索接口的方法
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、实现一个查找某个组件的接口
/// <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、实现一个迭代查找
首先,要查找指定节点下的某个名字的所有节点(不管深度多少),这个需要遍历。那么,我们可以先抽象出一个遍历的接口。
为了保证搜索的统一,那么我们还是从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来判断是否符合要求,是的话则加入结果列表。然后继续查找这个子结点下的其他子节点。(该搜索是不包括第一个开始节点的)

IGameObjectFinderForIteration的接口也很简单:
/// <summary>
/// 迭代搜索判断
/// </summary>
public interface IGameObjectFinderForIteration
{
    /// <summary>
    /// 指定节点是否合法
    /// </summary>
    /// <param name="node"></param>
    /// <returns></returns>
    bool isVaild(Transform node);
}

好的,这样就意味着我们要想查找某个根节点下的所有子节点(包括直接和间接的),只要实现一个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、有什么用?
很多人可能还不明白有什么用,通过上面的抽象。你可以发现我们把搜索全部统一为:
Finder.Find(transform, result, objectFinderImpl);
1、代码是统一的,不管你的搜索条件有多复杂。便于代码管理、维护、拓展。
2、可配置,你可以简单通过数字关联不同的搜索器的实现,然后通过附带的参数传递给具体的搜索器,来实现通过配置文本采用不同的搜索器进行搜索。这个在你做新手引导的时候很好用,因为,策划可能有时候要把一个xxx手指放到什么图标、什么按钮那里。那你就可以把这些查找交给策划来配置了~
3、如果还没明白有什么用,那就无视吧。总有一天你还会回来的。
分享到: QQ好友和群QQ好友和群 腾讯微博腾讯微博 腾讯朋友腾讯朋友 微信微信
转播转播0 分享淘帖0 收藏收藏0 支持支持0 反对反对0
回复

使用道具 举报

115

主题

3

听众

5676

积分

高级设计师

Rank: 6Rank: 6

纳金币
7268
精华
0

最佳新人 活跃会员 热心会员 灌水之王 突出贡献

沙发
发表于 2015-2-5 22:22:29 |只看该作者
Thanks for sharing this one !
回复

使用道具 举报

10

主题

0

听众

551

积分

初级设计师

Rank: 3Rank: 3

纳金币
586
精华
0

最佳新人 活跃会员 热心会员 灌水之王 突出贡献

板凳
发表于 2015-2-8 13:19:53 |只看该作者
感谢分享,谢谢提供下载
回复

使用道具 举报

您需要登录后才可以回帖 登录 | 立即注册

关闭

站长推荐上一条 /1 下一条

手机版|纳金网 ( 闽ICP备08008928号

GMT+8, 2024-5-22 21:46 , Processed in 0.083512 second(s), 27 queries .

Powered by Discuz!-创意设计 X2.5

© 2008-2019 Narkii Inc.

回顶部