运行模式和编辑模式是完全不同的,编辑模式下可以放很多很多资源,这些资源并不是全部打包到发布的游戏包中的。
打包时,Unity会自动过滤掉没有引用的资源,注意:Resources目录和StreamingAssets目录下的会都打包。
//--引用资源
只有被引用到的资源Unity才会打包,那么如何分辨资源是否被引用?
一张贴图被一个材质引用,这个材质被一个Cube引用,这个Cube被一个场景引用,这个场景被添加进了Scenes In Build中。
那么以上各个资源都会被打包进游戏包。
//--Resources
Resources文件夹是Unity中标志性的目录,这个目录下的资源无论引用与否,都会被强制打包在游戏包中。
Resources文件夹可以是顶层目录,也可以是某个文件夹的子目录,Unity会自动将它们合并在一起打包。
代码中动态读取这些资源并且加载它。
using UnityEngine;
public class MyResourcesLoadTest : MonoBehaviour
{
private void Start()
{
Texture texture = Resources.Load<Texture>("Textures/unity");
Debug.Log(texture.name);
}
}
注意:由于Resources目录下的资源都会被打包,所以尽可能不要把不需要运行时加载的资源,或者已经废弃掉的资源放进去,因为这样会增大包体。此外,Resources下的资源尽量不要直接引用在场景中,不然这个资源会被场景和Resources打成两份。
//--删除对象
运行时,需要使用GameObject.Destroy()和GameObject.DestroyImmediate()方法删除游戏对象。
其中GameObject.Destroy()会等一帧再彻底删除。因为有可能在这一帧的后面还有地方在操作这个对象,所以建议使用它来删除对象。
GameObject.DestroyImmediate()表示立即删除,如果这句代码后面有地方操作这个删除的对象,立刻就会报错。
using UnityEngine;
public class MyDestroyTest : MonoBehaviour
{
public GameObject go1;
public GameObject go2;
public GameObject go3;
private void Start()
{
GameObject.Destroy(go1);
//--延时一秒后删除
GameObject.Destroy(go2, 1.0f);
//--立即删除
GameObject.DestroyImmediate(go3);
}
}
//--删除资源
我们在场景中创建一个Cube,再创建一个材质,引用一张贴图。运行时,把Cube删除掉。
通过Profiler中依然可以看到这个贴图在内存中。
我们可以使用Resources.UnloadAsset()以及Resources.UnloadUnusedAssets()方法强制卸载资源。
资源卸载是异步操作,所以可以使用isDone来判断是否完成。
using UnityEngine;
public class MyDestroyTest : MonoBehaviour
{
public GameObject go1;
private AsyncOperation m_Operation;
private void Start()
{
GameObject.Destroy(go1);
m_Operation = Resources.UnloadUnusedAssets();
}
private void Update()
{
if (m_Operation != null)
{
if (m_Operation.isDone)
{
m_Operation = null;
Debug.Log("资源卸载完成!");
}
}
}
}
(如果有图集引用这个图的话,还是卸载不了。)
//--GC
在C#中,可能会有很多临时对象引用这个游戏资源,这很可能会导致Resources.UnloadUnusedAssets()无法释放掉。因此,在卸载无用资源前,需要保证C#完成垃圾收集工作,而且有时候进行一遍垃圾回收是没用的。最好调用两边GC()和Resources.UnloadUnusedAssets()。
using UnityEngine;
using UnityEngine.Events;
public class MyDestroyTest : MonoBehaviour
{
public GameObject go1;
private AsyncOperation m_Operation;
private void Start()
{
GameObject.Destroy(go1);
MyGC gc = GetComponent<MyGC>() ?? gameObject.AddComponent<MyGC>();
gc.UnloadUnusedAssets(delegate ()
{
gc.UnloadUnusedAssets(delegate ()
{
DestroyImmediate(gc);
Debug.Log("彻底卸载资源!");
});
});
}
public class MyGC : MonoBehaviour
{
public AsyncOperation m_Operation;
public UnityAction m_Callback;
public void UnloadUnusedAssets(UnityAction callback)
{
m_Callback = callback;
m_Operation = Resources.UnloadUnusedAssets();
System.GC.Collect();
}
private void Update()
{
if (m_Operation != null)
{
if (m_Operation.isDone)
{
m_Operation = null;
m_Callback();
//DestroyImmediate(this);
}
}
}
}
}