I have a very large 3D world/Environment which
I have divided into 1000 x 1000 m (1km) tiles.
Made assetbundles of all tiles and currently there are only 5 asset bundles (Expected to grow significantly maybe around 1000 asset bundles).
- Loading\unloading these asset bundles, i am calculating the distance of my player/camera with the tile and then calling for load or unload.
Please see below simple script (Loading tiles based on distance):
public Vector3 tileSize;
public int maxDistance;
public MultipleAssetBundleLoader[] tiles;
void Start()
{
this.tiles = FindObjectsOfType<MultipleAssetBundleLoader>();
}
void DeactivateDistantTiles()
{
foreach (MultipleAssetBundleLoader tile in tiles)
{
Vector3 tilePosition = tile.gameObject.transform.position + (tileSize / 2f);
float xDistance = Mathf.Abs(tilePosition.x - playerPosition.x);
float zDistance = Mathf.Abs(tilePosition.z - playerPosition.z);
if (xDistance + zDistance > maxDistance)
{
tile.DestroyBundleObject();
//tile.SetActive(false);
}
else
{
tile.StartDownloadingAB();
}
}
}
void Update()
{
DeactivateDistantTiles();
}
The function StartDownloadingAB simply download the asset bundles and instantiate game object from server or cache while DestroyBundleObject deactive the game object of the loaded bundle (if available). Here are code snippet for download the asset bundle:
public void StartDownloadingAB()
{
if (BundleLoadStatus == BundleLoadStatusEnum.bundleNotLoadedYet)
{
BundleLoadStatus = BundleLoadStatusEnum.bundlesLoading;
downloadABRef = StartCoroutine(DownloadAB());
}
else if (bundleObjectsDeactivated == true && BundleLoadStatus == BundleLoadStatusEnum.bundlesHasLoaded)
{
BundleObjectActive(true);
}
}
public IEnumerator DownloadAB()
{
if (isBundleLoading == true)
yield return false;
BundleLoadStatus = BundleLoadStatusEnum.bundlesLoading;
isBundleLoading = true;
//Debug.Log("loading " + url);
www = UnityWebRequestAssetBundle.GetAssetBundle(url);
yield return www.SendWebRequest();
if (www.error != null)
{
Debug.LogError("assetBundleURL : " + url);
Debug.LogError("www error : " + www.error);
www.Dispose();
www = null;
yield break;
}
AssetBundle bundle = ((DownloadHandlerAssetBundle)www.downloadHandler).assetBundle;
GameObject bundlePrefab = null;
bundlePrefab = (GameObject)bundle.LoadAsset(bundle.name);
AssetBundleRequest bundlePrefabAsync = bundle.LoadAssetAsync(bundle.name, typeof(GameObject));
yield return bundlePrefab;
if (bundlePrefab != null)
{
//assetBundleToLoadObj = (GameObject)Instantiate(bundlePrefab);
assetBundleToLoadObj = Instantiate(bundlePrefabAsync.asset as GameObject);
assetBundleToLoadObj.transform.parent = envParent.transform;
floorL7MeshRenderer.enabled = false;
}
www.Dispose();
www = null;
// try to cleanup memory
Resources.UnloadUnusedAssets();
bundle.Unload(false);
//bundle = null;
isBundleLoading = false;
BundleLoadStatus = BundleLoadStatusEnum.bundlesHasLoaded;
}
And For Destroying (actually deactivating the object as destroy is expensive function) the bundle.
Performance Issue:
The code is working fine and I am able to load/unload the asset bundle But the problems are
its performance is not good (The loop is expected to grow).
The Webgl is leggy sometime and it is not seamless or smoothly runs.
- When downloading the content(asset bundles) the game freeze despite using LoadAssetAsync.
Can anyone help me to write more efficient and elegant way to load/unload asset bundle ?