
public class GetMousePos : MonoBehaviour
{
public Canvas canvas;//画布
private RectTransform rectTransform;//坐标
void Start()
{
canvas = GameObjectFind("Canvas")GetComponent<Canvas>();
rectTransform = canvastransform as RectTransform; //也可以写成thisGetComponent<RectTransform>(),但是不建议;
}
void Update()
{
if (InputGetMouseButtonDown(0))
{
Vector2 pos;
if (RectTransformUtilityScreenPointToLocalPointInRectangle(rectTransform, InputmousePosition, canvasworldCamera, out pos))
{
rectTransformanchoredPosition = pos;
DebugLog(pos);
}
}
}
}
新建场景,在场景中拖一个画布(Canvas),然后随便找个地方挂上这个脚本就好了。
1
RectTransformUtility:矩阵变换工具
RectTransformUtilityScreenPointToLocalPointInRectangle 从屏幕点到矩形内的本地点
Parameters 参数
rect The RectTransform to find a point inside
cam The camera associated with the screen space position
screenPoint Screen space position
localPoint Point in local space of the rect transform
Returns
bool Returns true if the plane of the RectTransform is hit, regardless of whether the point is inside the rectangle
Description 描述
Transform a screen space point to a position in the local space of a RectTransform that is on the plane of its rectangle
屏幕空间点转换为矩形变换内部的本地位置,该点在它的矩形平面上。
The cam parameter should be the camera associated with the screen point For a RectTransform in a Canvas set to Screen Space - Overlay mode, the cam parameter should be null
该cam 参数应该是该相机关联的屏幕点。对于在画布上的矩形变换设置该屏幕空间为-Overlay模式,cam 参数应该为空。
When ScreenPointToLocalPointInRectangle is used from within an event handler that provides a PointerEventData object, the correct camera can be obtained by using PointerEventDataenterEventData (for hover functionality) or PointerEventDatapressEventCamera (for click functionality) This will automatically use the correct camera (or null) for the given event
当ScreenPointToLocalPointInRectangle从事件处理器内部提供一个PointerEventData对象被使用时,相机可以通过使用PointerEventDataenterEventData(为悬停功能)或者 PointerEventDatapressEventCamera(为单击功能)被获取。该函数将会自动对指定事件使用正确的相机(或者空)。
RectTransform矩形变换
RectTransformanchoredPosition 锚点位置
The position of the pivot of this RectTransform relative to the anchor reference point
该矩形变换相对于锚点参考点的中心点位置。
The anchor reference point is where the anchors are If the anchors are not together, the four anchor positions are interpolated according to the pivot placement
锚点参考点是锚点的位置。如果锚点不在一起,四个锚点的位置是根据布置的中心点的位置插值替换的。
七种坐标系统详解与互相转换的方法模型坐标和观察坐标
9月24日//先将坐标从模型空间转为世界空间 float3 worldPos = UnityObjectToWorldDir(vvertex); //物



>
在 Unity 中目前我发现了获取依赖关系的两个 API 接口,分别是:
EditorUtilityCollectDependencies
AssetDatabaseGetDependencies
其中 AssetDatabaseGetDependencies 获取到的结果就是上面演示的那样,是大粒度的依赖关系。而 EditorUtilityCollectDependencies 获取到的是小粒度的依赖关系,所依赖的组件和 Shader 等都会列出来,非常的仔细。
C#
#if UNITY_EDITOR
using UnityEngine;
using SystemCollections;
using UnityEditor;
namespace PTFind
{
[ExecuteInEditMode]
public static class Find
{
[MenuItem("Find/What objects in scene use this", false, 20)]
public static void SelectSceneUsesOfAsset()
{
Object selectedObject = SelectionactiveObject;
if (selectedObject == null)
{
return;
}
Object[] roots = new Object[]{ selectedObject };
var objs = EditorUtilityCollectDependencies(roots);
string path = AssetDatabaseGetAssetPath(selectedObject);
var objs2 = AssetDatabaseGetDependencies(path);
foreach (var obj in objs)
{
DebugLog(objGetType()Name);
}
}
}
}
#endif
#if UNITY_EDITOR
using UnityEngine;
using SystemCollections;
using UnityEditor;
namespace PTFind
{
[ExecuteInEditMode]
public static class Find
{
[MenuItem("Find/What objects in scene use this", false, 20)]
public static void SelectSceneUsesOfAsset()
{
Object selectedObject = SelectionactiveObject;
if (selectedObject == null)
{
return;
}
Object[] roots = new Object[]{ selectedObject };
var objs = EditorUtilityCollectDependencies(roots);
string path = AssetDatabaseGetAssetPath(selectedObject);
var objs2 = AssetDatabaseGetDependencies(path);
foreach (var objin objs)
{
DebugLog(objGetType()Name);
}
}
}
}
#endif
不得不说,Unity Editor 提供的默认的依赖查找的功能好弱,包括反向依赖关系,引用关系丢失等功能。或许我们可以利用这些接口自己做一个好用点的依赖关系查找插件。
这是涵盖Assets,Resources和资源管理的一列文章中的第二篇。
这篇文章涵盖了Unity序列化系统的内部原理和Unity是如何在不同的Objects间保持健壮的引用的,包括Unity编辑器与运行时。也讨论了Objects和Assets在技术上的区别。这里涉及的主题对理解如何高效地加载和卸载Unity资源起到很重要的作用。合适的资源管理的关键是hi保持短的加载时间和较低的内存使用。
为了明白Unity是如何合理地管理数据的,了解Unity是如何标识和序列化数据是很重要的。第一个关键点就是区分Assets和UnityEngineObjects。
Asset就是硬盘的上的一个文件,存储在Unity工程的Assets文件夹。Textures,3d模型或音频都是常见的Assets类型。一些Assets包含了Unity的内部数据类型,如材质,而另一些Assets需要处理成Unity内部数据类型,如FBX文件。
UnityEngineObject或具有大写'O'的对象,是描述特定资源实例的一组集合。可以是Unity使用的任何资源类型,比如mesh,sprite,AudioClip或AnimationClip。所有这些Objects都是继承自 UnityEngineObject 。
虽然大多数类型都是内置的,但有两种特殊类型:
Assets和Objects是一对多的关系,也就是说任何给定的Asset文件包含一到多个的Objects。
所有的nityEngineObjects可以引用其他UnityEngineObjects。这些Objects可能是在同一个Asset文件,也可能从其他Asset文件引入。比如一个材质通常引用一个或多个Texture Objects。这些Texture Objects通常从一个或多个texture Asset文件引入(比如Pngs,Jpgs)。
当序列化的时候,这些引用由两个独立的数据组成:File GUID和Local ID。File GUID标识目标Asset文件保存在哪里。局部唯一的Local ID标识Asset文件内的每个Object,因为Asset可能包含多个Objects。
File GUID保存在meta文件。这些meta文件是在Unity引入Asset的时候生成的,并且存储在和Asset同一个目录下。
以上的标识码和引用关系可以通过文本编辑查看:创建一个新的UnityObject,修改Editor Setting暴露显示Mate文件,序列化Assets为text。创建一个material,然后导入texture到工程。把这个material指认给一个场景中的cube并保存。
使用文本编辑器打开跟上满material关联的meta文件,靠近顶部会出现标记为"guid"的信息。这一行定义了material Asset's文件的GUID。而查找Local ID需要使用文本编辑器打开material文件。material Object's 的定义是这样的:
在上面的例子中,&之后的数据就是material的Local ID。如果这个material Object在Asset中GUID标识为"abcdefg",可以将material 对象唯一地标识为文件GUID "abcdefg"的组合,Local ID为"2100000"。
为什么需要Unity的File GUID和Local ID 回答的坚定的,因为它提供了一个灵活的、不依赖平台的工作流。
文件GUID为文件特定路径提供了抽象描述。只要一个特定的文件GUID与特定的文件关联起来,那么文件在磁盘的路径变得无关紧要了。文件可以自由移动,而不需要更新所有引用这个文件的Objects。
任何一个Asset可能包含(或通过import产生)多个UnityEngineObject 资源,这个时候需要Local ID明确的区分不同的Object。
如果一个File GUID关联的Asset文件丢失了,对该Asset的所有对象的引用也会丢失。所以meta文件必须要保存在跟它关联的同名文件目录下,这很重要。注:Unity会重新生成删除的或丢失的meta文件。
Unity Editor有Paths到GUIDs的映射表。无论Asset加载还是引入,都会记录在映射表。映射表由Asset指定路径链接到Asset File GUID。如果Unity Editor打开的状态下,meta文件丢失,并且Asset路径没有变化,Editor能够确保Asset保留相同的File GUID。
如果Unity Editor在关闭状态下丢失了meta文件,或者Asset路径变化了但meta没有跟着移动,那么所有引用该Asset的Objects都会被破坏。
在11内部Assets和Objects章节说过,非Unity原生Asset类型必须导入到Unity。这是通过asset导入器来完成的。虽然这些导入器通常自动调用,但它们也可以通过 AssetImport API暴露接口。比如, TextureImporter API在导入单个texture Assets(如PNG文件)提供了访问设置的接口。
导入的结果就是引入一个或多个UnityEngineObjects。这些Objects在Unity Editor是可见的,以父Asset下有多个子Asset形式显示,比如多个sprites嵌套在一个texture Asset,会当成sprite图集导入。其中这些每个Object共享一个File GUID,因为他们的源数据保存在相同的Asset文件。它们将通过导入的texture Asset内部的Local ID进行区分。
导入进程会将源Asset转化为适合所选择目标平台的Asset。导入进程可能包含了一些重要的 *** 作,比如texture压缩。因为导入进程通常是一个耗时的进程,被导入的Asset缓存到Library文件夹,避免下次启动Editor又重新导入Assets。
切确的说,导入后的内容存储在以对应Asset的File GUID前两位数字命名的文件夹中。这个文件夹存储在Library/metadata/文件夹中。Asset中单个的Objects被序列化到一个名字与Asset的File GUID相同的二进制文件中。
导入进程对所有的Assets有效,不仅仅对非原生Assets。原生assets不需要漫长的转换过程或重新序列化。
File GUIDs和Local IDs都是健壮性比较好的,但GUID比较慢,运行时需要消耗更多性能。Unity内部维护一个缓存,它将File GUIDs和Local IDs转化成简单的,唯一的整数。当新的Objects在缓存注册的时候,会被分配一个简单的,单调递增的整数,这就叫Instance ID。
缓存维护了给定的Instance ID,File GUID和定义Object源数据位置的Local ID与 Object在内存中的instance(如果有的话)之间的映射。解析Instance ID可以快速返回Instance ID代表的加载Object。如果目标Object还没有加载,File GUID和Local ID可以解析到Object源数据,可以让Unity及时加载出Object。
项目启动的时候,Instance ID缓存初始化所有的Objects(如场景中的引用),只要这些Objects在Resources文件夹。另外,当新的assets在运行时导入进来或从AssetBundle加载Objects时,Instance ID会加进缓存中。当提供访问指定File GUID和Local ID的AssetBundle卸载(uploaded)时,Instance ID才会从缓存中移除。发生这种情况的时候,Instance ID,File GUID,Local ID之间的映射会被删除(节约内存)。如果这个AssetBundle重新加载了,会从这个重新加载的AssetBundle为加载出来的每个Object创建一个新的Instance ID。
深度讨论AssetBundles卸载的含义,这看 Managing Loaded Assets 章节和 AssetBundle Usage Patterns 文章。
在一些平台上,一些事件可以强制让Objects强制从内存中移除。比如,当IOS app暂停的时候,图形Assets会从图形内存中卸载。如果这些Objects是从AssetBundle加载出来的就会被卸载掉,并且Unity不能够重新加载这些源数据。任何现存的引用这些Objects的对象视为无效。前面的这种情况,场景中可能出现不可见的meshes或紫红色的。
实践Tips:运行时,上述控制流并非字面上那么精确。当运行时,有大量大量加载 *** 作的时候,File GUIDs和Local IDs表现没有那么好。当创建一个Unity项目的时候,File GUIDs和Local IDs切确地映射成了一种更简单的格式。
Unity 3D是由Unity Technologies开发的一个让玩家轻松创建诸如三维视频游戏、建筑可视化、实时三维动画等类型互动内容的多平台的综合型游戏开发工具,是一个全面整合的专业游戏引擎。Unity类似于Director,Blender game engine, Virtools 或 Torque Game Builder等利用交互的图型化开发环境为首要方式的软件。其编辑器运行在Windows 和Mac OS X下,可发布游戏至Windows、Mac、Wii、iPhone、WebGL(需要HTML5)、Windows phone 8和Android平台。
Unity的资源加载及管理,基础很重要。此篇文章作为近期梳理项目内资源管理器的一个小总结,尝试尽量用人话将Unity对资源管理的关键点梳理清楚,个人觉得比较适合像我这样刚入门且对AssetBundle还不甚了解的家伙。
我理解的资源管理
举一个不恰当的例子来描述我所理解的资源管理(因为我实在想不出更合适的例子了),想象一个画面:一个表演者,站在一个台子后面,面向观众,按照规定的剧本, *** 作着台子后面不被观众看到的箱子,从里面不断的取出和放回各种新鲜的玩意儿,一会这么组合,一会那么拆散,博观众的眼球,最终完成表演。
我没有当表演者的经历,虽然我很想尝试,但想想也觉得这肯定不容易:
1、如果箱子里的东西都太大,拿起来会很费劲。
2、如果太小呢?恐怕会拿很多次。
3、不用的道具不收?放在台子上会影响接下来的表演。
4、用过的道具收了吧。万一收了后面需要的道具,一会儿用的时候还要再费劲拿一次,不拿的话吧还容易导致表演失败。
带着问题看文章
是选择合适的时间取出资源,并在合适的时候释放它们,尽可能保持较低的内存占用;还是选择让资源常驻内存,换取更快的读取和计算速度?如何在时间和空间上做出平衡,才能最大的提升游戏体验?我以为这些就是资源管理的目标和意义。可惜这并非易事。这不仅需要结合项目的实际情况,更需要丰富的实战经验。
但是在这里,你将不会看到任何可以参考的经验或建议,因为我也不知道啊。
无论你是否单身,在Unity的世界里,你都不愁找不到对象,因为一切都是对象。
无论是纹理、音乐还是预制体,在进入Unity的世界后,都变成了各种对象供我们使用,例如纹理转变为Texture2D或Sprite,音效文件转变为AudioClip,预制体变成了GameObject等等。这个由Asset(资源文件)转变为Object(对象),从磁盘进入内存的过程,就是实例化。而对资源进行的管理,本质上是对Object的管理。
“小当家,这个黄金炒饭是怎么加载出来的?”
简单介绍一下Unity加载资源的流程
在介绍Unity的资源加载机制之前,先举一个生活中的例子,来辅助我们了解Unity是如何工作的。
因为我从小热爱欧洲文学,所以在这就拿我最喜欢的《三国演义》做例子,我们都知道书中多次提到 “集齐七颗龙珠,就可以召唤神龙,并帮你实现一个愿望” 这种说法。
咸鱼都有梦想,何况一个上了岁数的程序员呢?但是很可惜,我们一颗龙珠都没有,为了凑齐这七颗龙珠,我们首先要知道它们分别在哪。一摸左兜,哎?发现了一本《召唤神龙的小诀窍》,里面记录了召唤神龙所必须七颗龙珠的 所在位置、大小、颜色以及如何使用等非常关键的信息 。
根据《召唤神龙的小诀窍》指引,我们知道原来第一颗龙珠藏在了素有小巴黎之称的北京通县,可是通县在哪儿呢?一摸右兜,原来这还有一本1986年出版的《中国地图》。那就放心了,出发吧!
终于,历经了81难,我们来到了目的地并最终找到了这颗龙珠。费这么大劲找到的龙珠,当然应该认真记录下来,于是我们马上掏出一个黑皮小本本,认真的记下: “第一颗龙珠放在背后小书包的左边缝有一个机器猫的侧兜里” 。
最终,经历了无数艰难险阻,我们凑齐了七颗龙珠(所以说人只要肯努力,老天就一定回馈你,至少让你知道你浪费了时间啊)。金光一闪,我们召唤出了神龙 后面实现了什么愿望我们不谈,因为谁没有点小秘密呢。
现在,让我们来回顾一下整个过程
1、这条召唤出来的神龙,就好比我们想要实例化的对象,就比如游戏对象吧,因为它相对复杂些。而这七颗龙珠呢,就好似组成这个游戏对象所必须的各种组件(Component)、纹理(Texture)、网格(Mesh)等等。
2、《召唤神龙的小诀窍》就好比我们读取的这个prefab文件,它记录了组成这个GameObject所必须的其他对象以及它们的位置。
重点来了:File GUID 及 Local ID。
File GUID
Unity会为每一个加入到Assets文件夹中的文件,创建一个同级同名的meta文件,虽然文件类型的不同会影响这个meta的具体内容,但它们都包含一个用来标记文件身份的File GUID。
例如,如果一个资源引用了另一个外部资源,比如一个Prefab引用了其他脚本、纹理或Prefab等,则一定会标明引用资源文件的File GUID。
Local ID
如果说File GUID表示为文件和文件之间的关系,那么Local ID表示的就是文件内部各对象之间的关系,打开一个Prefab文件可以很清晰的看到:
(点击上图,可放大查看)
一个对象通常是由 一个或多个 对象构成,每个记录在&符号后面的数字都是一个Local ID,每一个Local ID也表示这它将来也会被实例化成一个对象。也就是说,当一个prefab文件要实例化成一个GameObject时,它会自动尝试获取其内部Local ID所指的那个对象。如果这个所指的对象当前还没有被实例化出来,那么Unity会自动实例化这个对象,如此递归,直到所有涉及的对象都被实例化。
3、我们可以发现手中没有龙珠,是因为我们手中的黑色小本本,并没有记录龙珠装在书包的那个位置里;同样,Unity通过 Instance ID ,来获取或判断一个对象是否已经被加载完毕。 Instance ID由File GUID和Local ID转换而成,可以简单理解成是记录了资源所在内存地址的写着数字的钥匙牌。
每当Unity读入一个File GUID和LocalID时,就会自动将其转换成一个简单好记的数字牌,因为通过File GUID和Local ID定位资源的效率并没有直接解引用一个地址那么快。
如果发现这个牌上并没有挂着一把钥匙,表示当前这个这个资源还在磁盘中,尚不在内存里(没有加载);相反,如果这个牌子上有一把钥匙,表示这个资源已经被加载完毕,你可以快速的找到并使用它。
Unity会在项目启动后,创建并一直维护一张“映射表”,这张映射表记录的就是File GUID、Local ID以及由它们转换而成的Instance ID之间的关系,这样下次在请求资源时就可以快速的通过查看钥匙牌来获取资源了。
4、刚才的例子里,因为没有龙珠(资源没有加载),因此我们必须经历一场前往小巴黎的历险(LoadingAsset),而能够帮助我们准确定位北京通县的86版《中国地图》,可以近似理解成是 Unity维护的一套将GUID和FileID解析为数据源地址的机制, 这套机制中的信息,来自于:
(1) 场景加载时,Unity收集了与该场景关联的资源信息。
(2) 项目启动时,Unity收集了所有Resources文件夹下的资源信息。
(3) 读取AssetBundle时,Unity获取了AssetBundle文件的头部信息(Header)。
可以理解为:随着Unity知道更多的信息,这套机制将能够解析并定位更多的GUID和FileID。
5、当我们费劲千辛万苦找到龙珠后,记录在小本本上的7条位置,就好比7个能帮助够准确定位内存位置的Instance ID。想象一下,当我们下次再看到诸如《三颗龙珠召唤小神龙》这样的小诀窍( 另外一个prefab ),便可直接打开小本本( 查询映射表中的Instance ID ),对着编号及位置从书包里掏出龙珠( 对InstanceID所指的内存地址进行解引用 ),啪啪啪一 *** 作,小神龙这个游戏对象就能很快被召唤出来了,再也不用去什么通县了,可以节省大把时间,想想就觉的美滋滋呢。
AssetBundle
AssetBundle(阿赛特邦豆)是Unity官方推荐的资源加载方式,网上对AssetBundle的介绍有很多,且在了解了Unity对资源的加载机制后,其本身没有什么特别难以理解的地方了,因此在这不过多介绍,仅挑选几个关键点进行阐述。
AssetBundle的生成
生成AssetBundle有很多种方式,在此仅简单说一下比较常用的方式,使用BuildPipeline生成AssetBundle文件。
每一次调用BuildPipleLineBuildAssetBundles时,将会生成一批AssetBundle文件,具体数量根据传递AssetBundleBuild数组决定, 每一个AssetBundleBuild对象将对应一个AssetBundle及一个同名+manifest后缀文件 。其中AssetBundle文件的后缀用户自行设置,比如"unity3d","ab"等等;而manifest文件是给人看的,里面有这个AssetBundle的基本信息以及非常关键的资源列表。
除了AssetBundleBuild数组所定的AssetBundle外,还将额外在output路径下生成的一对与output文件夹同名的文件及一个同名manifest后缀文件。这个同名文件可厉害了,它记录了这批次AssetBundle之间的相互依赖关系。当然manifest文件还是给人看的,我们可以用它分析资源间的依赖关系,但是在项目实际运行时,Unity并不会关心它。
(点击上图,可放大查看)
可以通过这张图来看一下每次Build后资源的对应关系,当然这都不如你自己亲自Build一次看的清楚。
AssetBundle的加载
根据AssetBundle文件所在的位置(本地、远端),AssetBundle有不同的加载方式,在此仅总结最常用的本地AssetBundle文件加载。
我个人将AssetBundle拆分理解为: Bundle加载 和 Asset加载 两部分。因为AssetBundle文件可以从功能上分为两大块:
1、记录文件标记、压缩信息、文件列表的Header部分;
2、记录资源实际内容的Data部分。
当使用AssetBundleLoadFromFile或LoadFromFileAsync时,在pc平台及移动平台上,unity 仅会为我们读取AssetBundle的header部分,并不会将bundle的data部分整个读入内存。
当调用上一步生成的AssetBundle对象读取具体资源时(LoadAsset, LoadAssetAsync, LoadAllAssets),Unity会参考已经缓存的文件列表,找到目标资源在data部分的位置并读入到内存中。
如果一个资源引用到了其他资源,则必须要先读入被引用资源的AssetBundle文件,否则就会发生引用Miss。 这就好似召唤神龙时,通过《召唤神龙的小诀窍》得知第一颗龙珠在北京通县,但是当打开《中国地图》时,北京的地方被抠了一个窟窿,我去,这样我们就无法通过它准确定位龙珠位置了,只有六颗龙珠召唤出的神龙,当然有一部分是Miss喽。
为了避免上面Miss的情况,在加载资源时, 首先需要将该资源的依赖项全部加载完毕,不过仅需加载依赖资源的AssetBundle文件。 也就是说,我们只要将该依赖AssetBundle的Header部分加载(AssetBundleLoadFromFile或LoadFromFileAsync)就可以,这样在真正读取Asset时,Unity会自动处理好真实依赖的Asset,我们不用 *** 心。
AssetBundle的依赖关系如何读取呢?加载上面提到的那个很厉害的文件就可以了。
(点击上图,可放大查看)
非常简单的获取依赖关系的方法,通常会在项目启动时将全部依赖关系保存下来。
AssetBundle的使用
当AssetBundle被成功加载后,调用该Assebbundle对象的LoadAsset、LoadAllAssets或对应的异步版本即可加载资源,也就是实例化对象。如果这个对象已经被加载过,Unity并不会重复加载,还记得之前所说的映射表么,被加载过的资源就好比挂上了数字牌的钥匙,直接对地址解引用即可。
AssetBundle的卸载
如果说AssetBundle真的有什么容易出问题的地方,那恐怕就是卸载了。
在这里只说最常用的这个卸载方法吧:
public void Unload(bool unloadAllLoadedObjects);
一个被加载过的AssetBundle可以通过调用Unload来卸载这个Bundle下所有的Asset。但是调用这个函数时传入的参数 对卸载结果影响甚大。
Unity官方对这个函数的讲解非常详细,配图也非常直观,因此我只是简单总结一下。
相同点:
无论传入参数为 true 或是 false,调用Unload都可以Destroy当前AssetBundle对象,释放之前从AssetBundle文件中的Header部分所获取的信息。当然,被释放的AssetBundle对象无法再使用诸如LoadAsset、LoadAllAssets等函数加载资源。
不同点:
unloadAllLoadedObjects == true:
不仅Destroy了AssetBundle这个对象,而且 这个AssetBundle下包含的所有对象,只要实例化了,有一个算一个,统统释放掉。
感觉就像
foreach(Object asset in assets)
{
if(asset != null)
{
delete asset;
asset = null;
}
}
比如你通过abLoadAsset(apple)后,将apple设置给go_0的一个Renderer,如果这时候abUnload(true),那go_0就傻了,咋回事儿啊,图咋没了呢?WTF啊。
它的好处是: 不会有重复资源问题的情况发生,每次都处理的干干净净。
unloadAllLoadedObjects == false:
仅仅Destroy了AssetBundle这个对象,但是并没有释放这个AssetBundle下的任何Asset,因此如果有对象引用了这些Asset,也不会有问题。
它的风险(代价)是:下次再Load这个AssetBundle,并且通过这个AssetBundle重新读取了这个Asset,会在内存中重新创建一份,这样如果之前的Asset没有被释放,那么现在内存中就有两份Asset了。
这种情况如果频繁发生,便意味着内存中有很多资源将“不受控制”,容易引发内存占用过高的问题,而释放这种不受控的资源,仅有两种方式:
1、当没有对象引用到这些不受控资源时,每次调用ResourcesUnloadUnusedAssets,回收之。
2、加载场景时,如果加载模式没有设置为LoadSceneModeAdditive,则会自动调用ResourcesUnloadUnusedAssets。
同样,再举一个生活中的小例子以阐述这两种释放的差异吧:
小A交女朋友时喜欢送心形的石头给对方,这天小A认识了一个女孩,并确定了关系,送了一个精心挑选的心形石头给她,海誓山盟又云雨一番后,第二天由于感情不和等原因两人分手了。小A是个暖男,他为了女孩能彻底忘记优秀的自己并开始一段新的感情,约见了女孩,将之前送给女孩的石头拿(搬)走了,从此注销了微信消失在茫茫人海中。
确实,小A喜欢强壮的女孩,因为这样比较有安全感。
小B交女朋友时也喜欢送石头给对方,周一小B认识了一个女孩,并确定了关系,送了一个精心挑选的石头给她,海誓山盟又云雨一番后,第二天由于感情不和等原因两人分手了。但是小B家里是开石材加工场的,他并不关心这块石头,”送了就送了吧,至少我经历了浪漫的爱情“,小B这么想。并注销了微信消失在茫茫人海中达1天之久。
周二的时候小B重出江湖,并认识了一个新的女孩,确定了关系,第三天第四天啪啪啪第七天,第二周的时候,江湖上就出现了一个传说,集齐小B凑齐的七颗石头,便可以召唤神龙,于是就回到了文章开头我们提到的那个故事。
没错,小A对应的就是Unload(true),而小B对应的则是Unload(false)。
补充三点
1、移动Unity资源时,要在Unity编辑器内拖动,不要在 *** 作系统下剪切粘贴。因为这样Unity会为这个文件生成一个新的File GUID及meta文件,它会打破之前建立好的关系,让所有引用过这个文件的prefab出现miss的情况。
2、实际上在项目build完成后,就已经不存在File GUID和Local ID的概念了,转而用相对简单方式建立映射,这也是为什么我们在项目运行的过程中无法获取到File GUID的原因,不过原理上它们是一样的。
3、尽管一个AssetBundle的Header部分非常小,通常只有几十KB,但是Unity并不能保证读入大量AssetBundle的Header部分后资源的加载效率。因此还是按需读取AssetBundle吧。
以上就是关于unity UGUI如何获取鼠标指针所在位置的UI对象全部的内容,包括:unity UGUI如何获取鼠标指针所在位置的UI对象、unity设置模型骨架的坐标、如何在 Unity 中获取某个对象的依赖关系等相关内容解答,如果想了解更多相关内容,可以关注我们,你们的支持是我们更新的动力!
欢迎分享,转载请注明来源:内存溢出
微信扫一扫
支付宝扫一扫
评论列表(0条)