从asssetBundle加载的Prefab可以传递给Vuforia AnchorBehavior声明吗 [英] Can a Prefab loaded from asssetBundle be passed to Vuforia AnchorBehavior declaration

查看:33
本文介绍了从asssetBundle加载的Prefab可以传递给Vuforia AnchorBehavior声明吗的处理方法,对大家解决问题具有一定的参考价值,需要的朋友们下面随着小编来一起学习吧!

问题描述

目标是一个两步过程,其中从 AssetBundle 加载 Vuforia GroundPlane 对象的 Prefab,并传递给 AnchorBehavior 变量声明以放置游戏对象.

如果作为 Unity C# 的新手,我没有像我希望的那样准确,我深表歉意

尝试了各种方法将加载的 Prefab 等同于 AnchorBehavior.但是因为这是两种类型的对象,所以会出现错误,表明它们不能隐式相等

声明如下:

public PlaneFinderBehaviour plane;public ContentPositioningBehaviour planeFinder;公共锚行为模型;公共字符串 nameOfAssetBundle;公共字符串 nameOfObjectToLoad;

想法是传递代表预制件的nameOfObjectToLoad"并将其传递给AnchorBehavior"值,然后当脚本附加到按钮时可以使用以下方法onClick".

public void create(){planeFinder.AnchorStage = model.GetComponent();}

期望预制件将传递给 AnchorBehavior 并实例化预制件onClick"

这是提取这些片段的完整脚本.

使用 System.Collections;使用 System.Collections.Generic;使用 UnityEngine;使用 Vuforia;公共类 anchorManagerBundles : MonoBehaviour{公共 PlaneFinder 行为平面;public ContentPositioningBehaviour planeFinder;公共锚行为模型;公共字符串 nameOfAssetBundle;公共字符串 nameOfObjectToLoad;无效开始(){StartCoroutine(LoadAsset(nameOfAssetBundle, nameOfObjectToLoad));}IEnumerator LoadAsset(string assetBundleName, string objectNameToLoad){string filePath = System.IO.Path.Combine(Application.streamingAssetsPath, "AssetBundles");filePath = System.IO.Path.Combine(filePath, assetBundleName);//加载nameOfAssetBundle" AssetBundlevar assetBundleCreateRequest = AssetBundle.LoadFromFileAsync(filePath);收益率返回 assetBundleCreateRequest;AssetBundle assetBundle = assetBundleCreateRequest.assetBundle;//加载nameOfOjectToLoad"资源(使用Texture2D,因为它是一个纹理.如果是预制,则使用GameObject)AssetBundleRequest asset = assetBundle.LoadAssetAsync(objectNameToLoad);收益回报资产;//检索对象(使用Texture2D,因为它是一个Texture.如果是prefab,则使用GameObject)GameObject loadedAsset = asset.asset as GameObject;//对加载的loadedAsset对象做一些事情(例如加载到RawImage)//模型=loadedAsset;}公共无效创建(){planeFinder.AnchorStage = model.GetComponent();}}

进一步的研究揭示了我的新手技能.模型=loadedAsset;"的最终意图是我试图直接从一种数据类型转换为另一种数据类型,这是无法明确完成的.但到目前为止,我的研究还没有找到从 AssetBundle 中取出加载的 Prefab 并将其提供给 AnchorBehaviour 变量的方法.

如果有人对数据类型之间的这种转换方法有任何经验,非常感谢您的指导.

更新通过正确地转换声明,消除了转换错误.

model = (asset.asset as AnchorBehaviour);

但现在我有一个 NullReference 错误,表明我未能正确声明该值,在这一行

<代码> {planeFinder.AnchorStage = model.GetComponent();}

这现在是我的新困境,因为我不确定我在哪里未能正确声明变量.

更新当 AnchorBehaviour 变量设置为私有时,此错误得到解决.因此,现在脚本可以编译,但无法产生预期的结果.这可能表明需要更改加载 AssetBundle 组件的方式,如 IEnumerator 部分所述.Unity 控制台打印出以下日志注释

没有内容可放置在锚点处.将Anchor Stage"字段设置为您要放置的内容.UnityEngine.Debug:LogError(Object)

在所有建议之后,这是迄今为止的脚本,不幸的是它没有放置来自 AssetBundle 的内容.我可以看到更多关于我的研究和测试.

使用 System.Collections;使用 System.Collections.Generic;使用 UnityEngine;使用 Vuforia;公共类 anchorManagerBundles : MonoBehaviour{公共 PlaneFinder 行为平面;public ContentPositioningBehaviour planeFinder;私有 AnchorBehaviour 模型;公共字符串 nameOfAssetBundle;公共字符串 nameOfObjectToLoad;私有静态布尔值已经加载;私有静态 AssetBundle assetBundle;无效开始(){//只加载一次包if (!alreadyLoading){//设置标志以确保永远不会再这样做已经加载 = 真;StartCoroutine(LoadAsset(nameOfAssetBundle, nameOfObjectToLoad));}别的{LoadObjectFromBundle(nameOfObjectToLoad);}}私有 IEnumerator LoadAsset(string assetBundleName, string objectNameToLoad){string filePath = System.IO.Path.Combine(Application.streamingAssetsPath, "AssetBundles");filePath = System.IO.Path.Combine(filePath, assetBundleName);if (assetBundle == null){var assetBundleCreateRequest = AssetBundle.LoadFromFileAsync(filePath);收益率返回 assetBundleCreateRequest;assetBundle = assetBundleCreateRequest.assetBundle;}私有 IEnumerator LoadObjectFromBundle(string objectNameToLoad){AssetBundleRequest assetRequest = assetBundle.LoadAssetAsync(objectNameToLoad);收益回报资产请求;GameObject loadedAsset = (GameObject)assetRequest.asset;模型 = loadedAsset.GetComponent();}公共无效创建(){planeFinder.AnchorStage = 模型;}}

为资产添加 if 语句后,编译正常,我继续收到控制台警报,提示模型"(AnchorBehavior/Anchor Stage)字段需要有一个值.因此,似乎脚本没有传递在nameOfObjectToLoad"字段中声明的 AssetBundle 对象,或者传递的内容不匹配.因此,出于同样的解释,我暂时公开了模型"字段并手动填充了该字段.您将看到它将 Prefab 标识为AnchorBehavior"对象.编辑器中的按钮值 - 预期结果

这是尝试放置对象时编辑器控制台中的完整错误.

没有内容可放置在锚点处.将Anchor Stage"字段设置为您要放置的内容.UnityEngine.Debug:LogError(Object)Vuforia.ContentPositioningBehaviour:CreateAnchorAndPlaceContent(Func`2, Vector3, Quaternion)Vuforia.ContentPositioningBehaviour:PositionContentAtPlaneAnchor(HitTestResult)UnityEngine.Events.UnityEvent`1:Invoke(HitTestResult)Vuforia.PlaneFinderBehaviour:PerformHitTest(Vector2)UnityEngine.Events.UnityEvent`1:Invoke(Vector2)Vuforia.AnchorInputListenerBehaviour:Update()

为了进一步调试问题,我修改了以下部分.

 if (assetBundle == null){Debug.Log("加载assetBundle失败!!");产量中断;}

目的是尝试确定 AssetBundle 是否确实正在加载.这非常有用,但它产生了一个非常奇怪的结果,我会征求建议.

此脚本附加到一系列按钮上,以便在单击按钮时,使用 create() 函数根据变量实例化 Prefab.

这些按钮分组在 3 个不同的 UI 面板上.用户单击选定的面板按钮以显示所需的按钮面板.

很奇怪的是,当用户点击面板选择按钮时,编辑器日志中出现了如下错误.这是在点击带有附加脚本的实际按钮之前.

点击面板按钮

无法加载assetBundle!!UnityEngine.Debug:Log(Object)<LoadAsset>d__8:MoveNext()(在 Assets/Scripts/anchorManagerBundles.cs:38)UnityEngine.MonoBehaviour:StartCoroutine(IEnumerator)anchorManagerBundles:Start()(在 Assets/Scripts/anchorManagerBundles.cs:23)

点击按钮(脚本附加按钮)

没有内容可放置在锚点处.将Anchor Stage"字段设置为您要放置的内容.UnityEngine.Debug:LogError(Object)Vuforia.ContentPositioningBehaviour:CreateAnchorAndPlaceContent(Func`2, Vector3, Quaternion)Vuforia.ContentPositioningBehaviour:PositionContentAtPlaneAnchor(HitTestResult)UnityEngine.Events.UnityEvent`1:Invoke(HitTestResult)Vuforia.PlaneFinderBehaviour:PerformHitTest(Vector2)UnityEngine.Events.UnityEvent`1:Invoke(Vector2)Vuforia.AnchorInputListenerBehaviour:Update()

我不明白为什么在单击没有附加脚本的面板按钮时调用脚本.

对于这个令人费解的问题,非常感谢任何建议.

解决方案

Checkout AssetBundle.LoadAssetAsync

<块引用>

在 5.0 版之前,用户可以使用 LoadAsync 直接获取单个组件.这不再受支持.相反,请先使用 LoadAssetAsync 加载游戏对象,然后在对象上查找组件.

<小时>

您不能简单地将检索到的 GameObject 引用类型转换为 AnchorBehaviour 引用.相反,您必须使用 GetComponent.><小时>

所以你应该做的是

AssetBundleRequest assetRequest = assetBundle.LoadAssetAsync(objectNameToLoad);收益回报资产请求;GameObject loadedAsset = (GameObject)assetRequest.asset;//因为模型已经是 AnchorBehaviour 类型//你应该在这里做 GetComponent模型=loadedAsset.GetComponent();

既然您已经有了 AnchorBehaviour 类型的引用,第二个 GetComponent 调用将是多余的,因为它返回相同的引用.所以现在只用

public void create(){planeFinder.AnchorStage = 模型;}

<小时>

如果你有这个脚本的多个实例,像这样只加载一次 assetBundle 可能是有意义的

private static bool alreadyLoading;私有静态 AssetBundle assetBundle;无效开始(){//只加载一次包如果(!已经加载){//设置标志以确保永远不会再这样做已经加载 = 真;StartCoroutine(LoadAsset(nameOfAssetBundle, nameOfObjectToLoad));}别的{LoadObjectFromBundle(nameOfOjectToLoad);}}私有 IEnumerator LoadAsset(string assetBundleName, string objectNameToLoad){string filePath = System.IO.Path.Combine(Application.streamingAssetsPath, "AssetBundles");filePath = System.IO.Path.Combine(filePath, assetBundleName);var assetBundleCreateRequest = AssetBundle.LoadFromFileAsync(filePath);收益率返回 assetBundleCreateRequest;assetBundle = assetBundleCreateRequest.assetBundle;LoadObjectFromBundle(objectNameToLoad);}私有 IEnumerator LoadObjectFromBundle(string objectNameToLoad){AssetBundleRequest assetRequest = assetBundle.LoadAssetAsync(objectNameToLoad);收益回报资产请求;GameObject loadedAsset = (GameObject)assetRequest.asset;模型=loadedAsset.GetComponent();}

The goal is a two step process in which a Prefab of a Vuforia GroundPlane object is loaded from an AssetBundle, and passed to the AnchorBehavior variable declaration in order to place the gameObject.

And my apologies if as a newcomer to Unity C# i am not as accurate as i would like

Tried various approaches to equate the loaded Prefab to the AnchorBehavior. But because these are two types of objects, errors occur indicating these can't be implicitly equal

The declarations are the following:

public PlaneFinderBehaviour plane;
public ContentPositioningBehaviour planeFinder;
public AnchorBehaviour model;
public string nameOfAssetBundle;
public string nameOfObjectToLoad;

Idea was to pass the "nameOfObjectToLoad" representing the Prefab and pass it to the "AnchorBehavior" value, then the following method could be used "onClick", when the script is attached to a button.

public void create()
{
    planeFinder.AnchorStage = model.GetComponent<AnchorBehaviour>();
}

The expectation was that the Prefab would be passed to the AnchorBehavior and instantiate the Prefab "onClick"

Here is the full script from which these snippets were extracted.

using System.Collections;
using System.Collections.Generic;
using UnityEngine;
using Vuforia;

public class anchorManagerBundles : MonoBehaviour
{
    public PlaneFinderBehaviour plane;
    public ContentPositioningBehaviour planeFinder;
    public AnchorBehaviour model;
    public string nameOfAssetBundle;
    public string nameOfObjectToLoad;

    void Start()
    {
        StartCoroutine(LoadAsset(nameOfAssetBundle, nameOfObjectToLoad));
    } 

    IEnumerator LoadAsset(string assetBundleName, string objectNameToLoad)
    {
        string filePath = System.IO.Path.Combine(Application.streamingAssetsPath, "AssetBundles");
        filePath = System.IO.Path.Combine(filePath, assetBundleName);

        //Load "nameOfAssetBundle" AssetBundle
        var assetBundleCreateRequest = AssetBundle.LoadFromFileAsync(filePath);
        yield return assetBundleCreateRequest;

        AssetBundle assetBundle = assetBundleCreateRequest.assetBundle;

        //Load the "nameOfOjectToLoad" Asset (Use Texture2D since it's a Texture. Use GameObject if prefab)
        AssetBundleRequest asset = assetBundle.LoadAssetAsync<GameObject>(objectNameToLoad);
        yield return asset;

        //Retrieve the object (Use Texture2D since it's a Texture. Use GameObject if prefab)
        GameObject loadedAsset = asset.asset as GameObject;

        //Do something with the loaded loadedAsset  object (Load to RawImage for example) 
        //model = loadedAsset;
    }
    public void create()
    {
        planeFinder.AnchorStage = model.GetComponent<AnchorBehaviour>();
    }

}

Further research exposes my novice skills. The final intent, of "model = loadedAsset;" is that i am attempting to directly convert from one data type to another, which can't be done explicitly. But thus far, my research has not found a means to take the loaded Prefab from the AssetBundle and feed it to the AnchorBehaviour variable.

If anyone has any experience with approaches to this kind of conversion between data types, your guidance is very much appreciated.

UPDATE By casting the declaration correctly, the conversion error was eliminated.

model = (asset.asset as AnchorBehaviour);

but now i have a the NullReference error, indicating that i have failed to declare the value correctly, in this line

    {
        planeFinder.AnchorStage = model.GetComponent<AnchorBehaviour>();
    }

And this now is my new dilemma, as i am not sure where i have failed to declare the variable correctly.

UPDATE This error is resolved when the AnchorBehaviour variable is set as private. So, now the script compiles, but fails to produce the intended results. This likely points to a need to change how to load the AssetBundle component as described in the IEnumerator section. The Unity Console prints out the following logging comment

There is no content to place at the anchor. Set the "Anchor Stage" field to the content you wish to place.
UnityEngine.Debug:LogError(Object)

After all the advice, here is the script to-date, which unfortunately does not place the content from the AssetBundle. More research and testing on my part i can see.

using System.Collections;
using System.Collections.Generic;
using UnityEngine;
using Vuforia;

public class anchorManagerBundles : MonoBehaviour
{
    public PlaneFinderBehaviour plane;
    public ContentPositioningBehaviour planeFinder;
    private AnchorBehaviour model;
    public string nameOfAssetBundle;
    public string nameOfObjectToLoad;
    private static bool alreadyLoading;
    private static AssetBundle assetBundle;

    void Start()
    {
        // only load the bundle once
        if (!alreadyLoading)
        {
            // set the flag to make sure this is never done again
            alreadyLoading = true;
            StartCoroutine(LoadAsset(nameOfAssetBundle, nameOfObjectToLoad));
        }
        else
        {
            LoadObjectFromBundle(nameOfObjectToLoad);
        }
    }

    private IEnumerator LoadAsset(string assetBundleName, string objectNameToLoad)
    {
        string filePath = System.IO.Path.Combine(Application.streamingAssetsPath, "AssetBundles");
        filePath = System.IO.Path.Combine(filePath, assetBundleName);

        if (assetBundle == null) 
        { 
            var assetBundleCreateRequest = AssetBundle.LoadFromFileAsync(filePath); 
            yield return assetBundleCreateRequest; assetBundle = assetBundleCreateRequest.assetBundle; 
        }

    private IEnumerator LoadObjectFromBundle(string objectNameToLoad)
    {
        AssetBundleRequest assetRequest = assetBundle.LoadAssetAsync<GameObject>(objectNameToLoad);
        yield return assetRequest;

        GameObject loadedAsset = (GameObject)assetRequest.asset;

        model = loadedAsset.GetComponent<AnchorBehaviour>();
    }

    public void create()
    {
        planeFinder.AnchorStage = model;
    }
}

After adding the if statement for the asset, which compiles fine, i continue to have the console alert that the "model" (AnchorBehavior/Anchor Stage) field needs to have a value. So it seems that what the script is either not passing the AssetBundle Object declared in the "nameOfObjectToLoad" field, or what is passing is not matching. So for the same of explanation, i temporarily made the "model" field public and manually populated the field. You will see it identifies the Prefab as being a "AnchorBehavior" object. Button Values in Editor - Desired Outcome

Here is the full error in the Editor Console when attempting to place the object.

There is no content to place at the anchor. Set the "Anchor Stage" field to the content you wish to place.
UnityEngine.Debug:LogError(Object)
Vuforia.ContentPositioningBehaviour:CreateAnchorAndPlaceContent(Func`2, Vector3, Quaternion)
Vuforia.ContentPositioningBehaviour:PositionContentAtPlaneAnchor(HitTestResult)
UnityEngine.Events.UnityEvent`1:Invoke(HitTestResult)
Vuforia.PlaneFinderBehaviour:PerformHitTest(Vector2)
UnityEngine.Events.UnityEvent`1:Invoke(Vector2)
Vuforia.AnchorInputListenerBehaviour:Update()

In an effort to further debug the issue, i ammended the following section to this.

        if (assetBundle == null)
        {
            Debug.Log("Failed to Load assetBundle!!");
            yield break;
        }

The intent was to an attempt to identify if the AssetBundle was in fact being loaded. This was very useful, but it produced a very odd result for which i would solicit advise.

This script is attached to a series of buttons so that when the button is clicked, the create() function is used to instantiate the Prefab based on the variables.

These buttons are grouped on 3 different UI panels. The user clicks on the selected Panel button to expose the desire button panel.

What is very strange is that when the user clicks on the Panel Selection Button, the following errors are placed in the Editor Log. This is before the actual button which has the attached script has been clicked.

On Panel Button Click

Failed to Load assetBundle!!
UnityEngine.Debug:Log(Object)
<LoadAsset>d__8:MoveNext() (at Assets/Scripts/anchorManagerBundles.cs:38)
UnityEngine.MonoBehaviour:StartCoroutine(IEnumerator)
anchorManagerBundles:Start() (at Assets/Scripts/anchorManagerBundles.cs:23)

On Button Click (script attached button)

There is no content to place at the anchor. Set the "Anchor Stage" field to the content you wish to place.
UnityEngine.Debug:LogError(Object)
Vuforia.ContentPositioningBehaviour:CreateAnchorAndPlaceContent(Func`2, Vector3, Quaternion)
Vuforia.ContentPositioningBehaviour:PositionContentAtPlaneAnchor(HitTestResult)
UnityEngine.Events.UnityEvent`1:Invoke(HitTestResult)
Vuforia.PlaneFinderBehaviour:PerformHitTest(Vector2)
UnityEngine.Events.UnityEvent`1:Invoke(Vector2)
Vuforia.AnchorInputListenerBehaviour:Update()

I do not understand why the script is being called upon click of Panel Button, which does not have the script attached.

Any advise is most appreciated on this puzzling issue.

解决方案

Checkout AssetBundle.LoadAssetAsync

Prior to version 5.0, users could fetch individual components directly using LoadAsync. This is not supported anymore. Instead, please use LoadAssetAsync to load the game object first and then look up the component on the object.


You can't simply typecast the retrieved GameObject reference to a AnchorBehaviour reference. Instead you have to use GetComponent.


So what you should do is

AssetBundleRequest assetRequest = assetBundle.LoadAssetAsync<GameObject>(objectNameToLoad);
yield return assetRequest;

GameObject loadedAsset = (GameObject)assetRequest.asset;

// since model is already of type AnchorBehaviour
// you should do the GetComponent already here
model = loadedAsset.GetComponent<AnchorBehavior>();

Now that you already have a reference of type AnchorBehaviour the second GetComponent call would be redundant since it returns the same reference. So now only use

public void create()
{
    planeFinder.AnchorStage = model;
}


In case you have multiple instances of this script it might make sense to load the assetBundle only once like

private static bool alreadyLoading;
private static AssetBundle assetBundle;

void Start()
{
    // only load the bundle once
    if(!alreadyLoading) 
    {
        // set the flag to make sure this is never done again
        alreadyLoading = true;
        StartCoroutine(LoadAsset(nameOfAssetBundle, nameOfObjectToLoad));
    }
    else
    {
        LoadObjectFromBundle(nameOfOjectToLoad);
    }
} 

private IEnumerator LoadAsset(string assetBundleName, string objectNameToLoad)
{
    string filePath = System.IO.Path.Combine(Application.streamingAssetsPath, "AssetBundles");
    filePath = System.IO.Path.Combine(filePath, assetBundleName);

    var assetBundleCreateRequest = AssetBundle.LoadFromFileAsync(filePath);
    yield return assetBundleCreateRequest;

    assetBundle = assetBundleCreateRequest.assetBundle;

    LoadObjectFromBundle(objectNameToLoad);
}

private IEnumerator LoadObjectFromBundle(string objectNameToLoad)
{
    AssetBundleRequest assetRequest = assetBundle.LoadAssetAsync<GameObject>(objectNameToLoad);
    yield return assetRequest;

    GameObject loadedAsset = (GameObject)assetRequest.asset;

    model = loadedAsset.GetComponent<AnchorBehavior>();
}

这篇关于从asssetBundle加载的Prefab可以传递给Vuforia AnchorBehavior声明吗的文章就介绍到这了,希望我们推荐的答案对大家有所帮助,也希望大家多多支持IT屋!

查看全文
登录 关闭
扫码关注1秒登录
发送“验证码”获取 | 15天全站免登陆