从下载的资产包实例化后,引用游戏对象的渲染器材料不起作用

时间:2019-10-08 11:42:50

标签: unity3d assetbundle

嗨!如果您想节省时间并且仍然有帮助,请阅读本节以及最后一节以了解我的问题(第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。父级只有一个子级包含Renderer组件 现在,最后,问题是我没有得到正确的材料参考,我得到了通过切换按钮设置的旧参考材料,简单地是这样:

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

6。 因此,总之,当我按下代表某些化身/衣服部分的“切换按钮”时,即使下载了资产捆绑包,它仍可以通过功能正确设置其父对象和材质(但我必须再次单击相同的切换键才能使其工作),但是在下载资源后立即在 OnDownloadAssetBundleCompleteHandler 中触发相同的功能时,它不起作用:S为什么?它与资产卸载速度有关吗?有任何解决此问题的提示吗?

在游戏视图中,其行为如下: enter image description here

1 个答案:

答案 0 :(得分:0)

我修复了它。由于您不能像@derHugo那样使用DestoyImmediate,因为它可能导致引用错误,甚至可能永久损坏资产,因此我必须在实例化Assetbundle中的新游戏对象之前使用Destroy(),但是Destroy()会在最后删除指定的对象尝试在刚删除同一个旧帧之前尝试在同一个帧上访问刚实例化的GameObject上的Renderer组件时使用。我修复了使用yield return new WaitForEndOfFrame();产生一帧的问题,该函数恰好在尝试访问新GameObject之前负责销毁旧GameObjects的函数之后。