记录一下Addressables-Sample项目中的脚本和学习的笔记,主要是熟悉API及其使用方式.方便日后工作查询.
项目地址:
github: Addressables-Sample
1.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讲解
- 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讲解
- 加载Sprite
sheetSubReference.LoadAssetAsync<Sprite>().Completed += Subassetdone;
- 加载SubSprite
sheetReference.LoadAssetAsync<IList<Sprite>>().Completed += AssetDone;
|