① Unity3d 使用Assetbundle合并项目的几点注意
Unity3d中动态资源读取,除了Resources.Load方式。还有就是Assetbundle。
Assetbundle的各方面介绍,这里就不在赘述,网上搜搜就一大片。但是,是不是什么东西都能被打成Assetbundle呢?
基本上,引用到的资源,都能被打成Assetbundle。但是脚本和shader却不一样,虽然脚本和shader也能被导入Assetbundle。但是却不能把源文件导入(如果Assetbundle中存的是脚本的源文件,那也就没那么多热更新解决方案了)。最简单的验证方法,把一个项目的一个场景,导出Assetbundle,另一个项目读取这个Assetbundle运行。会发现资源都导入了,却没有执行的脚本。
因此,如果两个项目,想通过Assetbundle方式,来合并两个项目,那就必须把脚本也拷到要被导入的项目中。两个项目脚本合并,难免出现重名的脚本,重名的类。为了解决这个,每个项目,定一个唯一的namespace。如果项目开始的时候就定好了,那还好办,如果后期合并,前期都没加过。那就只能自己写个Editor脚本,批量加上。
Unity项目中,难免使用一些全局的设置,比如,Physic重力设置,Tag和Layer这些。重力还好办,项目运行起来,还能通过脚本修改。但是Tag,Layer却不行。只能想办法进行合并。
Unity中,Tag只能通过string修改。但是,导成Assetbundle之后,其存储是index。所以要么在合并Tag的时候,要么批量修改,要么写个映射。当然,最好的方式是,项目统一用一套Tag。
Layer相比于Tag要简单许多,Layer可以通过int修改。Unity最大有32个Layer,即使你不添加Layer,也能通过修改Layer的index来使用。那么只要工程中定义全局使用的Layer即可
由于项目的资源都是Assetbundle,那么打包的时候,Unity会自动帮你精简项目。所以,Shader和脚本,就有可能被精简掉。
所以保险起见,吧项目中所有的Shader全部添加到
Unity的脚本也得进行相应的设置
② 濡備綍鐏垫椿浣跨敤AssetBundle绠$悊CSS鏍峰紡鍙奐S鑴氭湰
2.0鐨勫彉鍖栫浉淇″ぇ瀹堕兘鐪嬪埌浜嗭紝鍏朵腑瀵逛竴涓璧勬簮鍖呮傚康鍋氬嚭浜嗗緢瀹岀編鐨勫疄鐜帮紝閭e氨鏄疉ssetBundle锛屼絾鏄寰堝氬垵瀛﹁呮湅鍙嬪彲鑳戒笉澶鑳藉熸g‘鐨勯嗕細鍏朵腑鐨勫惈涔
鎴戠敾浜嗕竴寮犲浘锛屽ぇ瀹跺彲浠ュ皢灏辩湅涓涓嬶細
鍏朵腑锛屾帶鍒跺櫒鍔ㄤ綔鐨勮嗗浘锛坴iew锛夋覆鏌撻『搴忔槸浼樺厛浜庢垜浠鐨勬ā鏉块〉锛坙ayout锛夌殑锛岄偅涔堜竴鏃︽垜浠鍦ㄦ煇涓瑙嗗浘涓浣跨敤浜嗘柊鐨凧S搴擄紝鎴栨柊鐨凜SS鏍峰紡鏂囦欢锛岄偅涔堟垜浠濡備綍鍘诲勭悊鍛锛
浠ヤ笅鏂瑰紡鏄閿欒鐨勶紝璇烽伩鍏嶄娇鐢锛
鏈夌殑浜轰細鐩存帴鍦ㄨ嗗浘閲屾坊鍔犲筩ss鎴栬卝s鐨刲ink寮曠敤锛岃繖鏍峰紩鍏ョ殑鏂囦欢鏄鍦ㄨ嗗浘鍖哄煙锛岃寉ii鐨勯粯璁js鍔犺浇浼氭斁鍦ㄦā鏉块〉鐨勬渶鍚庯紝杩欐牱鍙鑳藉艰嚧渚濊禆鍏崇郴娣蜂贡銆
姣斿備綘瑙嗗浘涓寮曠敤鐨刯s鏂囦欢閲岃皟鐢ㄤ簡jquery鍖咃紝浣嗘槸鎵ц屾椂jquery鐨勫姞杞戒唬鐮佸湪HTML椤甸潰鐨勬湯灏撅紝杩欐牱瀵艰嚧椤甸潰鑴氭湰閿欒銆
杩樻湁浜轰細鍥剧渷浜嬶紝鐩存帴鎶婇」鐩涓鎵鏈夌殑js鎴朿ss鏂囦欢閮戒功鍐檒ayout妯℃澘椤甸噷锛岃繖鏍蜂骇鐢熷ぇ閲忕殑鏃犳晥鏍峰紡鎴杍s锛屽奖鍝嶄簡鍔犺浇鏁堢巼鍙婇〉闈㈤敊浣嶉庨櫓銆
鎵浠ユg‘鐨勬柟寮忓簲璇ユ槸閫氳繃AssetBundle鍘昏В鍐宠繖涓闂棰橈紝鍏堝彂涓涓绠鍗曠殑绫荤粰澶у剁湅涓涓嬶細
namespace app\assets;
use yii\web\AssetBundle;
class AppAsset extends AssetBundle {
public $basePath = '@webroot';
public $baseUrl = '@web';
public $css = [
'public/skin/default_skin/css/theme.css',
];
public $js = [
'public/vendor/jquery/jquery-1.11.1.min.js',
'public/vendor/jquery/jquery_ui/jquery-ui.min.js',
'public/js/bootstrap/bootstrap.min.js',
];
//渚濊禆鍖
public $depends = [
//杩欓噷鍐欎綘鐨勪緷璧栧寘鍗冲彲锛屾病鏈夊氨鍒鍐
];
//瀵煎叆褰撳墠椤电殑鍔熻兘js鏂囦欢锛屾敞鎰忓姞杞介『搴忥紝杩欎釜搴旇ユ渶鍚庤皟鐢
public static function addPageScript($view, $jsfile) {
$view->registerJsFile($jsfile, [AppAsset::className(), 'depends' => 'app\assets\AppAsset']);
}
//瀵煎叆缂栬緫鍣
public static function addCkeditor($view) {
$view->registerJsFile('/public/js/utility/ckeditor/ckeditor.js', [AppAsset::className(), 'depends' => 'app\assets\AppAsset']);
}
}
鍙浠ョ湅鍒颁笂闈㈡垜鍒涘缓鐨勭被涓宸茬粡棰勫畾涔変簡涓や釜闈欐佹柟娉昦ddPageScript鍜宎ddCkeditor锛屽叾涓璦ddCkeditor鏄涓涓绗涓夋柟鐨刯s缁勪欢锛屾槸涓缂栬緫鍣锛屽叿浣撶殑寮鍙戠幆澧冧腑浣犱滑鍙浠ュ啓鍒鐨勬柟娉曞悕鍙婂姞杞藉埆鐨勭粍浠躲
閭d箞涓婄殑杩欎釜涓滆タ鍐欏ソ鍚庡簲璇ュ備綍鍘讳娇鐢ㄥ憿锛
鎴戜滑鍦ㄦā鏉块〉寮澶撮儴鍒嗗姞涓婅繖鍙ヨ瘽锛
//鑷鍔ㄥ姞杞借祫婧
AppAsset::register($this);
杩欐牱浼氬湪妯℃澘椤靛姞杞藉熀纭鐨勯」鐩璧勬簮鏂囦欢锛屾瘮濡俢ss鍜宩s浠涔堢殑銆
鐜板湪鎴戜滑鏈変竴涓瑙嗗浘鍙玞reate-mail锛岄渶瑕佷娇鐢╟keditor缂栬緫鍣锛岄偅涔堟垜浠搴旇ュ湪create-mail瑙嗗浘鐨勫紑澶村姞涓婅繖鍙ヨ瘽锛
//瀵煎叆ckeditor鍖呰祫婧
\app\assets\AppAsset::addCkeditor($this);
鏈鍚庤В閲婁竴涓嬶紝addCkeditor锛堬級鏂规硶鏄鎴戜滑棰勫厛瀹氫箟濂界殑锛岃繖鏍锋垜浠鍙浠ユ妸涓浜涘父瑙佺殑鍖呴兘鎷嗗寘骞堕勫勭悊濂斤紝濡傛灉浣犺夊緱楹荤儲鍙浠ョ洿鎺ヤ娇鐢ㄥ備笅鐨勬柟寮忥細
//瀵煎叆ckeditor鍖呰祫婧
\app\assets\AppAsset::addPageScript($this,'js鏂囦欢鐩稿硅矾寰勬垨url');
浠ヤ笂鐨勪緥瀛愬彧鏄浣跨敤浜唈s鏂囦欢浣滀负涓涓绠鍗曠殑浠嬬粛锛宑ss鏍峰紡鐨勫姞杞戒篃鏄涓鏍风殑閬撶悊銆
杩欐牱鍋氱殑濂藉勬槸锛屽嵆浣垮湪瑙嗗浘閲屽姞杞絚ss鎴杍s涔熶細鍥犱负渚濊禆鍏崇郴鑰屽嚭鐜板湪瑙嗗浘澶栭潰鐨勫父瑙勫姞杞藉尯鍩熶腑锛岃勮寖浜嗗緢澶氥
鍚屾椂涔熷洜涓轰緷璧栧叧绯伙紝浣犲湪瑙嗗浘閲屽姞杞界殑鏂囦欢鑲瀹氫細鎺掑湪浣犵殑鍩虹鏍峰紡鎴栬剼鏈鐨勫悗闈锛屼笉浼氬嚭閿欍
③ 如何做一个方便的资源管理方案
工具:
Unity 中的资源来源有三个途径:一个是Unity自动打包资源,一个是Resources,一个是AssetBundle。
Unity自动打包资源是指在Unity场景中直接使用到的资源会随着场景被自动打包到游戏中,这些资源会在场景加载的时候由unity自动加载。这些资源只要放置在Unity工程目录的Assets文件夹下即可,程序不需要关心他们的打包和加载,这也意味着这些资源都是静态加载的。但在实际的游戏开发中我们一般都是会动态创建GameObject,资源是动态加载的,因此这种资源其实不多。
Resources资源是指在Unity工程的Assets目录下面可以建一个Resources文件夹,在这个文件夹下面放置的所有资源,不论是否被场景用到,都会被打包到游戏中,并且可以通过Resources.Load方法动态加载。这是平时开发是常用的资源加载方式,但是缺点是资源都直接打包到游戏包中了,没法做增量更新。
AssetBundle资源是指我们可以通过编辑器脚本来将资源打包成多个独立的AssetBundle。这些AssetBundle和游戏包是分离的,可以通过WWW类来加载。AssetBundle的使用很灵活:可以用来做分包发布,例如大多数页游资源是随着游戏的过程增量下载的,或者有些手游资源过大,渠道要求发布的包限制在100M以内,那只能把一开始玩不到的内容做成增量包,等玩家玩到的时候通过网络下载。AssetBundle 也可以用来做我们下面讨论的自动增量更新。
Unity5相比之前的版本,AssetsBundle的打包过程有所简化。之前打包需要通过代码来设置需要打入包的资源并自己建立包的依赖关系,Unity5可以通过每个资源Inspector底部的AssetBundle下拉来指定该资源要打入哪个包,不指定就是不打包。打包过程只需要BuildPipeline.BuildAssetBundles一句话就行了,Unity5会根据依赖关系自动生成所有的包。每个包还会生成一个manifest文件,这个文件描述了包大小、crc验证、包之间的依赖关系等等,通过这个manifest打包工具在下次打包的时候可以判断哪些包中的资源有改变,只打包资源改变的包,加快了打包速度。manifest只是打包工具自己用的,发布包的时候并不需要。
关于自动生成依赖关系这个有必要提下,Unity确实会自动给你建立依赖关系,前提是你依赖的资源必须已经在Inspector中设置了BundleName。如果没有,Unity会把这个公用的资源重复打到多个用到的包中,因为这个公用资源不在一个独立的包中,Unity也不会智能地给你发现它是公用的,然后生成一个公用包。更深的坑在于,如果你公用的是一个FBX模型,你只给这个模型设置BundleName还不行,它用到的贴图,材质都要设,否则模型是公用了,贴图没有公用,结果贴图还是被打包到多个包中了。所以设置BundleName这个工作最好还是由编辑器脚本来完成。
方案:
Unity提供的就这些了,下面就自己发挥:如何做一个方便的资源管理方案,既可以开发时方便,又可以方便发布更新包呢?开发过程全用AssetsBundle是不合适的,因为开发中资源经常添加和更新,每次添加或者更新都生成一下AssetsBundle才能运行是很麻烦的。而且我们要做的是自动更新而不是分包下载,这也就是说在发布游戏的时候这些资源应该都是在游戏包中的,所以他们也不该从AssetsBundle加载。
分析完需求,方案也就出来了:资源还是放在Resources下面,但是这些资源同时也会打包到AssetBundle中。代码中所有加载资源的地方都通过自己的ResourceManager来加载,由ResourceMananger来决定是调用Resources.Load来加载资源还是从AssetsBundle加载。在开发环境下(Editor)这些资源显然是直接从Resources加载的,发布的完整安装包资源也是从Resources加载,只有当有一个增量版本时,游戏主程序才会去服务器把增量的AssetBundle下载下来,然后从AssetBundle加载资源。
实现:
实现中我们首先要考虑的是AssetBundle的粒度,即每个AssetBundle包含多少资源。增量包的最小粒度就是AsssetBundle, 如果单个AssetBundle过大,只要这个AssetBundle中有一个资源改变了就需要重新下载整个AssetBundle,浪费流量和玩家的等待时间;如果单个AssetBundle过小,极端情况是每个资源一个AssetBundle,虽然实现了更新最小化,但是带来了额外开销:AssetBundle本身也是有大小的,而且查找加载AssetBundle也是需要时间的。大家都往U盘里面拷过东西,拷一个1G的文件比拷1千个1M的文件要快很多。比较合理的做法是根据逻辑来,例如每个角色可以有独立的AssetBundle,公用的一些UI资源可以打到一个AssetBundle里面,每个场景独立的UI资源可以打成独立的AssetBundle。这样做资源预加载的时候也方便,每个场景需要用到几个Bundle就加载几个Bundle,无关的资源不会被加载。