Огромный мир загрузки / выгрузки в Unity Webgl с использованием комплектов активов - PullRequest
2 голосов
/ 08 апреля 2019

У меня очень большой трехмерный мир / Окружающая среда который

  1. У меня есть , разделенные на 1000 x 1000 м (1 км) плиток .

  2. Созданы пакеты активов из всех плиток , и в настоящее время существует только 5 пакетов активов (ожидается значительный рост, возможно, около 1000 пакеты активов).

  3. Загрузка \ выгрузка этих пакетов активов , я рассчитываю расстояние моего игрока / камеры с плиткой и затем призываю к загрузить или разгрузить.

Пожалуйста, смотрите ниже простой скрипт (Загрузка плиток на основе расстояния):

        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();
        }

Функция StartDownloadingAB просто загружает пакеты ресурсов и создает экземпляр игрового объекта с сервера или из кэша, в то время как DestroyBundleObject отключает игровой объект загруженного пакета (если доступно). Вот фрагмент кода для загрузки пакета ресурсов:

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;
}

И для уничтожения (на самом деле деактивация объекта, так как уничтожение является дорогой функцией) связки.

Проблема производительности:

Код работает нормально, и я могу загрузить / выгрузить пакет ресурсов, но проблемы

  1. его производительность не очень хорошая (ожидается рост цикла).

  2. Иногда Webgl длинноногий, он не гладкий или плавный.

  3. При загрузке контента (комплектов ресурсов) игра останавливается, несмотря на использование LoadAssetAsync .

Может кто-нибудь помочь мне написать более эффективный и элегантный способ загрузки / выгрузки пакета активов?

1 Ответ

2 голосов
/ 08 апреля 2019

Прежде всего, вы должны взглянуть на профилировщик и увидеть точки дросселирования вашего приложения, если оно застряло при загрузке пакетов (сопрограммы все еще выполняются в главном потоке и могут вызывать лаги), вы можете использовать асинхронная загрузка .Но вы хотели бы вызвать их раньше времени (когда игрок находится ближе к другому блоку, так что он готов, когда он фактически достигнет блока).Если ваши узкие места находятся где-то еще, например, что-то, связанное с рендерингом, вы можете подойти к этому как-то иначе (меньшие активы с меньшим количеством вершин / треугольников или более агрессивным отбраковкой).В любом случае для лучшего суждения вам нужно определить, где проблема, но с первого взгляда кажется, что проблема заключается в загрузке ресурса в основной поток.

...