Unity常见UI基础问题手册
仅作个人笔记用途。
UI顶层显示方法一.做一个新的UI摄像机① Canvas的Render Mode设置为Screen Space - Camera
② 新建摄像机(后面称之为UI摄像机),放到原先摄像机的下面
③ 拖拽UI摄像机到Canvas的Render Camera
④ UI摄像机的 Clear Flags 设置为 Depth only,用来去掉背景;Culling Mask设置为 UI。
⑤ 确保 UI摄像机的Depth > 其他摄像机的Depth (值小的会先渲染,所以值大的会在前面)
参考超级细致的调试教学视频
C#精要 - 同步异步、多线程篇
零.为什么我会理解错在看完clr之前,我曾对异步同步探究看了十几篇文章,但很可惜,没有完全理解,只知道了一大堆概念:IRP、异步要借用多线程…
在看完之后,我理解并甚至尝试实现一个简单的异步的时候才明白,之前无法理解是因为我不懂:
异步编程 和 异步函数 是不同的东西。也就是说,异步函数async/await 只是异步编程的一种罢了,你大可以利用ContinueWith或ThreadPool等来实现异步。
很多博客混淆了这两个概念,我不知道他们是否真正理解了,但是这会导致我这种代码先行基础后补的菜b无法理解。
所以这篇文章的理解是片面的,等有空了我再整理一下。
一.同步与异步 项目中每天都在接触,但是对这俩概念比较模糊。看《CLR via C#》刚好提到了,就去网上找到几篇好文,理解写篇自己的笔记。首先得说明的是,这一节讨论的只是概念,都是单纯的、不考虑多线程处理的同步与异步区别。
IO 概念区分
同步(Synchronous)
异步( Asynchronous)
阻塞( Blocking )
非阻塞( Nonblocking)
那首先,要弄清楚同步异步、阻塞非阻塞之间的关 ...
C#精要 - 反射篇
反射反射提供了封装程序集、模块和类型的对象(Type 类型)。可以使用反射动态创建类型的实例,将类型绑定到现有对象,或从现有对象获取类型并调用其方法或访问其字段和属性。如果代码中使用了属性,可以利用反射对它们进行访问。
Assembly类可以获得正在运行的装配件信息,也可以动态的加载装配件,以及在装配件中查找类型信息,并创建该类型的实例。
Type类可以获得对象的类型信息,此信息包含对象的所有要素:方法、构造器、属性等等,通过Type类可以得到这些要素的信息,并且调用之。
MethodInfo包含方法的信息,通过这个类可以得到方法的名称、参数、返回值等,并且可以调用之。
反射:反射提供了封装程序集,模块和类型对象,可以用反射动态地创建类型的实例,将类型绑定到现有对象,或者从现有对象类型里获取类型,然后调用类型的方法或访问字段和属性。
序列化:将对象转换为另一种媒介传输的格式过程。如,序列化一个对象,用Http通过internet在客户端和服务器之间传递该对象,在另一端用反序列化从该流中重新得到对象。
C#精要 - Mono篇
IL是什么?IL的全称是 Intermediate Language,是一种中间语言。它是一种属于通用语言架构和.NET框架的低阶(lowest-level)的人类可读的编程语言。目标为.NET框架的语言被编译成IL代码,然后汇编成字节码。
具体过程是:C#或者VB这样遵循CLI规范的高级语言,被先被各自的编译器编译成中间语言IL。等到需要真正执行的时候,这些IL会被加载到运行时库,也就是CLR中,由CLR动态编译(JIT)成汇编代码然后在执行。
JIT是什么?just-in-time compiler,即时编译器。它将IL翻译成汇编语言,它自身会对运行环境做出许多假定,从而进行自己的优化方案。
比如第一次调用一个方法时,JIT会把遇到的IL代码进行验证+编译,最后放进内存中。方法仅在首次调用时才会有一些性能损失,以后对该方法的所有调用都以本机代码的形式全速运行。
Mono是什么?是支持.net跨平台的一种方式。因为.net本身不支持跨平台只能运行在Windows上,所以需要一个跨平台的第三方.net库,这就是Mono。
mono作为一个中间层将IL代码的处理分出好多个分支,分别对应不 ...
C#精要 - 委托与事件篇
委托和事件的区别是什么?委托本质是一个继承自System.MulticastDelegate的类;而事件是一个类型成员,是对委托的封装,就和属性是对字段的封装一样。
事件通过event关键词来定义。是对委托的封装。
为什么封装?为了让委托链的意义,从一个方法执行队列变成一个可订阅、可通知(触发)的中介。
怎么封装的?随便在类内定义一个public事件,再查看IL代码多帮我们做了什么:
1.生成一个私有的委托字段(没错还是委托链实现的)
2.生成add和remove方法,内部处理是对生成的委托字段进行Delegate.Combine、Delegate.Remove。
怎么设计?举个例子的话,WPF的画面交互事件用的EventHandler其实就是一个sender加一个args参数,自定义可以如下的:
1delegate void MyEventHandler(EventSender sender,MyEventArgs e);
委托委托本质是一个继承自System.MulticastDelegate的类,所以像类一样使用即可。
新建一个委托发生了什么?当你写delegate的时候,编译 ...
C#精要 - 类内成员篇
类成员初始化顺序一般初始化顺序:
子类静态字段内联
子类静态构造
子类实例字段内联
父类静态字段内联
父类静态构造
父类实例字段内联
父类实例构造
子类实例构造
原则就是:先内联后构造;先静态后实例;先子类后父类(除了实例构造器)。
方法abstract抽象方法、virtual方法、隐式实现接口方法,它们本质上、在IL代码层中,都是virtual方法。
IL提供两种方式去调用方法:
call:可用于调用实例方法、虚方法和静态方法。// 我个人测下来感觉只有静态方法是用call…
callvirt:可用于调用实例方法、虚方法。过程会比call复杂一些,事前会check null,执行时也会去查虚函数表。
非虚方式调用 callcall 调用的,是编译时确定的类型,也就是申明类型。
如果变量申明的类型没有对应的方法,就检查基类型来查找匹配方法。
虚方法调用 callvirtcallvirt 调用的,是运行时确定的类型,也就是变量指向对象的实际类型(new的类型)。
上面说的是结果,但如果深究过程,在IL代码层的话,多态方法全部都是 callvirt 最初父类的同一个方法 ...
C#精要 - 异步篇
什么是异步?异步是一种任务执行的机制或者说方式,它的目的在于解决I/O等待会阻塞线程这个问题(最常见的就是GUI线程阻塞造成画面卡顿),它的实现依托于硬件底层的IRP(I/O Request Packet),它的本质其实是回调。
我可以使用比如 ReadAsync + Task.ContinueWith 的组合,来实现一个异步实践;
而更简单的方式是通过微软后续推出 .net4.5 的 async-await 这套关键词来实践。
异步函数 async-await异步函数,实际通过 核心类TaskAwaiter + 状态机 实现。
核心类 TaskAwaiter这个类比较简单,每个异步Task都有。我把它看作黑盒不细究,只看对外接口:
IsCompleted 属性:表示Task是否完成
GetResult() 方法:结束异步任务完成的等待
UnsafeOnCompleted(Action) 方法:设置延续任务
使用方法await必须在有async标记的方法内使用。如果async方法内部没有await,那它就和同步方法一样执行。
如果执行中遇到了await,就把需要awai ...
C#精要 - 常用数据结构篇
数组最基本的数组类型。
真实类型所有数组类型都隐式从System.Array抽象类派生,System.Array又从Object派生,所以数组都是引用类型。Array实现了IEnumerable、ICollection、IList接口。
特点在内存中是连续存储的,所以它的索引速度非常快。
初始化在new的时候,就必须指定它的Length大小。
数组单个元素的类型:
如果是值类型比如Int32,就会在托管堆上分配100个未装箱Int32所需的内存块,并给每个Int32实例都附上default值0;如果是引用类型比如Control,就会在托管堆上分配50个Control引用的内存块,并给每个引用都附上null。
扩容无法动态扩容,只能手动调用接口Array.Resize (ref T[] array, int newSize)。
内部创建新数组,使用Array.Copy将原数组拷贝到新数组中,再修改传入指针指向新数组。如果新Length还不如原数组Length大,会采用新Length,多的直接截断不要了。
查找接口Array.Find (T[] array, Predicate<T& ...
工具篇:定点数物理碰撞库
定点数基于《工具篇:定点数运算数学库》的定点数库。
处理流程1.读取配置:初始化碰撞环境
2.读取配置:初始化玩家碰撞体
3.FixedUpdate(具体看《Unity生命流程》):固定帧率检测碰撞发生
碰撞配置ColldierConfig。
长方体类型:位置、长宽高、轴向。
圆柱体类型:位置、半径。
碰撞体逻辑-视图分离只维护逻辑值,视图则根据定点数逻辑值转换成浮点数来进行更新。但是,视图层更新后并不参与任何运算,只显示。
碰撞环境环境初始化的前提是根据固定方式制作地图:只用 BoxCollider 和 CapsuleCollider 两种碰撞体,且全部放在一个EnvRoot结点下。
初始化时,遍历这个根节点,将所有的BoxCollider转化为定点数长方体形碰撞体,将所有的CapsuleCollider转化为定点数圆柱体形碰撞体。
生成下来,放到一个List中保存。
碰撞检测+矫正计算(一对一)Cylinder碰到Box
1.求出 向量OK = Cylinder.Pos - Box.Pos。
2.求出 向量OK 分别在 Box.X方向向量、Box.Z方向向量 上的投影的长度:
使用 ...
工具篇:定点数运算数学库
初识什么是定点数?约定计算机中小数点的位置,且这个位置固定不变,小数点前、后的数字,分别用二进制表示,然后组合起来就可以把这个数字在计算机中存储起来,这种表示方式叫做「定点」表示法,用这种方法表示的数字叫做「定点数」。
为什么不用浮点数?具体怎么使用?定点数参与逻辑运算,转换回浮点数后不再用浮点数参与任何逻辑运算。
定点数型Int从浮点数转换到定点数放大1024倍,从而使得浮点数小数误差变小。
用long存储防止高位越界。
使用移位运算实现,比直接乘更优。
int型转换可以不损失精度;float型转换需要损失一些精度:(long)Math.Round(f * 1024)。
乘除运算出现问题乘法运算相当于多乘了一次倍数,所以直接除以1024(右移10位)即可。1024(原数1) * 2048(原数2) = 2^21 (原数是2^11而不是期待的2)
除法运算相当于多除了一次倍数,所以直接乘以1024(左移10位)即可。2048(原数2) / 1024(原数1)= 2 (原数是2^-9而不是期待的2)
大小比较简单重写operator。
定点数转换回浮点数缩小1024倍之后强转float ...

