Unity5打包assetbundle
2016-04-29 15:42
477 查看
Unity5打包assetbundle
using System; using System.Collections.Generic; using System.IO; using UnityEditor; using UnityEngine; public class AssetBundleExporterGUI { private static readonly string BUNDLE_PATH_ART = System.Environment.CurrentDirectory + "/../../../../../starts-art/Assetbundles/"; private static readonly string BUNDLE_PATH_GAME = System.Environment.CurrentDirectory + "/../../../../../starts-game-assets/trunk/assetbundles/"; private const string IOS_BUNDLE_PATH = "ios/"; private const string ANDROID_BUNDLE_PATH = "android/"; private const string WEBPLAYER_BUNDLE_PATH = "webplayer/"; private const string ASSETBUNDLE_EXT = ".assetbundle"; private const string PREFAB_PATH = "Assets/_prefabs/{0}.prefab"; // This is our one-and-only dependency bundle. Any downloaded bundle can reference this, // which means any assets within it won't be duplicated in any dependent bundle. private static string PREFAB_EXT = ".prefab"; private static string SHARED_PREFAB = "gui_shared"; private static string SHARED_PREFAB_PATH = "Assets/_prefabs/" + SHARED_PREFAB; private const string SHARED_BUNDLE = "gui_shared"; // These are the bundles that do not have any dependency. These bundles are intended to be // loaded on-demand on the client because they can contain textures that we do not want to // have always loaded in memory. // // IMPORTANT: None of these bundles should be in GUI_PRELOADED_SCREENS in AssetConstants.cs // located in the starts client codebase. If you are adding a new independent bundle, please // ensure this or communicate this to the dev implementing it. // // Bundles come in two categories: // 1. always-loaded, does not contain its own textures, depends on gui_shared // 2. loaded on-demand, does not depend on gui_shared // All of the following are true: // "If a bundle is always loaded, then it's dependent on gui_shared" // "If a bundle is not always loaded, then it's not dependent on gui_shared" // "If a bundle is dependent on gui_shared, then it's always loaded" // "If a bundle is not dependent on gui_shared, then it's not always loaded" // We have 1 exception: // gui_hud depends on gui_shared and also has a few textures // private static readonly string[] independentBundles = new string[] { // The shared bundle doesn't depend on itself. SHARED_BUNDLE, "gui_xxxxxxxxx", }; private const string HUD_BUNDLE = "gui_hud"; private static string selectedPath; [MenuItem("Assets/StaRTS/Build Selected AssetBundle(s) - Android", false, 1)] public static void ExportSelectionAndroid() { ExportSelectionTarget(BuildTarget.Android); } [MenuItem("Assets/StaRTS/Build Selected AssetBundle(s) - iOS", false, 2)] public static void ExportSelectionIOS() { ExportSelectionTarget(BuildTarget.iOS); } [MenuItem("Assets/StaRTS/Build Selected AssetBundle(s) - WebPlayer", false, 3)] public static void ExportSelectionWebPlayer() { ExportSelectionTarget(BuildTarget.WebPlayer); } // Useful for when you only want to export to a single target and no others. private static void ExportSelectionTarget(BuildTarget target) { if (!Start()) { return; } /*UnityEngine.Object[] prefabs; List<string> dependencies; if (!GetSelectedPrefabs(out prefabs, out dependencies)) { return; }*/ UnityEngine.Object[] prefabs = Selection.GetFiltered(typeof(UnityEngine.Object), SelectionMode.DeepAssets); if (!ExportPrefabs(prefabs, target)) { return; } Success(); } // Useful for when you want all targets. It makes sure to order the targets smartly. [MenuItem("Assets/StaRTS/Build Selected AssetBundle(s) - All Platforms", false, 4)] public static void ExportSelectionAll() { if (!Start()) { return; } /*UnityEngine.Object[] prefabs; List<string> dependencies; if (!GetSelectedPrefabs(out prefabs, out dependencies)) { return; }*/ List<BuildTarget> targets = new List<BuildTarget>(); targets.Add(BuildTarget.Android); targets.Add(BuildTarget.iOS); targets.Add(BuildTarget.WebPlayer); // Ensure that the current build target is the first target in the // list to minimize the amount of asset re-importing that is done. // Whichever was used last will be used first in the subsequent export for (int i = 0; i < targets.Count; i++) { if (targets[i] == EditorUserBuildSettings.activeBuildTarget) { if (i != 0) { targets.Insert(0, targets[i]); targets.RemoveAt(i + 1); } break; } } UnityEngine.Object[] prefabs = Selection.GetFiltered(typeof(UnityEngine.Object), SelectionMode.DeepAssets); for (int i = 0; i < targets.Count; i++) { if (!ExportPrefabs(prefabs, targets[i])) { return; } } Success(); } static private bool GetSelectedPrefabs(out UnityEngine.Object[] prefabs, out List<string> dependencies) { dependencies = new List<string>(); // Begin() already ensured this was non-empty. UnityEngine.Object[] selection = Selection.GetFiltered(typeof(UnityEngine.Object), SelectionMode.DeepAssets); // Store prefab objects in a new array for multiple target // exports. When the editor re-imports assets for a new target, // the selection is lost. prefabs = new UnityEngine.Object[selection.Length]; for (int i = 0; i < selection.Length; i++) { string bundleName = selection[i].name; List<string> deps = new List<string>(); deps.Add(SHARED_BUNDLE); for (int j = 0, jlen = independentBundles.Length; j < jlen; j++) { if (bundleName == independentBundles[j]) { deps.Clear(); break; } } if (i == 0) { dependencies.AddRange(deps); } else { bool matches = deps.Count == dependencies.Count; if (matches) { for (int j = 0; j < deps.Count; j++) { if (dependencies[j].IndexOf(deps[j]) < 0) { matches = false; break; } } } if (!matches) { // We require that all bundles to be built have the same dependencies. Error("The selected bundles don't have the same dependencies.\n" + "Try building self-contained bundles separately " + "from those that depend on the shared bundle."); return false; } } prefabs[i] = selection[i]; } return true; } private static bool ExportPrefabs( UnityEngine.Object[] prefabs, BuildTarget target) { Debug.Log("Exporting bundles for " + target); EditorUserBuildSettings.SwitchActiveBuildTarget(target); SetPathAndExportBundle(prefabs, target); return true; } // Returns true if the given prefab has no textures of its own, // outside of the given dependency prefab. // If returns false, assetNames will be set to a newline-separated list of offending assets. private static bool IsValidDependency(UnityEngine.Object prefab, UnityEngine.Object dependencyPrefab, out string assetNames) { bool valid = true; assetNames = null; string[] prefabPaths = new string[] { string.Format(PREFAB_PATH, prefab.name) }; string[] prefabAssets = AssetDatabase.GetDependencies(prefabPaths); string[] dependencyPaths = new string[] { string.Format(PREFAB_PATH, dependencyPrefab.name) }; string[] dependencyAssets = AssetDatabase.GetDependencies(dependencyPaths); // If everything in the prefab is also in the dependency bundle, then none of it will // actually get bundled with the prefab, and that's the goal. for (int i = 0, iCount = prefabAssets.Length; i < iCount; i++) { string assetName = prefabAssets[i]; // These are the legal asset types. Anything else is considered illegal to have in an // depdendent bundle that isn't also inside the depdendency bundle. // NOTE: Mainly we want to check .png, .ttf, .prefab, .shader, but rather than only // checking those, it's safer to do the reverse: allow known legal assets to be skipped. // That way, any new type of asset that we find will not be skipped and either it's a // proper dependency, or it'll cause the error to pop, and we'll consider what to do // about it. Either fix the asset, or add the new extension to our "legal" list. if (assetName == prefabPaths[0] || // Ignore the root object. assetName.EndsWith(".cs") || // Scripts only have references bundled. assetName.EndsWith(".mat") || // Materials are lightweight, they reference shaders // and textures, which themselves are prevented. assetName.EndsWith(".controller") || assetName.EndsWith(".anim") || assetName.EndsWith(".fbx")) { continue; } bool found = false; for (int j = 0, jCount = dependencyAssets.Length; j < jCount; j++) { if (assetName == dependencyAssets[j]) { found = true; break; } } if (!found) { valid = false; assetNames = assetNames == null ? assetName : assetNames + "\n" + assetName; } } return valid; } private static bool Start() { UnityEngine.Object[] selection = Selection.GetFiltered(typeof(UnityEngine.Object), SelectionMode.DeepAssets); if (selection.Length < 1) { Debug.Log("No prefabs were selected to bundle!"); return false; } return AskForExportPath(); } private static void Success() { EditorUtility.DisplayDialog("Export complete!", string.Empty , "OK", string.Empty ); } private static void Error(string error) { Debug.LogError(error); EditorUtility.DisplayDialog("Error", error, "OK", string.Empty); } private static bool AskForExportPath() { int option = EditorUtility.DisplayDialogComplex( "Where would you like the bundles saved?", "Choose starts-art to export the bundle for an engineer to grab " + "for integration. Choose starts-game-assets to test the bundle " + "locally and potentially commit to production.", "starts-art", "Other", "starts-game-assets"); string baseDirectory = string.Empty ; switch (option) { case 0: baseDirectory = BUNDLE_PATH_ART; break; case 1: baseDirectory = EditorUtility.OpenFolderPanel( "Select the base export directory", string.Empty , string.Empty) + "/"; break; case 2: baseDirectory = BUNDLE_PATH_GAME; break; default: Debug.Log("Invalid selection for export."); // Shouldn't be possible. return false; } // Verify path exists if (baseDirectory == string.Empty || !Directory.Exists(baseDirectory)) { Error("Base directory does not exist: " + baseDirectory); return false; } selectedPath = baseDirectory; // Create subdirectories if they do not exist if (!Directory.Exists(baseDirectory + ANDROID_BUNDLE_PATH)) { Directory.CreateDirectory(baseDirectory + ANDROID_BUNDLE_PATH); } if (!Directory.Exists(baseDirectory + IOS_BUNDLE_PATH)) { Directory.CreateDirectory(baseDirectory + IOS_BUNDLE_PATH); } if (!Directory.Exists(baseDirectory + WEBPLAYER_BUNDLE_PATH)) { Directory.CreateDirectory(baseDirectory + WEBPLAYER_BUNDLE_PATH); } return true; } private static void SetPathAndExportBundle(UnityEngine.Object[] prefabs, BuildTarget target) { string path = selectedPath; switch (target) { case BuildTarget.iOS: path += IOS_BUNDLE_PATH; break; case BuildTarget.Android: path += ANDROID_BUNDLE_PATH; break; case BuildTarget.WebPlayer: path += WEBPLAYER_BUNDLE_PATH; break; } ExportBundle(prefabs, path, target, false); } static private bool ExportBundle(UnityEngine.Object[] prefab, string path, BuildTarget target, bool combined) { string directoryPath = Path.GetDirectoryName(path); if (!Directory.Exists(directoryPath)) { Directory.CreateDirectory(directoryPath); } AssetBundleBuild[] buildMap; List<UnityEngine.Object> independentBundles = new List<UnityEngine.Object>(); string prefabPath; if (combined) { buildMap = new AssetBundleBuild[2]; buildMap[0].assetBundleName = SHARED_PREFAB + ASSETBUNDLE_EXT; buildMap[0].assetNames = AssetDatabase.GetDependencies(new string[]{SHARED_PREFAB_PATH + PREFAB_EXT}); buildMap[1].assetBundleName = prefab[0].name + ASSETBUNDLE_EXT; for (int i = 0; i < prefab.Length; i++) { prefabPath = AssetDatabase.GetAssetPath(prefab[i]); buildMap[1].assetNames = new string[]{prefabPath}; } } else { buildMap = new AssetBundleBuild[prefab.Length + 1]; buildMap[0].assetBundleName = SHARED_PREFAB + ASSETBUNDLE_EXT; buildMap[0].assetNames = AssetDatabase.GetDependencies(new string[] {SHARED_PREFAB_PATH + PREFAB_EXT}); for (int i = 0; i < prefab.Length; i++) { prefabPath = AssetDatabase.GetAssetPath(prefab[i]); if (IsIndependentBundle(prefab[i].name)) { independentBundles.Add(prefab[i]); } else { buildMap[i + 1].assetBundleName = prefab[i].name + ASSETBUNDLE_EXT; buildMap[i + 1].assetNames = new string[]{prefabPath}; } } } BuildPipeline.BuildAssetBundles(directoryPath, buildMap, BuildAssetBundleOptions.ForceRebuildAssetBundle, target); if (independentBundles.Count > 0) { buildMap = new AssetBundleBuild[independentBundles.Count]; for (int i = 0; i < independentBundles.Count; i++) { prefabPath = AssetDatabase.GetAssetPath(independentBundles[i]); buildMap[i].assetBundleName = independentBundles[i].name + ASSETBUNDLE_EXT; buildMap[i].assetNames = new string[]{prefabPath}; } BuildPipeline.BuildAssetBundles(directoryPath, buildMap, BuildAssetBundleOptions.ForceRebuildAssetBundle, target); } return true; } static private bool IsIndependentBundle(string prefabName) { int index = Array.FindIndex(independentBundles, item => item.Equals(prefabName)); if (index > 0) { return true; } return false; } }
相关文章推荐
- Vuforia 在Unity 中失焦的问题
- 使用Unity3D 5.3.4 模仿2D游戏 FlappyBird(一)
- unity安装记录
- Unity 编辑器列表控件
- 在unity3d中用EasyTouch的操纵杆控制相对于不同角度的摄像机的第三人物视角的相对位移的代码段
- 简要分析unity3d中剪不断理还乱的yield
- 基于unity的飞行模拟设计
- unity发射弓箭轨迹的实现
- Shader之学习笔记三
- Unity3D 5.3.4的UGUI编程
- unity编译时自动结束项目运行
- unity渲染层级关系小结
- Unity3d碰撞检测中碰撞器与触发器的区别
- Unity3D中世界坐标转换到NGUI坐标
- Unity世界坐标与屏幕坐标之间如何转换
- Unity ScreentoWorldPoint中的z坐标说明
- Unity3D的几种坐标系
- unity3D 彻底搞懂 Quaternion LookRotation FromToRotation SetLookRotation方法
- Visual Studio 2015 Tools for Unity安装
- Unity协程和线程的区别