Ссылка на материал рендера gameobject после создания экземпляра из загруженного пакета ресурсов не работает - PullRequest
0 голосов
/ 08 октября 2019

Hi! Если вы хотите сэкономить время и по-прежнему помогать, прочитайте этот раздел и последний, чтобы понять мою проблему (часть 1 и 6). Так много кода было необходимо, чтобы полностью представить проблему

Использование Unity 2019.3.0b2

1.

Я создаю приложение WebGL, которое позволяет вам настроить своего персонажа с помощью ресурсовиз загруженных пакетов активов. Пока что у меня есть загрузка и создание экземпляра работы, но Я также хочу изменить загруженный материал игрового объекта на собственный цвет из средства выбора цвета . В этом случае мне нужно обратиться к адекватному Renderer . У меня есть функция, которая отправляет запрос, и это выглядит так:

private IEnumerator SendRequestCoroutine(UnityWebRequest request, UnityAction<UnityWebRequest> OnDownloadCompleteHandler, UnityAction<float> OnDownloadProgressHandler = null)
    {
        request.SendWebRequest();
        while(!request.isDone)
        {
            if(OnDownloadProgressHandler != null)
                OnDownloadProgressHandler.Invoke(request.downloadProgress);
            yield return null;
        }
        // Has to fire once more because progress stops at around 0.87,
        // never returning 1 unless download is finished.
        if (OnDownloadProgressHandler != null)
            OnDownloadProgressHandler.Invoke(1);
        OnDownloadCompleteHandler.Invoke(request);
    }

2. Я запускаю эту сопрограмму вот так:

public void DownloadAssetBundle(string url, ProgressBar bar = null)
{
    if (isRequestSend)
    {
        Alerter.ShowMessage("Request has been already send, please wait untill complete.");
        return;
    }
    UnityWebRequest request = HttpService.Instance.GetAssetBundleRequest(url);

    if(bar != null)
    {
        HttpService.Instance.SendDownloadRequest
        (
            request,
            (rq) => { OnDownloadAssetBundleCompleteHandler(rq); },
            (rq) => OnDownloadProgressHandler(rq, bar)
        );
        isRequestSend = true;
    }
    else
    {
        HttpService.Instance.SendDownloadRequest
        (
            request,
            (rq) => { OnDownloadAssetBundleCompleteHandler(rq); }
        );
        isRequestSend = true;
    }
}

3. OnDownloadAssetBundleCompleteHandler выглядит следующим образом:

//Function that will handle asset bundle when completed.
private void OnDownloadAssetBundleCompleteHandler(UnityWebRequest request)
{
    isRequestSend = false;
    if(request.isHttpError || request.isNetworkError)
    {
        //Handle downloading error
        Alerter.ShowMessage("Seems like there was a problem with downloading, try again.");
    }
    else
    {
        AssetBundle bundle;
        //Handle content update
        bundle = DownloadHandlerAssetBundle.GetContent(request);
        AssetBundleInfo assetBundleInfo = bundle.LoadAllAssets<AssetBundleInfo>().FirstOrDefault();

        if (assetBundleInfo == null)
        {
            //Handle error
            Alerter.ShowMessage("Couldn't read information about this Character Part. AssetBundleInfo null exception.");
            bundle.Unload(false);
            return;
        }
        GameObject goToLoad = null;

        goToLoad = bundle.LoadAsset<GameObject>(assetBundleInfo.ObjectName);

        if (goToLoad == null)
        {
            Alerter.ShowMessage("Couldn't read information about this Character Part. Downloaded asset's gameobject null exception.");
            bundle.Unload(false);
            return;
        }
        Sticher.ConnectComponent(goToLoad, assetBundleInfo.PartType);
        ColorSetter.Instance.ChangeSelectedBodyPart(assetBundleInfo.PartType);
        bundle.Unload(false);
    }
}

4. Теперь последний шаг - установить адекватное преобразование, чтобы мой сценарий искал компонент типа Renderer, получил его материал индекса 0 в качестве текущего материала для модификации, класс, содержащий ChangeSelectedBodyPart функция выглядит так:

using Assets.Scripts.Models.Enums;
using System.Collections;
using System.Collections.Generic;
using UnityEngine;

public class ColorSetter : MonoBehaviour
{
public Renderer rend;
public ColorPicker picker;
public static ColorSetter Instance;

private void Awake()
{
    if(Instance != null)
    {
        Destroy(this);
    }
    else
    {
        Instance = this;
        DontDestroyOnLoad(this);
    }
}

// Start is called before the first frame update
void Start()
{
    picker.onValueChanged.AddListener(color => 
    {
        if (rend == null)
            return;
        rend.material.SetColor("_BaseColor", color);
    }
    );
}

public void ChangeSelectedBodyPart(AvatarPartType p)
{
    switch(p)
    {
        case AvatarPartType.ClothesUpper:
            SetActiveMaterial(Sticher.Instance.Clothes_Upper);
            break;
        case AvatarPartType.ClothesLower:
            SetActiveMaterial(Sticher.Instance.Clothes_Lower);
            break;
        case AvatarPartType.Shoes:
            SetActiveMaterial(Sticher.Instance.Shoes);
            break;
        case AvatarPartType.Hair:
            SetActiveMaterial(Sticher.Instance.Hair);
            break;
        case AvatarPartType.Skin:
            SetActiveMaterial(Sticher.Instance.Skin);
            break;
    }
}

private void SetActiveMaterial(Transform parent)
{
    rend = parent.GetComponentInChildren<Renderer>();
}
}

5. PS. у parent есть только один дочерний элемент, содержащий компонент Renderer Теперь, наконец, проблема в том, что я не получаю правильную ссылку на материал, я получил старый, который устанавливается с помощью кнопки переключения, просто так:

    public void OnValueChanged(bool value)
{
    if(value)
    {
        ColorSetter.Instance.ChangeSelectedBodyPart(PartType);
        ButtonManager.Instance.RemoveAllButtonsFromPartsWindow();
        ButtonManager.Instance.PopulatePartsPanelWithAvatarPartsOfType(PartType);
    }
}

6. Таким образом, в заключение, когда я нажимаю на «кнопку переключения», которая представляет некоторую часть тела / одежды аватара, она правильно устанавливает своего родителя и материал через функцию, даже после того, как пакет ресурсов был загружен (но я должен нажать на тот же переключатель снова, чтобы заставить его работать), но когда я запускаю ту же функцию в OnDownloadAssetBundleCompleteHandler сразу после загрузки ресурса, он не работает: S Почему? Это связано со скоростью выгрузки активов? Любые советы по исправлению этого?

В Game View это ведет себя так: enter image description here

1 Ответ

0 голосов
/ 09 октября 2019

Я исправил это. Поскольку вы не можете использовать DestoyImmediate, как сказал @derHugo, потому что это может привести к ошибкам ссылок или даже к разрушению ресурсов, мне пришлось использовать Destroy () вместо этого перед созданием нового игрового объекта из assetbundle, однако Destroy () удалит данный объект в концекадра, пока я пытаюсь получить доступ к компоненту Renderer в только что созданном GameObject только в том же кадре, прежде чем старый будет уничтожен. Я исправил это, получив один кадр, используя yield return new WaitForEndOfFrame(); сразу после функции, которая заботится об уничтожении старых GameObjects перед попыткой доступа к новому GameObject.

...