#Render Queue VS Sorting Layer , what it is the difference between the two concepts ?
Answer : Render Queue is at the shader level while sorting layer at a higher level , developed specifically for Sprites but open for use by any renderer . The concepts i suppose are similar in that you are grouping together and ordering renderable draw calls , but since you may have batched sprites( or other renderers ) that use the same material ( and thus the same render queue ) , you may need an extra "sorting" capability to determine the priority of drawing sprites from a single texture.
Render Queue is the lowest level sort applying to everything in the scene , while Sorting Layer and then Order in Layer provide an extra sub-sort specifically for Sprites . Sorting layers were developed for Sprites to have the ability to place one sprite over another , but you can apply them to you own renderer as well : github.com/nickgravely…
If you had two sprites that used two different materials , and the render queue on those materials differed , but the sorting layer was the same , you may get unexpected results since the render queue would take priority and override the Order in Layer . But I can't confirm that .
Questioner : I think you are right, except that sorting layer is not limited in sprite, all renderer has sorting layer.After some testing, I find that sorting layer only works for objects in the same render queue. It means you can using sorting layer to sort rendering order of sprite and particle system, because both sprite and particle shader has the same "Transparent" render queue.
That is correct, but only the Sprites (currently) expose it in the inspector, meaning to me this is how Unity intended it to be used. But it is a handy feature, so I will update my post to correct that. I was trying to think of a good reason to use it, and you just pointed it out. That would be very handy indeed if you wanted to mix 2D sprites with other engine features like particles so the particles are always on top.
Source Original : answers.unity.com/questions/6…
背包系统
1 - grid auto layout 2 - UI 按钮 图片接口 3 - 是不是只有继承自monobehaviour的类才可以作为脚本组件添加给游戏对象 ; 4 - localscale ?? 5- resources.load() ;
当且仅当UI元素的锚点集中定位于父Rect Transform中心时 , Rect Transform显示的pos(x,y,z)才是transform.localScale ;
当UI元素的各锚点集中于一点,但并不位于父Rect Transform中心时 , Rect Transform显示的pos(x,y,z)并不是localPosition,
而仅仅是Pivot点相对于锚点的位置 ;
当UI元素的锚点成线段式的时候, 即>------< ,PosX
Rect Transform显示的pos(x,y,z)仅仅只是描述了UI元素的Pivot点于Anchors (称之为可变的原点)的相对位置 ,所以rect TransForm的值随着Pivot于Anchors
的相对位置的不同而不同 ;虽然随着锚点的分布不同 。 pos(x,y,z)会被top,left,right,bottom所替代,但是其依然描述的是
而UI元素的local position所参考的原点却是固定的 , 总是位于父rect transform的中心位置 ;
所以当且仅当UI元素的Anchors集中抛锚于父rect transform中心时 ,rect transform的pos(x,y,z)才与local position在数值上相等 ;
锚点的不同分布决定了Rect Transform组件将如何描述子Rect于父rect的相对位置, 这种相对位置也说明了子rect将如何随着父rect做适应性变化,分为以下集中情况
1 , 当各锚点集中定位于父rect transform中一点时 ,Rect Transform显示的位置信息由pos(x,y,z)所描述 , 即pivot以Anchors为原点的坐标 ;这种相对位置情况
说明了子rect不会随父rect做适应性变化 ,仅仅只会保持原有尺寸固定于父rect中 ;
2,当锚点两两分开成线段时 , 分为两种情况 : 水平和竖直 。 当呈水平分布时 >-----< , 意味着在子rect将随着父rect在水平方向上做适应性的变化,竖直方向上将不会变化,
所以用于描述适应性变化的相对位置信息将由(posX , posY , posZ ,width , height )变为( left , posY , posZ ,right,height ) ;
3 ,当四个锚点完全分散开后,意味着子rect将随着父rect同时在水平和竖直两个方向上发生适应性变化 ,用于描述适应性变化的相对位置信息将由(PosX , PosY ,PosZ , width , height )变为
(left , top , posZ , right , bottom) ,
上面描述的是通常的情况 ,但是如果添加了某些组件,那么上述的相对位置描述将由该组件来定义 ,;
比如Text 添加了Content Size Fitter之后 ,对第2种情况 ,posY不变 ,但是left会变成PosX , 此时PosX和PosY
参照的坐标系原点是由Content Size Fitter定义的 ,(0,0)始终位于 >-------<的直线上(这也是为何posY会保持不变),
具体位置由pivot相对于Text-Rect的相对位置而定 ;
对于第3种情况 ,相对位置信息将有 (left , top , posZ , right , bottom)变为(posX,posY,posZ, W Delta , H Delta ) ;
具体位置也由pivot点相对于Text-Rect的相对位置而定 ,若pivot在Text-Rect内部,则原点也在内部 ,pivot点在外部 ,则原点
也被定义在外部 ;对应于2,3两种通常情况的特殊情况 ,位置信息全部都是由pos(x,y,z)的形式来定义的 ,在Rect-Transform组件中
,若位置信息为pos(x,y,z)的形式 , 就意味着子rect只会保持对父rect的相对定位 ,而不会随父rect做适应性的变化 ,无论是以何种方式来
定义的相对位置,结论都是如此;
上述所描述的所有情况 , 无论是通常情况 , 还是特殊情况 , 本质上都是以不同的定位方式来确定子rect在父rect中的相对位置。
从而保持子rect相对于父rect的定位和尺寸比例 ;
需要注意 , local position和rect transform在定义上不是等同的 ,它们仅仅在锚点集中于父rect中心时在数值上相等 ;
脚本系统
File --> Build Setting ---- >按顺序添加多场景(按顺序从0开始) 。 如果游戏只有一个默认场景,那么那么该场景默认是0 , 且不会显示在该框中出现 ;
***Unity的C#脚本系统只是在语言操控的角度实现了Unity可视化操作的功能(替代性而已),是平行对应的关系 ; 对这种对应关系的思考 , 如场景中的按钮Button ,是一个游戏对象 , 类Button相当于一个操纵游戏对象本身特性的接口 , 用于修改游戏对象的参数 , 而语言和Unity场景对象的中间映射操作 ,是由Unity来完成的 。 就如 作为游戏对象的按钮Button 和 类Button 是一条线段的两个端点 ,是对应的关系 , 开发者通过操纵(编程)类Button这个端点 , 从而实现控制游戏对象按钮Button的目的 。而中间的线是Unity应该发挥的作用 ;
又如OnPointerClick(EventData)也是同样的道理 , 作为开发者操纵的端点 ;
IPointerEnterHandler, IPointerExitHandler,IDragHandler,IBeginDragHandler,IEndDragHandler
通过实现这几个接口 ,可以定义在指定的gameObject区域内如何对鼠标事件进行反应 。通过实现IPointerEnterHandler, IPointerExitHandler ,分别定义鼠标指针进入gameObject区域那一刻和离开gameObject区域那一刻的反应 ;通过实现IDragHandler,IBeginDragHandler,IEndDragHandler ,分别定义鼠标指针在区域内开始拖拽那一刻,拖拽中,结束拖拽那一刻的反应 ,值得注意的是 ,这三个接口包含现IDragHandler,所以是连贯的一个历程,不像上述两个事件接口一样,只实现了两个时刻---开始和结束 ;而且需要注意的是 ,IBeginDragHandler,IEndDragHandler不能脱离IDragHandler而单独实现 ,否则这两个拖拽事件将无效 ,还值得一提的是 ,拖拽的开始只能发生在gameObject区域内,而拖拽中的整个历程可以发生在区域外,此时eventData的信息会被一直更新,直到拖拽结束;
通过这几个接口实现的事件函数 ,在触发时都会自动接收一个PointerEventData类型的实例参数eventData ,一定要注意!!! 这个eventData并不是几个对象,而是同一个对象 ,记录了事件发生时关于鼠标指针的各类信息,用作各类鼠标事件沟通的桥梁 ;比如eventData.pointerEnter引用了指针所指向的游戏对象 ,在各类鼠标事件被触发时被传递给相应的事件函数 ; 有些信息 ,比如布尔位eventData.dragging标示了是否处于拖拽状态 ,所以需要实现IDragHandler,IBeginDragHandler,IEndDragHandler ,当拖拽一开始 ,eventData.dragging便被设置为true ,当拖拽一结束便被设置为false ;
由一个问题引发的对帧处理的思考
transform.translate(Vector3 stepVector ,Space relativeTo)是一个步进的函数。第一个参数stepVector是一个步进向量,决定了每次调用的步进的方向和距离 。第二个参数relativeTo是枚举类型为Space的变量,Space有两个具体的枚举值 ,分别是Space.Self 和 Space.World ,含义是自身坐标系和世界坐标系 ,所以relativeTo表示了transform.translate变换的标准是自身坐标系还是世界坐标系 。当然如果gameObject的transform没有进行旋转等变换,那么gameObject的自身坐标系和世界坐标系是一致的(方位取向),那么 ,不管以哪一种坐标系作为移动变换的标准 ,结果都是一致的。
所以单次调用transform.translate(Vector3 stepVector ,Space relativeTo)等价于 :
- transform.translate(Vector3 stepVector ,Space.World) <=> transform.position += stepVector ;
- transform.translate(Vector3 stepVector ,Space.Self) <=> transform.localposition += stepVector ;
另外还需要注意的是,Space.Self指的是gameObject-transform的自身坐标系 , 不要将它和父transform的坐标系相混淆 ;
transform.lerp(Vector3 startPos ,Vector3 endPos , ratio)是插值函数 ,它是和空间无关的 ,它仅仅只是一个数值计算函数。比如startPos和endPos都是Vector3类型的 ,分别代表的是起点坐标和终点坐标 ,transform.lerp并不关心这两个坐标是Space.Self下的 ,还是Space.World下的 ,它仅仅把其当作数值来计算插值,并根据比率ratio来返回这个插值 ,等价的公式为 :
transform.lerp的应用 :
- 如果startPos和endPos是Space.World下的 ,那么 : transform.position += transform.lerp(startPos,endPos,ratio) ;
- 如果startPos和endPos是Space.Self下的 ,那么 :transform.localposition += transform.lerp(startPos,endPos,ratio) ;
对这两个函数需要注意的是 ,它们是帧相关的 ,一个对初学者常见的错误是:尝试一帧中调用多次的transform.translate或者tranform.lerp() ,以期呈现出过渡的效果 。 这是绝对不可取的 ,因为这种方式并不会如你所愿拥有过渡的效果 ,而是直接从起始点到累加计算下的最终点 。因为帧处理的最后部分才是Rendering ,才会把帧处理的前部分的计算结果渲染到屏幕上 ,注意! 渲染的是最终计算结果 !!!。
还可以从上述引申的一点是 ,脚本中的每一个用户自定义函数都是帧相关的 。为什么这么说呢 ? 我们可以把脚本中的函数分成3类 :
- 事件响应函数 ,比如 IPointerEnter() , IPointerExit,IDragHandler,IBeginDragHandler,IEndDragHandler等等 , 它们的执行依靠于事件的触发 ;
- Unity预留的自执行函数 , 比如Awake() , Start() ,Update() , LateUpdate() , FixedUdpate()等等
- 用户自定义的函数
第一种函数毫无疑问是帧相关的 ,即只要在单帧中捕捉到事件的触发,就会调用并且处理事件响应函数中的计算任务。所以我们说它是帧相关的 ,就是指它包含在帧处理的流程中 。
第二种函数也是帧相关的 ,但是诸如Awake(),Start()这类函数 ,只在游戏初始化阶段执行一次 ,所以我们就姑且认为它的计算任务只存在于第一帧的帧处理流程中;
而诸如Update(),LateUpdate(),FixedUpdate()这类的函数,是包含在每一帧的处理中的,虽然这对FixedUpdate()来说有点牵强(详见我的帧处理博文),但是这么说基本上也没错 .所以这类函数也是帧相关的 。
而对第三类函数 ,即用户自定义函数来说,它们基本上都是作为被封装的计算任务 ,你必须在事件响应函数和Unity预留的自执行函数中调用它们 ,它们才可以执行 。 所以从根本上说 ,用户自定义函数也是帧相关的 ,因为它们只是作为事件响应函数和Unity预留自执行函数的计算任务而存在(当然,纯数据类,及不包含函数的类除外) !