Wayback Machinekoobas.hobune.stream
May JUN Jul
Previous capture 12 Next capture
2021 2022 2023
1 capture
12 Jun 22 - 12 Jun 22
sparklines
Close Help
  • Products
  • Solutions
  • Made with Unity
  • Learning
  • Support & Services
  • Community
  • Asset Store
  • Get Unity

UNITY ACCOUNT

You need a Unity Account to shop in the Online and Asset Stores, participate in the Unity Community and manage your license portfolio. Login Create account
  • Blog
  • Forums
  • Answers
  • Evangelists
  • User Groups
  • Beta Program
  • Advisory Panel

Navigation

  • Home
  • Products
  • Solutions
  • Made with Unity
  • Learning
  • Support & Services
  • Community
    • Blog
    • Forums
    • Answers
    • Evangelists
    • User Groups
    • Beta Program
    • Advisory Panel

Unity account

You need a Unity Account to shop in the Online and Asset Stores, participate in the Unity Community and manage your license portfolio. Login Create account

Language

  • Chinese
  • Spanish
  • Japanese
  • Korean
  • Portuguese
  • Ask a question
  • Spaces
    • Default
    • Help Room
    • META
    • Moderators
    • Topics
    • Questions
    • Users
    • Badges
  • Home /
  • Help Room /
avatar image
0
Question by Sasa_Meden · Jul 13, 2016 at 10:58 AM · assetbundlecache

Help with asset bundle manager

Hi guys, I'm new to Asset Bundle Manager. I use latest Unity , my target platform is Android. I have two scenes I added to AssetBundle and put them on my ftp server. When I'm online assets download and scenes load (I see increase in my cache size on my phone). But when offline ,scenes don't load from cache. I have no idea what I'm supposed to do when assets are downloaded and need to be loaded from cache. Here is my Manager code: I made no changes to this, just left it as it is from Unity store.

 using UnityEngine;
 #if UNITY_EDITOR    
 using UnityEditor;
 #endif
 using System.Collections;
 using System.Collections.Generic;
 using PlayerPrefs = CodeCons.PlayerPrefs;
 
 /*
      In this demo, we demonstrate:
     1.    Automatic asset bundle dependency resolving & loading.
         It shows how to use the manifest assetbundle like how to get the dependencies etc.
     2.    Automatic unloading of asset bundles (When an asset bundle or a dependency thereof is no longer needed, the asset bundle is unloaded)
     3.    Editor simulation. A bool defines if we load asset bundles from the project or are actually using asset bundles(doesn't work with assetbundle variants for now.)
         With this, you can player in editor mode without actually building the assetBundles.
     4.    Optional setup where to download all asset bundles
     5.    Build pipeline build postprocessor, integration so that building a player builds the asset bundles and puts them into the player data (Default implmenetation for loading assetbundles from disk on any platform)
     6.    Use WWW.LoadFromCacheOrDownload and feed 128 bit hash to it when downloading via web
         You can get the hash from the manifest assetbundle.
     7.    AssetBundle variants. A prioritized list of variants that should be used if the asset bundle with that variant exists, first variant in the list is the most preferred etc.
 */
 
 namespace AssetBundles
 {    
     // Loaded assetBundle contains the references count which can be used to unload dependent assetBundles automatically.
     public class LoadedAssetBundle
     {
         public AssetBundle m_AssetBundle;
         public int m_ReferencedCount;
         
         public LoadedAssetBundle(AssetBundle assetBundle)
         {
             m_AssetBundle = assetBundle;
             m_ReferencedCount = 1;
         }
     }
     
     // Class takes care of loading assetBundle and its dependencies automatically, loading variants automatically.
     public class AssetBundleManager : MonoBehaviour
     {
         public enum LogMode { All, JustErrors };
         public enum LogType { Info, Warning, Error };
     
         static LogMode m_LogMode = LogMode.All;
         static string m_BaseDownloadingURL = "";
         static string[] m_ActiveVariants =  {  };
         static AssetBundleManifest m_AssetBundleManifest = null;
     #if UNITY_EDITOR    
         static int m_SimulateAssetBundleInEditor = -1;
         const string kSimulateAssetBundles = "SimulateAssetBundles";
     #endif
     
         static Dictionary<string, LoadedAssetBundle> m_LoadedAssetBundles = new Dictionary<string, LoadedAssetBundle> ();
         static Dictionary<string, WWW> m_DownloadingWWWs = new Dictionary<string, WWW> ();
         static Dictionary<string, string> m_DownloadingErrors = new Dictionary<string, string> ();
         static List<AssetBundleLoadOperation> m_InProgressOperations = new List<AssetBundleLoadOperation> ();
         static Dictionary<string, string[]> m_Dependencies = new Dictionary<string, string[]> ();
     
         public static LogMode logMode
         {
             get { return m_LogMode; }
             set { m_LogMode = value; }
         }
     
         // The base downloading url which is used to generate the full downloading url with the assetBundle names.
         public static string BaseDownloadingURL
         {
             get { return m_BaseDownloadingURL; }
             set { m_BaseDownloadingURL = value; }
         }
     
         // Variants which is used to define the active variants.
         public static string[] ActiveVariants
         {
             get { return m_ActiveVariants; }
             set { m_ActiveVariants = value; }
         }
     
         // AssetBundleManifest object which can be used to load the dependecies and check suitable assetBundle variants.
         public static AssetBundleManifest AssetBundleManifestObject
         {
             set {m_AssetBundleManifest = value; }
         }
     
         private static void Log(LogType logType, string text)
         {
             if (logType == LogType.Error)
                 Debug.LogError("[AssetBundleManager] " + text);
             else if (m_LogMode == LogMode.All)
                 Debug.Log("[AssetBundleManager] " + text);
         }
     
     #if UNITY_EDITOR
         // Flag to indicate if we want to simulate assetBundles in Editor without building them actually.
         public static bool SimulateAssetBundleInEditor 
         {
             get
             {
                 if (m_SimulateAssetBundleInEditor == -1)
                     m_SimulateAssetBundleInEditor = EditorPrefs.GetBool(kSimulateAssetBundles, true) ? 1 : 0;
                 
                 return m_SimulateAssetBundleInEditor != 0;
             }
             set
             {
                 int newValue = value ? 1 : 0;
                 if (newValue != m_SimulateAssetBundleInEditor)
                 {
                     m_SimulateAssetBundleInEditor = newValue;
                     EditorPrefs.SetBool(kSimulateAssetBundles, value);
                 }
             }
         }
         
     
         #endif
     
         private static string GetStreamingAssetsPath()
         {
             if (Application.isEditor)
                 return "file://" +  System.Environment.CurrentDirectory.Replace("\\", "/"); // Use the build output folder directly.
             else if (Application.isWebPlayer)
                 return System.IO.Path.GetDirectoryName(Application.absoluteURL).Replace("\\", "/")+ "/StreamingAssets";
             else if (Application.isMobilePlatform || Application.isConsolePlatform)
                 return Application.streamingAssetsPath;
             else // For standalone player.
                 return "file://" +  Application.streamingAssetsPath;
         }
     
         public static void SetSourceAssetBundleDirectory(string relativePath)
         {
             BaseDownloadingURL = GetStreamingAssetsPath() + relativePath;
         }
         
         public static void SetSourceAssetBundleURL(string absolutePath)
         {
             BaseDownloadingURL = absolutePath + Utility.GetPlatformName() + "/";
         }
     
         public static void SetDevelopmentAssetBundleServer()
         {
             #if UNITY_EDITOR
             // If we're in Editor simulation mode, we don't have to setup a download URL
             if (SimulateAssetBundleInEditor)
                 return;
             #endif
             
             TextAsset urlFile = Resources.Load("AssetBundleServerURL") as TextAsset;
             string url = (urlFile != null) ? urlFile.text.Trim() : null;
             if (url == null || url.Length == 0)
             {
                 Debug.LogError("Development Server URL could not be found.");
                 //AssetBundleManager.SetSourceAssetBundleURL("http://localhost:7888/" + UnityHelper.GetPlatformName() + "/");
             }
             else
             {
                 AssetBundleManager.SetSourceAssetBundleURL(url);
             }
         }
         
         // Get loaded AssetBundle, only return vaild object when all the dependencies are downloaded successfully.
         static public LoadedAssetBundle GetLoadedAssetBundle (string assetBundleName, out string error)
         {
             if (m_DownloadingErrors.TryGetValue(assetBundleName, out error) )
                 return null;
         
             LoadedAssetBundle bundle = null;
             m_LoadedAssetBundles.TryGetValue(assetBundleName, out bundle);
             if (bundle == null)
                 return null;
             
             // No dependencies are recorded, only the bundle itself is required.
             string[] dependencies = null;
             if (!m_Dependencies.TryGetValue(assetBundleName, out dependencies) )
                 return bundle;
             
             // Make sure all dependencies are loaded
             foreach(var dependency in dependencies)
             {
                 if (m_DownloadingErrors.TryGetValue(assetBundleName, out error) )
                     return bundle;
     
                 // Wait all the dependent assetBundles being loaded.
                 LoadedAssetBundle dependentBundle;
                 m_LoadedAssetBundles.TryGetValue(dependency, out dependentBundle);
                 if (dependentBundle == null)
                     return null;
             }
     
             return bundle;
         }
     
         static public AssetBundleLoadManifestOperation Initialize ()
         {
             return Initialize(Utility.GetPlatformName());
         }
             
     
         // Load AssetBundleManifest.
         static public AssetBundleLoadManifestOperation Initialize (string manifestAssetBundleName)
         {
     #if UNITY_EDITOR
             Log (LogType.Info, "Simulation Mode: " + (SimulateAssetBundleInEditor ? "Enabled" : "Disabled"));
     #endif
     
             var go = new GameObject("AssetBundleManager", typeof(AssetBundleManager));
             DontDestroyOnLoad(go);
         
     #if UNITY_EDITOR    
             // If we're in Editor simulation mode, we don't need the manifest assetBundle.
             if (SimulateAssetBundleInEditor)
                 return null;
     #endif
     
             LoadAssetBundle(manifestAssetBundleName, true);
             var operation = new AssetBundleLoadManifestOperation (manifestAssetBundleName, "AssetBundleManifest", typeof(AssetBundleManifest));
             m_InProgressOperations.Add (operation);
             return operation;
         }
         
         // Load AssetBundle and its dependencies.
         static protected void LoadAssetBundle(string assetBundleName, bool isLoadingAssetBundleManifest = false)
         {
             Log(LogType.Info, "Loading Asset Bundle " + (isLoadingAssetBundleManifest ? "Manifest: " : ": ") + assetBundleName);
     
     #if UNITY_EDITOR
             // If we're in Editor simulation mode, we don't have to really load the assetBundle and its dependencies.
             if (SimulateAssetBundleInEditor)
                 return;
     #endif
     
             if (!isLoadingAssetBundleManifest)
             {
                 if (m_AssetBundleManifest == null)
                 {
                     Debug.LogError("Please initialize AssetBundleManifest by calling AssetBundleManager.Initialize()");
                     return;
                 }
             }
     
             // Check if the assetBundle has already been processed.
             bool isAlreadyProcessed = LoadAssetBundleInternal(assetBundleName, isLoadingAssetBundleManifest);
     
             // Load dependencies.
             if (!isAlreadyProcessed && !isLoadingAssetBundleManifest)
                 LoadDependencies(assetBundleName);
         }
         
         // Remaps the asset bundle name to the best fitting asset bundle variant.
         static protected string RemapVariantName(string assetBundleName)
         {
             string[] bundlesWithVariant = m_AssetBundleManifest.GetAllAssetBundlesWithVariant();
 
             string[] split = assetBundleName.Split('.');
 
             int bestFit = int.MaxValue;
             int bestFitIndex = -1;
             // Loop all the assetBundles with variant to find the best fit variant assetBundle.
             for (int i = 0; i < bundlesWithVariant.Length; i++)
             {
                 string[] curSplit = bundlesWithVariant[i].Split('.');
                 if (curSplit[0] != split[0])
                     continue;
                 
                 int found = System.Array.IndexOf(m_ActiveVariants, curSplit[1]);
                 
                 // If there is no active variant found. We still want to use the first 
                 if (found == -1)
                     found = int.MaxValue-1;
                         
                 if (found < bestFit)
                 {
                     bestFit = found;
                     bestFitIndex = i;
                 }
             }
             
             if (bestFit == int.MaxValue-1)
             {
                 Debug.LogWarning("Ambigious asset bundle variant chosen because there was no matching active variant: " + bundlesWithVariant[bestFitIndex]);
             }
             
             if (bestFitIndex != -1)
             {
                 return bundlesWithVariant[bestFitIndex];
             }
             else
             {
                 return assetBundleName;
             }
         }
     
         // Where we actuall call WWW to download the assetBundle.
         static protected bool LoadAssetBundleInternal (string assetBundleName, bool isLoadingAssetBundleManifest)
         {
             // Already loaded.
             LoadedAssetBundle bundle = null;
             m_LoadedAssetBundles.TryGetValue(assetBundleName, out bundle);
             if (bundle != null)
             {
                 bundle.m_ReferencedCount++;
                 return true;
             }
     
             // @TODO: Do we need to consider the referenced count of WWWs?
             // In the demo, we never have duplicate WWWs as we wait LoadAssetAsync()/LoadLevelAsync() to be finished before calling another LoadAssetAsync()/LoadLevelAsync().
             // But in the real case, users can call LoadAssetAsync()/LoadLevelAsync() several times then wait them to be finished which might have duplicate WWWs.
             if (m_DownloadingWWWs.ContainsKey(assetBundleName) )
                 return true;
     
             WWW download = null;
             string url = m_BaseDownloadingURL + assetBundleName;
         
             // For manifest assetbundle, always download it as we don't have hash for it.
             if (isLoadingAssetBundleManifest)
                 download = new WWW(url);
             else
                 download = WWW.LoadFromCacheOrDownload(url, m_AssetBundleManifest.GetAssetBundleHash(assetBundleName), 0); 
     
             m_DownloadingWWWs.Add(assetBundleName, download);
     
             return false;
         }
     
         // Where we get all the dependencies and load them all.
         static protected void LoadDependencies(string assetBundleName)
         {
             if (m_AssetBundleManifest == null)
             {
                 Debug.LogError("Please initialize AssetBundleManifest by calling AssetBundleManager.Initialize()");
                 return;
             }
     
             // Get dependecies from the AssetBundleManifest object..
             string[] dependencies = m_AssetBundleManifest.GetAllDependencies(assetBundleName);
             if (dependencies.Length == 0)
                 return;
                 
             for (int i=0;i<dependencies.Length;i++)
                 dependencies[i] = RemapVariantName (dependencies[i]);
                 
             // Record and load all dependencies.
             m_Dependencies.Add(assetBundleName, dependencies);
             for (int i=0;i<dependencies.Length;i++)
                 LoadAssetBundleInternal(dependencies[i], false);
         }
     
         // Unload assetbundle and its dependencies.
         static public void UnloadAssetBundle(string assetBundleName)
         {
     #if UNITY_EDITOR
             // If we're in Editor simulation mode, we don't have to load the manifest assetBundle.
             if (SimulateAssetBundleInEditor)
                 return;
     #endif
     
             //Debug.Log(m_LoadedAssetBundles.Count + " assetbundle(s) in memory before unloading " + assetBundleName);
     
             UnloadAssetBundleInternal(assetBundleName);
             UnloadDependencies(assetBundleName);
     
             //Debug.Log(m_LoadedAssetBundles.Count + " assetbundle(s) in memory after unloading " + assetBundleName);
         }
     
         static protected void UnloadDependencies(string assetBundleName)
         {
             string[] dependencies = null;
             if (!m_Dependencies.TryGetValue(assetBundleName, out dependencies) )
                 return;
     
             // Loop dependencies.
             foreach(var dependency in dependencies)
             {
                 UnloadAssetBundleInternal(dependency);
             }
     
             m_Dependencies.Remove(assetBundleName);
         }
     
         static protected void UnloadAssetBundleInternal(string assetBundleName)
         {
             string error;
             LoadedAssetBundle bundle = GetLoadedAssetBundle(assetBundleName, out error);
             if (bundle == null)
                 return;
     
             if (--bundle.m_ReferencedCount == 0)
             {
                 bundle.m_AssetBundle.Unload(false);
                 m_LoadedAssetBundles.Remove(assetBundleName);
     
                 Log(LogType.Info, assetBundleName + " has been unloaded successfully");
             }
         }
     
         void Update()
         {
             // Collect all the finished WWWs.
             var keysToRemove = new List<string>();
             foreach (var keyValue in m_DownloadingWWWs)
             {
                 WWW download = keyValue.Value;
     
                 // If downloading fails.
                 if (download.error != null)
                 {
                     m_DownloadingErrors.Add(keyValue.Key, string.Format("Failed downloading bundle {0} from {1}: {2}", keyValue.Key, download.url, download.error));
                     keysToRemove.Add(keyValue.Key);
                     continue;
                 }
     
                 // If downloading succeeds.
                 if(download.isDone)
                 {
                     PlayerPrefs.SetBool("Game2Loaded", true);
                     PlayerPrefs.Flush();
                     AssetBundle bundle = download.assetBundle;
                     if (bundle == null)
                     {
                         m_DownloadingErrors.Add(keyValue.Key, string.Format("{0} is not a valid asset bundle.", keyValue.Key));
                         keysToRemove.Add(keyValue.Key);
                         continue;
                     }
                 
                     //Debug.Log("Downloading " + keyValue.Key + " is done at frame " + Time.frameCount);
                     m_LoadedAssetBundles.Add(keyValue.Key, new LoadedAssetBundle(download.assetBundle) );
                     keysToRemove.Add(keyValue.Key);
                 }
             }
     
             // Remove the finished WWWs.
             foreach( var key in keysToRemove)
             {
                 WWW download = m_DownloadingWWWs[key];
                 m_DownloadingWWWs.Remove(key);
                 download.Dispose();
             }
     
             // Update all in progress operations
             for (int i=0;i<m_InProgressOperations.Count;)
             {
                 if (!m_InProgressOperations[i].Update())
                 {
                     m_InProgressOperations.RemoveAt(i);
                 }
                 else
                     i++;
             }
         }
     
         // Load asset from the given assetBundle.
         static public AssetBundleLoadAssetOperation LoadAssetAsync (string assetBundleName, string assetName, System.Type type)
         {
             Log(LogType.Info, "Loading " + assetName + " from " + assetBundleName + " bundle");
     
             AssetBundleLoadAssetOperation operation = null;
     #if UNITY_EDITOR
             if (SimulateAssetBundleInEditor)
             {
                 string[] assetPaths = AssetDatabase.GetAssetPathsFromAssetBundleAndAssetName(assetBundleName, assetName);
                 if (assetPaths.Length == 0)
                 {
                     Debug.LogError("There is no asset with name \"" + assetName + "\" in " + assetBundleName);
                     return null;
                 }
     
                 // @TODO: Now we only get the main object from the first asset. Should consider type also.
                 Object target = AssetDatabase.LoadMainAssetAtPath(assetPaths[0]);
                 operation = new AssetBundleLoadAssetOperationSimulation (target);
             }
             else
     #endif
             {
                 assetBundleName = RemapVariantName (assetBundleName);
                 LoadAssetBundle (assetBundleName);
                 operation = new AssetBundleLoadAssetOperationFull (assetBundleName, assetName, type);
     
                 m_InProgressOperations.Add (operation);
             }
     
             return operation;
         }
     
         // Load level from the given assetBundle.
         static public AssetBundleLoadOperation LoadLevelAsync (string assetBundleName, string levelName, bool isAdditive)
         {
             Log(LogType.Info, "Loading " + levelName + " from " + assetBundleName + " bundle");
     
             AssetBundleLoadOperation operation = null;
     #if UNITY_EDITOR
             if (SimulateAssetBundleInEditor)
             {
                 operation = new AssetBundleLoadLevelSimulationOperation(assetBundleName, levelName, isAdditive);
             }
             else
     #endif
             {
                 assetBundleName = RemapVariantName(assetBundleName);
                 LoadAssetBundle (assetBundleName);
                 operation = new AssetBundleLoadLevelOperation (assetBundleName, levelName, isAdditive);
     
                 m_InProgressOperations.Add (operation);
             }
     
             return operation;
         }
     } // End of AssetBundleManager.
 }

//////////////////////////////////////////////////////////////////////////////////////////////////////////////// And here is my scene loader

 using UnityEngine;
 using System.Collections;
 using AssetBundles;
 
 
 public class LoadScenes : MonoBehaviour
 {
     private string sceneAssetBundle;
     private string sceneName;
     private int lvl;
     
     // Use this for initialization
     IEnumerator Start ()
     {
         lvl = LeveNumbers.GetLvlNum();
         if (lvl == 1) {
             sceneAssetBundle = "game2scene";
             sceneName = "Game2Scene";
         }
         if (lvl == 2)
         {
             sceneAssetBundle = "game3scene";
             sceneName = "Game3Scene";
         }
 
         yield return StartCoroutine(Initialize() );
         
         // Load level.
         yield return StartCoroutine(InitializeLevelAsync (sceneName, true) );
     }
 
     // Initialize the downloading url and AssetBundleManifest object.
     protected IEnumerator Initialize()
     {
         // Don't destroy this gameObject as we depend on it to run the loading script.
         DontDestroyOnLoad(gameObject);
         
         // With this code, when in-editor or using a development builds: Always use the AssetBundle Server
         // (This is very dependent on the production workflow of the project. 
         //     Another approach would be to make this configurable in the standalone player.)
         //#if DEVELOPMENT_BUILD || UNITY_EDITOR
         //AssetBundleManager.SetDevelopmentAssetBundleServer ();
 //#else
         // Use the following code if AssetBundles are embedded in the project for example via StreamingAssets folder etc:
         //AssetBundleManager.SetSourceAssetBundleURL(Application.dataPath + "/");
         // Or customize the URL based on your deployment or configuration
         AssetBundleManager.SetSourceAssetBundleURL("myftp/AssetBundles/");
 //#endif
 
         // Initialize AssetBundleManifest which loads the AssetBundleManifest object.
         var request = AssetBundleManager.Initialize();
         
         if (request != null)
             yield return StartCoroutine(request);
     }
 
     protected IEnumerator InitializeLevelAsync (string levelName, bool isAdditive)
     {
         // This is simply to get the elapsed time for this phase of AssetLoading.
         float startTime = Time.realtimeSinceStartup;
 
         // Load level from assetBundle.
         AssetBundleLoadOperation request = AssetBundleManager.LoadLevelAsync(sceneAssetBundle, levelName, isAdditive);
         if (request == null)
             yield break;
         yield return StartCoroutine(request);
 
         // Calculate and display the elapsed time.
         float elapsedTime = Time.realtimeSinceStartup - startTime;
         Debug.Log("Finished loading scene " + levelName + " in " + elapsedTime + " seconds" );
     }
 }

I'm probably missing something simple. Please excuse my noobness.

Comment
Add comment
10 |3000 characters needed characters left characters exceeded
â–¼
  • Viewable by all users
  • Viewable by moderators
  • Viewable by moderators and the original poster
  • Advanced visibility
Viewable by all users

1 Reply

· Add your reply
  • Sort: 
avatar image
0

Answer by tomekkie2 · Nov 30, 2016 at 12:28 PM

Look at this answer here: http://answers.unity3d.com/questions/522806/loading-assetbundles-when-offline.html

And then try to use: WWW.LoadFromCacheOrDownload in your LoadScenes script.

You will also have access to download.progress and be able to show the users download progress when downloading from www.

Comment
Add comment · Share
10 |3000 characters needed characters left characters exceeded
â–¼
  • Viewable by all users
  • Viewable by moderators
  • Viewable by moderators and the original poster
  • Advanced visibility
Viewable by all users

Your answer

Hint: You can notify a user about this post by typing @username

Up to 2 attachments (including images) can be used with a maximum of 524.3 kB each and 1.0 MB total.

Follow this Question

Answers Answers and Comments

64 People are following this question.

avatar image avatar image avatar image avatar image avatar image avatar image avatar image avatar image avatar image avatar image avatar image avatar image avatar image avatar image avatar image avatar image avatar image avatar image avatar image avatar image avatar image avatar image avatar image avatar image avatar image avatar image avatar image avatar image avatar image avatar image avatar image avatar image avatar image avatar image avatar image avatar image avatar image avatar image avatar image avatar image avatar image avatar image avatar image avatar image avatar image avatar image avatar image avatar image avatar image avatar image avatar image avatar image avatar image avatar image avatar image avatar image avatar image avatar image avatar image avatar image avatar image avatar image avatar image avatar image

Related Questions

IOS/Android AssetBundle Cache Cleanup 0 Answers

Assetbundles freeze on load from cache 0 Answers

Assets Bundle size increases after download 0 Answers

What is the best way to cache downloaded textures on Android/iOS ? 2 Answers

Asset Bundle - How to load from cache after download it from webrequest ? 0 Answers


Enterprise
Social Q&A

Social
Subscribe on YouTube social-youtube Follow on LinkedIn social-linkedin Follow on Twitter social-twitter Follow on Facebook social-facebook Follow on Instagram social-instagram

Footer

  • Purchase
    • Products
    • Subscription
    • Asset Store
    • Unity Gear
    • Resellers
  • Education
    • Students
    • Educators
    • Certification
    • Learn
    • Center of Excellence
  • Download
    • Unity
    • Beta Program
  • Unity Labs
    • Labs
    • Publications
  • Resources
    • Learn platform
    • Community
    • Documentation
    • Unity QA
    • FAQ
    • Services Status
    • Connect
  • About Unity
    • About Us
    • Blog
    • Events
    • Careers
    • Contact
    • Press
    • Partners
    • Affiliates
    • Security
Copyright © 2020 Unity Technologies
  • Legal
  • Privacy Policy
  • Cookies
  • Do Not Sell My Personal Information
  • Cookies Settings
"Unity", Unity logos, and other Unity trademarks are trademarks or registered trademarks of Unity Technologies or its affiliates in the U.S. and elsewhere (more info here). Other names or brands are trademarks of their respective owners.
  • Anonymous
  • Sign in
  • Create
  • Ask a question
  • Spaces
  • Default
  • Help Room
  • META
  • Moderators
  • Explore
  • Topics
  • Questions
  • Users
  • Badges