赞
踩
/** * 程序说明 */ using UnityEngine; using UnityEngine.UI; /// <summary> /// 枚举大写字母开头,驼峰式 /// </summary> public enum AvatarType { Saber, Archer, Rider, } /// <summary> /// 类名大写字母开头,驼峰式 /// </summary> public class Example : MonoBehaviour { #region Abbreviation /** * GameObject->Go * Transform->Trans * Position->Pos * Button->Btn * Dictionary->Dict * Number->Num * Current->Cur */ #endregion /// <summary> /// 公有变量和公共属性使用首字母大写驼峰式 /// </summary> public int ExampleNum; public int ExampleIndex { get; set; } /// <summary> /// 常亮使用全大写,单词与单词用下划线分割 /// </summary> private const int EXAMPLE_DK_ID = 20; /// <summary> /// 私有最好也别省略private /// 私有变量可以加前缀 m 表示私有成员 mExampleBtn /// 但在Unity进行私有序列化时[SerializeField] 可视面板上的 M 就比较奇怪 /// </summary> private Button mExampleBtn; /// <summary> /// 方法名一律使用首字母大写驼峰式 /// </summary> public void ExampleFunc() { //局部变量最好用var匿名声明 小写驼峰式 var go = transform.Find("Example").gameObject } /// <summary> /// 函数与函数直接留一行空行 /// </summary> public void ExampleFunc2() { //局部变量最好用var匿名声明 小写驼峰式 var go = transform.Find("Example").gameObject } }
-- 系统功能扩展:保持与原功能的风格一致,使用小写,如string的拓展:string.split -- 逻辑功能命名:保持与C#代码规范一致,采用大写驼峰式命名 --------------------------------示例--------------------------------------- --[[ @desc: 程序说明 ]] local Example = Class("Example") -- 方法说明(全部为局部) local function ExampleFunc(self) end -- 方法导出(都定义在底部) Example.ExampleFunc = ExampleFunc return Example
└── LuaScripts ├── Base # 基础公用模块(基本上就是C#端翻成Lua) │ ├── Collections # 常用的集合(Stack, Queue) │ ├── Common # 公共方法(Class, Singleton等) │ ├── Debug # 调试器 │ ├── Event # 事件管理 │ ├── Extension # Lua端系统方法拓展(string的拓展等) │ ├── Pool # 对象池 │ ├── Timer # 定时器 │ ├── Update # Update管理 │ └── Init # 基础公共模块初始化 ├── Global # 全局内容 │ └── Init # 全局内容初始化 ├── Modules # 模块目录 │ └── ... # 各个模块 ├── Views # 视图UI目录 │ ├── ... # 各个功能UI │ ├── ViewConfig # UI与Prefab对应配置 │ └── ViewManager # 视图UI管理 ├── Config # 全局配置文件 └── GameMain # Lua程序入口
冗余情况:
A
依赖C
,B
依赖C
,如果只打成A,B
两个Bundle
包,就会冗余C
。每个资源文件单独打成一个Bundle
包,简单方便,同时保证不冗余,但会造成Bundle
数目过多。
粒度问题:
A
依赖B、C、D
,按单资源打成单Bundle
包的策略会打成A,B,C,D
四个Bundle
,加载依赖是要加载4个Bundle包
,但如果C,D
是被A
所唯一依赖的,那么更好的策略就是A,C,D
打成一个Bundle
包,那么加载依赖就只用加载2个Bundle包
,提高了加载效率,同时也不会冗余资源。(类似散图和图集的关系,但具体两者差距多少,并没有实际测过)
打包策略:
保证不冗余的情况下,最大限度的减少粒度:
a. 指定根目录,记录所有文件和其被依赖列表
b. 文件被依赖数大于1,就单独打成Bundle包,否则向上归并至被依赖项
/// <summary> /// 合并依赖,并分组资源 /// </summary> public static void GroupAssetBundles() { /* 清除同层依赖 把同层之间被依赖的节点下移 (a->b, a->c, b->c) ==> (a->b->c) * a a * / \ ==> / * b -> c b * / * c * 例如:prefab上挂着mat, mat依赖shder。特别注意,此时prefab同时依赖mat,和shader。可以点击右键查看 * (prefab->mat, prefab->shader, mat->shader) ==> (prefab->mat->shader) */ var removeList = new List<string>(); foreach(var item in mAssetItemDict) { removeList.Clear(); var path = item.Key; var assetItem = item.Value; foreach(var depend in assetItem.Depends) { var dependAssetItem = GetAssetItem(depend); foreach(var beDepend in dependAssetItem.BeDepends) { if (assetItem.Depends.Contains(beDepend)) removeList.Add(depend); } } foreach(var depend in removeList) { assetItem.Depends.Remove(depend); var dependAssetItem = GetAssetItem(depend); dependAssetItem.BeDepends.Remove(path); } } /* 向上归并依赖 * a e * \ / * b f ==> (a,b,c,h) -> (d) <- (e,f) * / | \ / * c h d */ foreach(var item in mAssetItemDict) { var path = item.Key; var assetItem = item.Value; while(assetItem.BeDepends.Count == 1) { assetItem = GetAssetItem(assetItem.BeDepends[0]); if (assetItem.BeDepends.Count != 1) { item.Value.AssetBundleName = assetItem.AssetBundleName; } } } }
/// <summary> /// 遍历Atlas下所有的SpriteAtlas,建立图片资源依赖 /// </summary> public static void CreateSpriteAtlasMap() { var dir = new DirectoryInfo(BuilderConfig.SpriteAtlasPath); if (!dir.Exists) return; var files = dir.GetFiles(); for (var i = 0; i < files.Length; i++) { var fileInfo = files[i]; EditorUtility.DisplayProgressBar("CreateSpriteAtlasMap", fileInfo.FullName, 1.0f * (i + 1) / files.Length); if (AssetUtils.ValidAsset(fileInfo.FullName)) { var fullPath = fileInfo.FullName.Replace("\\", "/"); var path = fullPath.Substring(fullPath.IndexOf(BuilderConfig.AssetRootPath)); var assetItem = GetAssetItem(path); var depends = AssetDatabase.GetDependencies(path); foreach (var depend in depends) { if (AssetUtils.ValidAsset(depend) && depend != path) { mSpriteAtlasDict.Add(depend, path); assetItem.Depends.Add(depend); var dependAssetItem = GetAssetItem(depend); dependAssetItem.BeDepends.Add(path); } } mSpriteAtlasDict.Add(path, path); } } }
Assets/LuaScripts/.lua -> Assets/GameAssets/LuaScripts/.lua.bytes
/// <summary> /// 创建Lua二进制文件 /// Assets/LuaScripts/*.lua -> Assets/GameAssets/LuaScripts/*.lua.bytes /// </summary> public static void CreateLuaBytes() { if (Directory.Exists(BuilderConfig.LuaScriptsDestPath)) { FileUtil.DeleteFileOrDirectory(BuilderConfig.LuaScriptsDestPath); } var dir = new DirectoryInfo(BuilderConfig.LuaScriptsSrcPath); if (!dir.Exists) return; var stack = new Stack<DirectoryInfo>(); stack.Push(dir); while (stack.Count > 0) { var dirInfo = stack.Pop(); var files = dirInfo.GetFiles(); foreach (var file in files) { if (AssetUtils.ValidAsset(file.FullName)) { var fullPath = file.FullName.Replace("\\", "/"); var startIndex = fullPath.IndexOf("LuaScripts"); var destPath = fullPath.Insert(startIndex, "GameAssets/") + ".bytes"; if (Base.Utils.FileUtil.CheckFileAndCreateDirWhenNeeded(destPath)) { file.CopyTo(destPath); } } } var subDirs = dirInfo.GetDirectories(); foreach (var subDir in subDirs) { stack.Push(subDir); } } }
资源发布到真机前,要构建对应平台的AssetBundle
iOS
真机和Mac
下的编辑模式,用WWW
加载StreamingAssets
下的资源路径:"file://" + Application.streamingAssetsPath
iOS
真机测试:Player Setting –> Other Setting -> Strip Engine Code
去掉
Resources
:官方不推荐
AssetBundle
:官方介绍
AssetDataBase
: 编辑模式下
编辑器模式下:UnityEditor.AssetDatabase.LoadAssetAtPath
AssetBundle
同步加载:
1.根据AssetBundleManifest
,同步加载自身及所有依赖的AssetBundle(LoadFromFile)
2.根据加载出来的AssetBundle
同步加载对应资源(LoadAsset)
/// <summary> /// 同步加载所有依赖Bundle /// </summary> /// <param name="path">Path.</param> public AssetBundle SyncLoadAllAssetBundle(string path) { var manifest = GetAssetBundleManifest(); var assetBundleName = PathToBundle(path); var dependencies = manifest.GetAllDependencies(assetBundleName); foreach (var depend in dependencies) { SyncLoadAssetBundle(depend); } return SyncLoadAssetBundle(assetBundleName); } /// <summary> /// 根据AB包名同步加载AssetBundle /// </summary> private AssetBundle SyncLoadAssetBundle(string assetBundleName) { AssetBundleUnit unit = null; if (!mAssetBundleUnitDict.TryGetValue(assetBundleName, out unit)) { var path = PathUtil.GetLocalAssetBundleFilePath(assetBundleName); var assetBundle = AssetBundle.LoadFromFile(path); if (assetBundle == null) { Debugger.LogError("Load AssetBundle Error: " + assetBundleName); return null; } unit = mAssetBundleUnitPool.Spawn(); unit.AssetBundle = assetBundle; unit.RefCount++; mAssetBundleUnitDict.Add(assetBundleName, unit); } else { unit.RefCount++; } return unit.AssetBundle; }
打app
整包的时候,备份一份lua
全量文件,后面打lua
增量包的时候,根据文件差异进行比对,新增和差异的lua文件打成一个lua_update.bundle
,放在一个update
文件夹中,并压缩成zip
,放到服务器端,客户端通过https
下载增量包并解压到Application.persistentDataPath
目录。游戏加载lua
文件的时候,优先从lua_update.bundle
中查找。
做个编辑器工具,指定某个或某些资源文件(预设、音频、动画、材质等),打成多个assetbundle
,放在一个update
文件夹中,并压缩成一个zip
,放到服务器端,客户端通过https
下载增量包并解压到Application.persistentDataPath
目录。
游戏加载资源文件的时候,优先从update
文件夹中查找对应的资源文件。
persistentDataPath/res/
├──/update/
│ ├──/lua/
│ │ └──lua_update.bundle #lua增量bundle
│ ├──/res/
│ │ ├──aaa.bundle #预设aaa的bundle
│ │ ├──bbb.bundle #音频bbb的bundle
│ │ └──... #其他各种格式的资源bundle
│ └──/cfg/
│ ├──cfg.bundle #配置增量bundle
│ └──... #其他文本或二进制文件增量bundle
├──out_put.log #游戏日志
└──...
关于persistentDataPath
,可以参见我这篇博客:https://blog.csdn.net/linxinfa/article/details/51679528
使用命令行运行unity并执行某个静态函数(运用于命令行打包和批量打包)
https://blog.csdn.net/linxinfa/article/details/70914939
Unity与iOS交互(XUPorter的使用)
https://blog.csdn.net/linxinfa/article/details/87103423
Unity打iOS之xcodeapi的使用
https://blog.csdn.net/linxinfa/article/details/87618408
Copyright © 2003-2013 www.wpsshop.cn 版权所有,并保留所有权利。