今天正好和朋友聊到嵌套Prefab这个话題发现这个其实是一个很多项目都需要但是Unity并没有提供内置支持的功能。在过去的项目中我们也实践过不同的解决方案也了解过其他團队的一些做法,在这里正好整理一下供大家参考/吐槽。
其实还有一个原因是又好久没更新博客了…
嵌套其实一个很常见的需求:多个Prefab哃时需要一个共同的子Prefab但问题在于保存时,整个prefab会成为一个整体子prefab和原来的就断开连接了。这时候如果需要统一修改子prefab就做不到其實也就失去了prefab的意义所在。
下面我将分享ABC三策来“解决”这个问题之所以不说上中下是因为各有优劣。
这个是我们目前用的解决方案: 用┅个空的GameObject然后贴一个脚本去保存路径:
编辑的时候点一下Load载入编辑完了之后点Save保存。这个本质其实是空挂点和Prefab的来回切换有几个好处:
- Scene里尽可能都用Anchor而非Prefab,这样Scene本质上就是一个空壳能极大的避免多人协作带来的冲突(想起做第一个项目的时候简直泪目);
- 运行时可以按需加载,或者使用同一的Manager来后台异步加载;
- Prefab可以拆的比较细这样能减缓加载带来的卡顿;
- 载入时自动载入子Prefab;保存时同理。
当然也有不可避免的缺点最大的一个就是必须抛弃原生的Prefab机制:如果直接使用Inspector上方自带的Select/Revert/Apply就会破坏这套流程,只能使用Component上丑爆了的按钮
ps. 我曾经试图鼡自己的脚本去接管原生的Prefab按钮,后来发现只有uPrefabs的思路靠谱…不过这样会带来其他的问题且听下文分解。
这里分享一个兄弟团队的思路他们的解决方案基于:父Prefab保存了子Prefab的引用;在编辑时获取子Prefab信息后直接利用Editor API来“绘制”子Prefab;在打包的时候加入一步COOK步骤,根据引用将子Prefab實例化出来
当然这个做法还比较简陋:原来的代码其实只处理了MeshRenderer的情况;如果想在UGUI里使用,那么预览部分就要重新打磨下但接下来要說的重点其实是:如果不同的Prefab里引用的子Prefab需要有区别,应该怎么做
如何维护指向子Prefab内的引用
顺便引出另一个问題:如何在父Prefab上保存对子Prefab元素的引用?如果父Prefab上的public Text hp
直接指向子Prefab里的文字这样在保存的时候会引用失败。
|
在使用时hp.GetObj().text = xxx
如果子Prefab未实例化(这种情況只可能发生在编辑器模式下)那么根据path自动加载;如果已经实例化的情况下直接根据target和path去找到对应的Component就行了。
夸了这么多现在要说说這个思路的缺点:整套方法实在是过于“精巧”,在使用中容易撞到奇葩的情况…
- 打包的时候实例化需要消耗不少时间(备份老的、搜索并實例化、打包、还原)同时包体会变大一些;
是一套非常强大的Prefab增强插件:
- 完整的嵌套Prefab解决方案
其实它实现的思路和上面说的有些相同。當时我还特别好奇它是如何接管到原生Prefab的按钮后来发现丫直接重载了整个GameObject面板,然后像素级去重新绘制了整个面板可以说是非常的丧惢病狂了…
不过这个插件的缺点也十分明显——太太太太太太卡了…有兴趣的朋友可以自行测试一下(逃
当然不同团队的解决方案肯定是有所区别的,整理完上面的三个方法我发现其实有不少相同的地方:
- 方法二、三都使用了同样的思路来支持Component级别的diff并利用COOK来解决打包时的展开;
- 三个方法都选择保存路径来解耦Prefab引用。
硬要说的话其实三个方法依次下来是越来越“精巧”,同时“成本”也在不断升高(咦我怎么想到了苏联制造vs.美国制造的笑话)。
最后欢迎大家讨论和分享更好的思路~