查看原文
其他

做好这7件事让你的Unity工程事半功倍

2016-07-01 崔国军 Gad-腾讯游戏开发者平台
某一天我看到一个人在Quora上问,程序员怎么样才能写一个超过10,000行代码的工程。当软件变得越来越大的时候,维护项目就变得越来越难,这是事实。
所以才诞生了这篇文章-如果你不能让你的项目井井有条,那么你就很难一直推动项目前进。在项目的后期,你会发现你自己的时间都浪费在了混乱的项目上,而不是用于添加新的功能。
这对于任何Unity项目来说都是成立的。这里是从我的角度来看能让你的工程井井有条的最重要的提示。 
1. 目录结构
如果不涉及组织项目的目录结构,根本就没法谈及对项目的管理。
在这件事情上,Unity给开发者完全的自由,但是正因为如此,这个事情就经常搞得一团糟。
下面的目录结构是我个人使用的结构:3rd-Party(第三方插件)Animations(动画相关的部分)Audio(音效相关的部分)Music(音乐相关的部分)SFX(特效音乐相关的部分)Materials(材质相关的部分)Models(模型相关的部分)Plugins(插件)Prefabs(预制件)Resources(资源,特别是需要动态加载的都要放在这里)Textures(纹理相关的部分)Sandbox(沙盒)Scenes(场景)Levels(关卡)Other(其他)Scripts(脚本)Editor(编辑器相关的内容)Shaders(着色器)
1.不要在根目录下存任何的资源文件。尽可能的使用子目录。
2.不要在根目录下创建任何多余的目录,除非你确实需要它。
3.命名规则要始终保持一致。如果你决定对目录名字使用驼峰命名法而对资源的名字使用小写字母命名,那么就要在整个项目的生命周期一直坚持下去。
4.不要试图把上下文特定的资源文件移动到一个一般性的目录里面。举个例子来说,如果这些材质是由模型生成的,那么就不要把这些材质移动到材质目录下。因为如果你这么做了,很快你就不知道这些材质是从哪来的以及要做什么用。
5.使用3rd-Party目录来存储从资源商店导入的资源。它们通常有它们自己的目录格式而且不能更改。
6.使用Sandbox 目录来放那些你还没有完全确定的实验性的东西。当做这些实验性的内容的时候,你要关心的最后一件事情就是合理的管理。
在Sandbox 目录里尽情的做你想做的事情,然后如果不想要了就移除它们,如果你希望把它们包含在你的项目里就重新把它们移出去管理好。当你是与其他人一起为某个项目工作的时候,那么你可以创建你的私人Sandbox子目录,比如:Sandbox/JohnyC。 
2.场景层次结构
除了项目需要层次结构以外,场景也需要层次结构。如同之前一样,我将给你一个模板,你可以按照你的需求进行调整:
Management(各种管理器)
GUI(用户交互界面)
Cameras(相机)
Lights(光源)
World(世界中相关的内容)Terrain(地形相关的内容)Props(其他的物体)
Dynamic(动态资源)
这里面有几条规则你需要遵守:1.所有空对象都应该位于(0,0,0)点并且有默认的旋转和大小。
2.当你在运行时初始化一个物体的时候,请确保它是放到了_Dynamic目录下-放在根目录下会导致你的整个层次结构被破坏,而没有统一放在一个地方,又会导致查找的时候非常困难。
3.对于只包含了脚本的空物体,使用“@”作为名字前缀—比如说@Cheats。 
3. 任何时候都使用预制件
Unity中的预制件机制并不完美,但是它是你能找到的最好的分享预先设置好的物体层次结构的办法。总的来说,要试图去把你放到场景中的所有东西都做成预制件。
你应该能够只添加一个或者几个预制件就能在一个空白场景里面创建一个新的关卡。
为什么你要使用预制件?理由就是任何时候当你改变一个预制件的时候,所有这个预制件的实例都会发生相应的改变。
你有100个关卡,并且希望对所有的关卡都添加一个摄像机特效?没有问题!如果你的摄像机是一个预制件的话,只要在这个摄像机的预制件上添加这个特效就可以了!
要小心的是你不能在预制件里面还套着另外一个预制件。请使用链接-有一个成员变量需要一个预制件的赋值,并且确保在这个实例创建的时候对这个成员变量赋予正确的预制件。如果可以的话,可以考虑在Awake() 或者在OnEnable() 函数里自动链接预制件的实例。
4. 学习如何使用版本控制系统(version control system,VCS)
你可能已经了解了诸如GIT、Subversion或者其他版本控制系统。事实上,“知道某些东西”只是你可以学习内容的一小部分。
你应该关注学习你所选择的版本控制系统中那些不常见但是非常重要的功能。为什么要这么做?主要是版本控制系统的强大往往超出你的想象,但是不幸的是很多用户仅仅把版本控制系统当作一个备份和同步的解决方案。
举个例子来说,你知道GIT允许你隐藏你的变化么? 通过这个行为,你可以先不提交你的修改到主干(masterbranch),而在随后继续着这个修改。

程序员往往选择注释掉成块的代码以防止这块代码在以后被用到。请不要这么做!如果你在使用版本控制系统的话,请学会如何快速浏览这个文件的之前版本情况的方法。
如果你对这个做法比较熟悉了以后,你的代码会看着整洁很多而不需要成块的注释代码。 
5.学习如何编写编辑器脚本
Unity是一个伟大的游戏引擎,部分是由于它卓越的扩展性(关于这方面可以看下Unity资源商店,里面的资源可以很容易就导入到Unity中)。
学习如何编写编辑器脚本并利用这些知识。你没有必要为你的编辑器脚本创建时髦的用户交互界面,用户交互可以非常的简单,比如菜单项就能做很多有意义的事情。下面是一些不久前我创建的编辑器脚本的例子:

下载Google Spreadsheet并保存为CVS文件-我在Google的驱动上有一个翻译方面的Spreadsheet,这个脚本会自动下载最新版本作为CVS文件存储起来,所以我根本就不需要手动做这个事情树的位置、旋转和大小的随机分布-在场景中有很多树的情况下,希望这些树看上去更像一个森林而不是一个网格。
创建分布式系统-为特定的目标进行构建,压缩所有的文件并把它们拷贝到正确的地方。
资源中的字符串替换-有几个文件,都会包含应用程序的版本,有这么一个工具,替换就方便了很多。
你可以从官方文档里面学习如何创建编辑器脚本。 
6.学习在项目中进行防御性编程
你曾经听说过防御性编程么?维基百科对它有如下的定义:
防御性编程(Defensive programming)是防御式设计的一种具体体现,它是为了保证对程序的不可预见的使用,不会造成程序功能上的损坏。
防御式编程主要用于可能被滥用、恶作剧或无意地造成灾难性影响的程序上。
通常情况下,在你写MonoBehaviour的时候,你应该确保以下这些事情:1、所有需要的引用都被正确的设置。
2、所有需要的组件都在这个MonoBehaviour里面正确的初始化。
3、如果你在使用单例,请确保它们是存在的。
4、如果你要搜索某个物体并且期望这个搜索能够返回成功的结果,那么这个查找尽可能的早做。
5、在你运行场景前利用混杂的编辑器代码(比如通过ExecuteInEditMode宏和#if UNITY_EDITOR宏定义的编辑器代码)来做尽可能多的检查。
在很多检查中你可以使用断言( asserts)。你应该阅读下关于《一个关于空指针异常的故事》(A Story of NullPointerException )的第一部分和第二部分。 
7.实现编辑器模式下(in-editor)或者游戏模式下(in-game)的特殊处理
在你学完如何编写编辑器脚本以后,你应该能够写一些编辑器模式下的特殊处理。
举个例子来说,可以在菜单项里面添加一个解锁某个事情(比如说全部关卡)的功能。创建这样一个功能真的很容易:
通常情况下你可以实现这些特殊处理:
1、解锁所有关卡、角色、物品等等。2、让你的角色永远不死。
3、加/减诸如时间、金钱、硬币等属性的值。4、让你看到一些事情,而这些事情是其他玩家看不到的。5、任何其他可以帮助你测试你的游戏的东西。
同样也可以在游戏模式下做很多特殊处理(但是会比较难以编写)。
这种类型的特殊处理会在非Unity编辑器模式下运行,但是你必须考虑在什么情况下你会希望执行这些特殊操作。
原文作者:Piotr Sobolewski译者:崔国军
【版权声明】原文作者未做权利声明,视为共享知识产权进入公共领域,自动获得授权。
相关阅读:腾讯是如何做Unity手游性能优化的Unity动画系统项目实战
腾讯游戏开发者平台长按,识别二维码,加关注
经验分享丨项目实践项目孵化丨渠道发行做有梦想的游戏人-GAME AND DREAM-

您可能也对以下帖子感兴趣

文章有问题?点此查看未经处理的缓存