记录一下Addressables-Sample项目中的脚本和学习的笔记,主要是熟悉API及其使用方式.方便日后工作查询.

项目地址:

github: Addressables-Sample

Unity官方教程

Bilibili-Unity官方教程 Addressables【中文字幕】

Basic AssetReference

1.1 Scenes/BasicReference

实例化的AssetReference引用,并销毁

脚本 BasicReference.cs
using System.Collections;
using System.Collections.Generic;
using UnityEngine;
using UnityEngine.AddressableAssets;
using UnityEngine.ResourceManagement;

public class BasicReference : MonoBehaviour
{

	public AssetReference baseCube;

	public void SpawnThing()
	{
		baseCube.InstantiateAsync();
	}
}

脚本 SelfDestruct.cs
using UnityEngine;
using UnityEngine.AddressableAssets;

public class SelfDestruct : MonoBehaviour {

	public float lifetime = 2f;

	void Start()
	{
		Invoke("Release", lifetime);
	}

	void Release()
	{
        if (!Addressables.ReleaseInstance(gameObject))
            Destroy(gameObject);
	}
}

  • 创建的对象将被Addressables.ReleaseInstance销毁,即使它们不是以这种方式创建的。从版本0.8开始,这将抛出一个警告,但仍然会删除资源。在将来,我们的目的是使这种方法不破坏资产,或打印警告。相反,它将返回一个布尔值,以便您可以在需要时手动销毁。
API讲解

1.引用

public AssetReference baseCube;

AssetReference 是addressable asset的引用.AssetReference有一个Asset属性

public virtual Object Asset { get; }

Asset是加载的资产。此值仅在LoadAssetAsync返回的AsyncOperationHandle完成后设置。如果只调用instantialeasync,则不会设置它。如果调用release,它将被设置为null。

2.加载

baseCube.InstantiateAsync();是基本异步加载,会返回一个AsyncOperationHandle,里面包含了加载过程中的所有信息.

3.延时调用

Invoke是MonoBehaviour类中的方法。还有一个类似的InvokeRepeating方法.

CancelInvoke取消定时器.

4.销毁

void Release()
{
    if (!Addressables.ReleaseInstance(gameObject))
        Destroy(gameObject);
}

Addressables.ReleaseInstance(gameObject)的作用是释放并销毁通过Addressables.instantialeasync创建的对象。

1.2 Scenes/FilteredReferences

请注意,在这个实例中从不等待加载完成。我们只是在继续之前检查它们是否完成(如果资产存在)
。这通常不是最佳实践,但在某些场景中有一些好处。

脚本 FilteredReferences.cs

using System;
using System.Collections;
using System.Collections.Generic;
using UnityEngine;
using UnityEngine.AddressableAssets;
using Object = UnityEngine.Object;

public class FilteredReferences : MonoBehaviour
{
    [Serializable]
    public class AssetReferenceMaterial : AssetReferenceT<Material>
    {
        public AssetReferenceMaterial(string guid) : base(guid) { }
    }
    
    public AssetReferenceGameObject leftObject;
    public AssetReferenceGameObject rightObject;
    public AssetReferenceMaterial spawnMaterial;
    public AssetReferenceMaterial midMaterial;
    public AssetReferenceMaterial lateMaterial;

    public Vector3 leftPosition;
    public Vector3 rightPosition;

    MeshRenderer m_LeftMeshRender;
    MeshRenderer m_RightMeshRender;
    
    void Start()
    {
        leftObject.LoadAssetAsync();
        rightObject.LoadAssetAsync();
        spawnMaterial.LoadAssetAsync();
        midMaterial.LoadAssetAsync();
        lateMaterial.LoadAssetAsync();
    }

    int m_FrameCounter = 0;

   
    //Note that we never actually wait for the loads to complete.  We just check if they are done (if the asset exists)
    //before proceeding.  This is often not going to be the best practice, but has some benefits in certain scenarios.
    void FixedUpdate()
    {
        m_FrameCounter++;
        if (m_FrameCounter == 20)
        {
            if (leftObject.Asset != null)
            {
                var leftGo = Instantiate(leftObject.Asset, leftPosition, Quaternion.identity) as GameObject;
                m_LeftMeshRender = leftGo.GetComponent<MeshRenderer>();
            }

            if (rightObject.Asset != null)
            {
                var rightGo = Instantiate(rightObject.Asset, rightPosition, Quaternion.identity) as GameObject;
                m_RightMeshRender = rightGo.GetComponent<MeshRenderer>();
            }

            if (spawnMaterial.Asset != null && m_LeftMeshRender != null && m_RightMeshRender != null)
            {
                m_LeftMeshRender.material = spawnMaterial.Asset as Material;
                m_RightMeshRender.material = spawnMaterial.Asset as Material;
            }
    }

        if (m_FrameCounter == 40)
        {
            if (midMaterial.Asset != null && m_LeftMeshRender != null && m_RightMeshRender != null)
            {
                m_LeftMeshRender.material = midMaterial.Asset as Material;
                m_RightMeshRender.material = midMaterial.Asset as Material;
            }
        }

        if (m_FrameCounter == 60)
        {
            m_FrameCounter = 0;
            if (lateMaterial.Asset != null && m_LeftMeshRender != null && m_RightMeshRender != null)
            {
                m_LeftMeshRender.material = lateMaterial.Asset as Material;
                m_RightMeshRender.material = lateMaterial.Asset as Material;
            }
        }
    }

    void OnDisable()
    {
        //note that this may be dangerous, as we are releasing the asset without knowing if the instances still exist.
        // sometimes that's fine, sometimes not.
        
        leftObject.ReleaseAsset();
        rightObject.ReleaseAsset();
        spawnMaterial.ReleaseAsset();
        midMaterial.ReleaseAsset();
        lateMaterial.ReleaseAsset();
    }
}

  • 使用列表中引用的案例。
  • 关键功能:加载“AssetReference”后,它将保留一个名为“%.Asset”的成员。在本例中,您不希望使用complete回调来保存资产,因为加载可能与触发的顺序不完全相同。因此,引用与自己加载的资产保持一致是很有用的。
  • 这里,对象通过传统的GameObject.instantite实例化,不会增加Addressables ref计数。这些对象仍然调用Addressables来释放自己,但是由于它们不是通过Addressables实例化的,所以版本只会破坏对象,并且不会减少ref计数。
  • 这些AssetReference的管理器必须在“OnDestroy”中释放它们,否则ref计数将在场景关闭后继续存在。
API讲解

1.引用

public AssetReferenceGameObject leftObject;
public AssetReferenceMaterial rightObject;

AssetReferenceGameObject和AssetReferenceMaterial 是AssetReference泛型类型

public class AssetReferenceGameObject : AssetReferenceT<GameObject>, IKeyEvaluator

AssetReferenceGameObject继承至AssetReferenceT

2.加载

都是通过LoadAssetAsync();方法加载.在逻辑处理上,并不是等待资源加载完成才进行处理,而是在继续逻辑之前检查它们是否加载完成.

3.卸载

ReleaseAsset();

请注意,这可能很危险,因为我们在不知道实例是否仍然存在的情况下释放资产。

有时候可以,有时候不行。

1.3 Scenes/ListOfReferences

脚本 ListOfReferences.cs

using System.Collections;
using System.Collections.Generic;
using UnityEngine;
using UnityEngine.AddressableAssets;
using UnityEngine.ResourceManagement;
using UnityEngine.ResourceManagement.AsyncOperations;

public class ListOfReferences : MonoBehaviour {

	public List<AssetReference> shapes;

	bool m_IsReady = false;
	int m_ToLoadCount;

	int currentIndex = 0;
	// Use this for initialization
	void Start ()
	{
		m_ToLoadCount = shapes.Count;
		foreach (var shape in shapes)
		{
			shape.LoadAssetAsync<GameObject>().Completed += OnShapeLoaded;
		}
	}

	void OnShapeLoaded(AsyncOperationHandle<GameObject> obj)
	{
		m_ToLoadCount--;
		if (m_ToLoadCount <= 0)
			m_IsReady = true;
	}

	public void SpawnAThing()
	{
		if (m_IsReady && shapes[currentIndex].Asset != null)
		{
			for(int count = 0; count <= currentIndex; count++)
				GameObject.Instantiate(shapes[currentIndex].Asset);
			currentIndex++;
			if (currentIndex >= shapes.Count)
				currentIndex = 0;

		}
	}

	void OnDestroy()
	{
		foreach (var shape in shapes)
		{
			shape.ReleaseAsset();
		}
	}
}

使用的API与之前的相同,只是在加载的逻辑处理上不同.通过每个AssetReference加载的回调方法OnShapeLoaded()里处理m_ToLoadCount,以此判断全部的资源是否加载完毕.

API讲解
  1. Completed
shape.LoadAssetAsync<GameObject>().Completed += OnShapeLoaded;

LoadAssetAsync返回的是一个AsyncOperationHandle,Completed是AsyncOperationHandle里面加载完成后的回调.

1.4 Scenes/SubobjectReference

脚本 SubobjectReference.cs

using System;
using System.Collections.Generic;
#if UNITY_EDITOR
using UnityEditor.AddressableAssets.GUI;
#endif
using UnityEngine;
using UnityEngine.AddressableAssets;
using UnityEngine.ResourceManagement.AsyncOperations;
using UnityEngine.UI;

public class SubobjectReference : MonoBehaviour
{
    public AssetReference sheetReference;
    public AssetReference sheetSubReference;
    public List<SpriteRenderer> spritesToChange;

    public Button loadMainButton;
    public Button loadSubButton;

    public void LoadMainAsset()
    {
        loadMainButton.interactable = false;
        sheetReference.LoadAssetAsync<IList<Sprite>>().Completed += AssetDone;
    }

    public void LoadSubAsset()
    {
        loadSubButton.interactable = false;
        sheetSubReference.LoadAssetAsync<Sprite>().Completed += Subassetdone;
    }
    
    void AssetDone(AsyncOperationHandle<IList<Sprite>> op)
    {
        if (op.Result == null)
        {
            Debug.LogError("no sheets here.");
            return;
        }

        spritesToChange[0].sprite = op.Result[1];
        
        loadMainButton.interactable = false;
    }

     void Subassetdone(AsyncOperationHandle<Sprite> op)
    {
        if (op.Result == null)
        {
            Debug.LogError("no sprite in sheet here.");
            return;
        }

        spritesToChange[1].sprite = op.Result;
        
        loadSubButton.interactable = false;
    }

    void Start()
    {
        Addressables.InitializeAsync();
    }

}

  • 这个案例主要是Sprite,和SubSprite的加载
  • “AssetReference”包含一个主资源(“editorAsset”)和一个可选的子对象。某些引用类型(例如,对精灵图纸和精灵地图集的引用)可以使用子对象。如果引用使用子对象,那么它将在编辑模式期间加载主资源,并在运行时期间加载子对象。
  • 此场景显示从精灵工作表(主资源)加载精灵,并在运行时将精灵作为子对象加载。
API讲解
  1. 加载Sprite
 sheetSubReference.LoadAssetAsync<Sprite>().Completed += Subassetdone;
  1. 加载SubSprite
 sheetReference.LoadAssetAsync<IList<Sprite>>().Completed += AssetDone;
Logo

瓜分20万奖金 获得内推名额 丰厚实物奖励 易参与易上手

更多推荐