1.生命周期
初始化阶段
Awake:仅被调用一次,不同的物体顺序随机调用
OnEnable
Start:仅被调用一次
物理阶段
FixedUpdate:处理刚体时
yield WaitForFixedUpdate
OnTriggerXXX
OnCollisionXXX
游戏逻辑阶段
Update
yield null
yield WaitForSeconds
yield WWW
yield StartCoroutine
LateUpdate:所有update函数调用后被调用
GUI渲染阶段
OnGUI
帧结束阶段
yield return WaitForEndOfFrame
暂定阶段
OnApplicationPause
物体激活禁用阶段
OnDisable
应用结束
OnDestroy
OnApplicationQuit
2.协程是什么
在主线程运行的同时开启另一段逻辑处理,为了协助当前程序的执行
Unity的协程在每帧结束后,去检测yield的条件是否满足
3.协程和线程的区别
多线程是同时运行多个线程
协程是通过协作完成,在任意指定时刻只有一个协程在运行
协程可以操作unity 的方法和componet,线程不可以
使用场景:定时器,下载资源
4.协程的原理
协程的关键字是IEnumerator,也是遍历时候的迭代器关键字
保留运行状态以便下次继续往下运行
延时的功能主要靠 WaitForSeocnds 实现
其实就是记录一个时间变量,循环内一直yield return null,达到时间就退出
StartCoroutine后,会对IEnumerator进行MoveNext操作,如果是WaitForSeocnds类型,就会进行等待
5.协程优化
缓存WaitForSceonds对象,使用字典存储
避免产生GC开销
可以自己封装一层协程
6.Update和FixedUpdate的区别
Update是每渲染新的一帧会调用
时间间隔的不确定的,有时候渲染快,有时候喧染慢
FixedUpdate是固定间隔调用的,取决与TimeManager里面的FixedTimeStep
默认是0.02,1/0.02=50,就是50次,可以保证一秒内调用50次
void Update()
{
time += Time.deltaTime;
if (time >= 1f)//调用的次数=1/0.02f*1f
{
time = 0f;
//第50次的FixedUpdate
}
}
FixedUpdate也是基于Update实现的,如果更新频率快就反复调用,更新频率慢就会等待调用
void Update()
{
time += Time.deltaTime;
if (time >= 0.02f)
{
int count_2 = Mathf.FloorToInt(time / 0.02f);
for (int i = 0; i < count; i++)
{
Debug.LogError("应该调用 FixedUpdate 了");
}
time = 0f;
}
}
7.为什么Unity能调用到Start、Update
没有override,就是通过反射的方式
查找场景内的全部MonoBehaviour,将方法指针记录下来
然后统一进行调用
8.记录节点空间几何信息的组件
是Transform
其父类是Component
9.四元数和欧拉角
欧拉角由三个角度组成、直观容易理解
缺点就是存在万向锁问题
四元数内部有xyzw四个数字组成,可以解决万向锁问题
10.向量点乘、叉乘以及归一化的意义
点乘:描述了两个向量的相似度,结果越大两向量越相似,还可表示投影
叉乘:得到的垂直于原来两个向量的向量
归一化:只关心方向,不关系大小
11.矩阵相乘的意义
用于表现线性变化:旋转、缩放、投影、平移等等
12.MeshRenderer的作用
Mesh是模型的网格
MeshFilter是获取模型网格的组件
MeshRenderer是把网格渲染出来的组件
有蒙皮的模型导入Unity,自动添加SkinnedMeshRenderer
13.动画是怎么动的
先建立人物的骨骼
制作蒙皮,把模型绑定到骨骼上,使用T-Pose
设置模型上每个控制点对肌肉和骨骼的影响程度
调节绑定骨骼,使模型动起来
14.模型如何换装
获取需要换装的每个部位的SkinnedMeshRenderer
获取要替换的SkinnedMeshRenderer
遍历骨骼节点,获取对应的骨骼信息(先遍历要替换的,再自身的,如果一样就获取)
进行替换,绑定骨骼,替换材质,更换sharedMesh
15.场景中放置多个Camera会怎么样
可以看到多个摄像机的混合
一般UI专门有一个摄像机,调节为depth only
16.高速碰撞
会穿透,碰撞检测失败
可以调碰撞体变大,或者使用射线检测(代码限制)
17.OnBecameVisible和OnBecameInvisible
OnBecameVisible() : 当物体在/进入摄像机会调用一次
OnBecameInvisible() : 当物体离开摄像机会调用一次
18.material和sharedMaterial的区别
修改sharedMaterial将改变所有物体使用这个材质的外观,也改变存储在工程里的材质设置
material不会
19.LOD是什么?
Levels of Detail,多层次细节
会根据离摄像机的远近和重要度,决定渲染的资源分配
降低不重要物体的面数和细节都,从而获得高效率的渲染运算
20.Mipmap是什么?
为了加快渲染速度和减少图像锯齿
贴图变成由一些列预先计算和优化的文件
21.碰撞器和触发器的区别
collider碰撞器会有碰撞的效果,触发OnCollisionXXX函数
isTrigger=true后,就是触发器没有碰撞效果,调用OnTriggerXXX函数
22.CharacterCOntroller和Rigidbody的区别
Rigidbody具有完全真实的物理特性
CC是受限制的刚体,具有一定的物理效果但不是完全真实的
23.刚体如何施加力
AddForce
AddForceAtPosition
24.物体旋转的函数
transform.Rotate:自旋
transform.RotateAround:绕着某点旋转
25.unity几种光源
平型关、聚光灯、点光源、区域光
26.对象池
当需要频繁创建或销毁物体,需要优化来节省内存
做一个pool,开始时预先实例化足够的数量,然后用的时候取出不用的时候收回
27.prefab是什么
预制件,相当于一个模板,便于加载
28.常用优化方法
1.对象池,暂时不用的物体隐藏而不是Destory掉
2.释放AssetBundle占用的资源
3.使用光照贴图,不使用实时光源
4.UI的动静分离、合批、循环滑动
5.设置纹理的压缩格式
6.缓存经常用的组件
7.少用GameObject.Find
8.自定义Updater(Unity会做一些检查,遍历所有的update脚本,是否可以调用,准备去调用等等)
9.Animator.Set,提前进行hash
10.缓存YieldInstruction
29.加载资源的方式
静态引用:生命public遍历,不易控制生命周期
Resources.Load:会打到包内,无法进行热更新
AssetDataBase.Load:只能编辑器下
AssetBundle:可以更好的管理资源,与资源的热更新
Addressable:2019新出的资源管理系统
30.Animator和Animation的区别
Animation只有控制动画播放的方法
Animator有更高级的功能,比如状态机、骨骼动画、动画融合等
31.常用数学函数
Mathf.Abs:绝对值
Mathf.Round:四舍五入
Mathf.Clamp:限制
Mathf.Lerp:插值
Mathf.Floor:向下取整
Mathf.Ceil:向上取整
32.用鼠标实现场景中拖动物体,用鼠标滚轮实现缩放
缩放直接控制相机的FOV
Camera.main.fieldOfView -= Input.GetAxis("Mouse ScrollWheel") * 10f;
拖动需要:
求出当前物体与鼠标的世界坐标的偏移offset,鼠标的z轴使用物体的屏幕坐标z
按住时计算鼠标的世界坐标+偏移offset即可
33.MVC、MVP、MVVP
MVC是Model、View、Controller,交互流程:V发起C,C更新M后刷新V
MVP多了Presenter,对M和V的解耦,交互流程:V发出给P事件,P更新Model后刷新V
MVVM多了ViewModel,交互流程:VM进行数据绑定,更新的Model自动刷新到View
存在BindableProperty<T>,封转一个属性,set方法里面触发事件
View里面存在对应的ViewModel,并且调用Bind方法,修改后触发回调,直接刷新视图
34.圆形图片替代Mask
重写OnPopulateMesh进行顶点填充
通过VertexHelper添加顶点、三角形、UV
中心点:
Vector2 center = new Vector2((rect.width * (0.5f - pivot.x)), (rect.height * (0.5f - pivot.y)));
顶点坐标:
(0,0)UV(0.5f,0.5f)
其他:
float x = center.x + radius * Mathf.Cos(angdeg);//x就是cos
float y = center.y + radius * Mathf.Sin(angdeg);//y就是sin
float uvX = (radius * Mathf.Cos(angdeg) + radius) / (2 * radius);//(x+r)/2r
float uvY = (radius * Mathf.Sin(angdeg) + radius) / (2 * radius);
35.推荐三本0基础本书
零基础学C#
Unity入门到精通
3d数学
36.UGUI事件系统
可触发的事件,基于不同的接口
PointerEnter、PointerExit、PointerDown、PointUp、PointClick、Drag、Drop、Scroll等等
37.UGUI渲染层级
Canvas的渲染模式:
Overlay:屏幕最前方
Camera:基于相机
WorldSpace:基于世界坐标
同一Canvas下的层级:
根据transform的siblingIndex,值越大越后渲染层级越大,显示在前面
不同Canvas下的层级:
根据SortOrder
38.UI框架
管理场景中的所有面板,控制面板之间的切换
新开发面板只需继承面板基类,只需关心自己逻辑即可
UIBase生命周期:
OnCreate、OnShow、OnHide、OnDestory
UIManager管理所有UIBase:
Show方法显示UI
如果没有就加载,调用OnCreate,继续调用OnShow
如果有,直接调用OnShow
Hide方法隐藏UI
调用OnHide
Destory方法销毁UI
调用OnDestory
对于弹窗式的UI采用栈存储,必须先关闭栈顶的面板才能关闭下面的
另【最重要的】数据逻辑分离
39.Event框架
可以添加事件以及移除事件,进行独立模块解耦
主要用Dict存储Key和注册的委托,Key可以使用枚举
委托可以多封装几个Action提供多参数泛型,避免使用object有装箱拆箱操作
40.光照贴图
增强静态场景光照效果的技术,使用较少的性能让静态场景看上去更真实
41.如何实现游戏的暂停、加速和减速
Time.timeScale=0,可让游戏暂停
Time.timeScale=2,可让游戏加速
42.技能释放怎么做
游戏中技能一般都是动作+粒子特效
美术给做好特效,只需切换动作的时候播放特效即可
43.有限状态机
状态机负责管理所有状态以及状态的改变
每个状态封装成一个基类FSMState,生命周期:
OnEnter、OnUpdate、OnExit
状态管理FSMSystem:
负责状态注册、切换、以及执行Update
缺点:
针对状态编程,不可复用,跑和攻击时一个单独的状态
如果新增边跑边攻击还需要重新写一个状态
可用行为树:针对行为编程,跑和攻击都是一个行为,可以复用行为
44.行为树
定义好行为树,程序运行时会自顶向下通过条件搜索这棵树,最终确定需要做的行为,并且执行它
根节点->随机选择节点->逃跑、战斗、待机
Sequence、Find、Random Selector、Selector、Repeater
Unity行为树插件《BehaviorDesigner》
优点:
耦合度低,扩展性强