| |
|
开发:
C++知识库
Java知识库
JavaScript
Python
PHP知识库
人工智能
区块链
大数据
移动开发
嵌入式
开发工具
数据结构与算法
开发测试
游戏开发
网络协议
系统运维
教程: HTML教程 CSS教程 JavaScript教程 Go语言教程 JQuery教程 VUE教程 VUE3教程 Bootstrap教程 SQL数据库教程 C语言教程 C++教程 Java教程 Python教程 Python3教程 C#教程 数码: 电脑 笔记本 显卡 显示器 固态硬盘 硬盘 耳机 手机 iphone vivo oppo 小米 华为 单反 装机 图拉丁 |
-> 游戏开发 -> Unity游戏开发客户端面经——Unity(初级) -> 正文阅读 |
|
[游戏开发]Unity游戏开发客户端面经——Unity(初级) |
前言:记录了总6w字的面经知识点,文章中的知识点若想深入了解,可以点击链接学习。由于文本太多,按类型分开。这一篇是 Unity 常问问题总结,有帮助的可以收藏。? 1. 生命周期????????Awake?—>?OnEnable —>?Start?—>?FixedUpdate?—>Update??—>?LateUpdate—>?OnGUl?—>?OnDisable?—>?OnDestroy 详细介绍????????1. Awake ????????Awake用于在游戏开始之前初始化变量或游戏状态。在脚本整个生命周期内它仅被调用一次,Awake在所有对象被初始化之后调用, ????????当脚本设置为不可用时,运行时Awake方法仍然会执行一次。 ????????所以你可以安全的与其他对象对话或用诸如GameObject.FindWithTag 这样的函数搜索它们。每个游戏物体上的Awake以随机的顺序被调用。因此,你应该用Awake来设置脚本间的引用,并用Start来传递信息,Awake总是在Start之前被调用。它不能用来执行协同程序。 ????????2.?OnEnable ????????当对象变为可用或激活状态时被调用事件监听。 ????????3.?Start ????????Start在behaviour的生命周期中只被调用一次。它和Awake的不同是Start只在脚本实例被启用时调用。你可以按需调整延迟初始化代码。Start总是在Awake之后执行。这允许你协调初始化顺序。 ????????4. Update ????????Update每帧调用一次用于更新游戏场景和状态,比较适合做控制。 ????????5.?FixedUpdate ????????每隔固定物理时间间隔调用一次用于物理状态的更新,和Update不同的是FixedUpdate逻辑帧,Update是渲染帧。如果帧率很低,可以每帧调用该函数多次;如果帧率很高,可能在帧之间完全不调用该函数。 ????????FixedUpdate?内应用运动计算时,无需将值乘以?Time.deltaTime。这是因为?FixedUpdate?的调用基于可靠的计时器(独立于帧率)。 ????????6. LateUpdate ????????每帧调用一次(在 update 之后调用) 用于更新游戏场景和状态,和摄像机相关的更新。 ????????官网上例子是摄像机的跟随,都是所有的Update操作完才进行摄像机的跟进,不然就有可能出现摄像机已经推进了,但是视角里还未有角色的空帧出现。 ????????7.?OnGUI ????????OnGUI 渲染和处理 OnGUI 事件。 ????????8.?OnDisable ????????OnDisable 当对象变为不可用或非激活状态时被调用事件移除。 ????????9.?OnDestroy ????????OnDestroy 当对象被销毁时调用。 2. 如何让已经存在的GameObject在LoadLevel后不被卸载掉????????DontDestroyOnLoad(transform.gameObject); 3. 碰撞? ? ?物体发生碰撞的必要条件????????两个物体都必须带有碰撞器Collider,其中一个物体还必须带有Rigidbody刚体。 ? ? ?碰撞器与触发器????????1.碰撞器是触发器的载体,而触发器只是碰撞器身上的一个属性。 ????????2. 当ls Trigger=false时,碰撞器根据物理引擎引发碰撞,产生碰撞的效果,可以调用OnCollisionEnter/Stay/Exit函数; ????????3.当ls Trigger=true时,碰撞器被物理引擎所忽略,没有碰撞效果,可以调用OnTriggerEnter/Stay/lExit函数。 ????????4. 如果既要检测到物体的接触,又不想让碰撞检测影响物体移动或要检测一个物件是否经过空间中的某个区域,这时就可以用到触发器。 4. 协程(进程/线程)?????1. 概念 ? ? 进程 ????????保存在硬盘上的程序运行以后,会在内存空间里形成一个独立的内存体,这个内存体有自己独立的地址空间,有自己的堆,不同进程间可以进行进程间通信,上级挂靠单位是操作系统。一个应用程序相当于一个进程,操作系统会以进程为单位,分配系统资源(CPU 时间片、内存等资源),进程是资源分配的最小单位。 ? ? 线程 ????????线程从属于进程,也被称为轻量级进程,是程序的实际执行者。线程是操作系统能够进行运算调度的最小单位。它被包含在进程之中,是进程中的实际运作单位。一条线程指的是进程中一个单一顺序的控制流,一个进程中可以并发多个线程,每条线程并行执行不同的任务。一个线程只有一个进程。 ????????每个独立的线程有一个程序运行的入口、顺序执行序列和程序的出口,但是线程不能够独立执行,必须依存在应用程序中,由应用程序提供多个线程执行控制。 ????????线程拥有自己独立的栈和共享的堆,共享堆,不共享栈,线程亦由操作系统调度(标准线程是的)。 ? ? 协程 ????????协程是伴随着主线程一起运行的一段程序。 ? ? 注意点: ????????协程与协程之间是并行执行,与主线程也是并行执行,同一时间只能执行一个协程提起协程,自然是要想到线程,因为协程的定义就是伴随主线程来运行的! ????????一个线程可以拥有多个协程,协程不是被操作系统内核所管理,而完全是由程序所控制。 ????????协程和线程一样共享堆,不共享栈,协程由程序员在协程的代码里显示调度。 ????????协成是单线程下由应用程序级别实现的并发。 ????????2.线程与协程的区别 ????????协同程序与多线程情况下的线程比较类似:有自己的堆栈,自己的局部变量,有自己的指令指针,但与其它协同程序共享全局变量等很多信息。 ????????协程(协同程序): 同一时间只能执行某个协程。开辟多个协程开销不大。协程适合对某任务进行分时处理。 ????????线程: 同一时间可以同时执行多个线程。开辟多条线程开销很大。线程适合多任务同时处理。
????????线程和协同程序的主要不同在于:在多处理器情况下,从概念上来讲多线程程序同时运行多个线程;而协同程序是通过协作来完成,在任一指定时刻只有一个协同程序在运行,并且这个正在运行的协同程序只在必要时才会被挂起。 ?????2. 协程作用 ????????在Unity中只有主线程才能访问Unity3D的对象、方法、组件。当主线程在执行一个对资源消耗很大的操作时,在这一帧我们的程序就会出现帧率下降,画面卡顿的现象! ????????那这个时候我们就可以利用协程来做这件事,因为协程是伴随着主线程运行的,主线程依旧可以丝滑轻松的工作,把脏活累活交给协程处理就好了!简单来说:协程是辅助主线程的操作,避免游戏卡顿。 ????????3.?操作 ????????3.1定义协程
????????3.2 启动协程 ????????1. Startcoroutine (string methodName):通过协程的方法名(字符串形式)启动。 ????????2. StartCoroutine (string methodName,object values):带参数的通过方法名(字符串形式)进行调用。 ????????3. Startcoroutine (IEnumerator routine):通过调用方法的形式启动。 ????? ?3.3 停止携程
????????4. 底层原理 ????????协程是通过迭代器来实现功能的,通过关键字IEnumerator来定义一个迭代方法。 ????????注意:提起IEnumerator就会想到IEnumerable,可千万不能搞混了! ????????StartCoroutine 接受到的是一个 IEnumerator ,这是个接口,并且是枚举器或迭代器的意思。 ????????yield 是 C#的一个关键字,也是一个语法糖,背后的原理会生成一个类,并且也是一个枚举器,而且不同于 return,yield 可以出现多次。 ????????yield 实际上就是返回一次结果,因为我们要一次一次枚举一个值出来,所以多个 yield 其实是个状态模式,第一个 yield 是状态 1,第二个 yield 是状态 2,每次访问时会基于状态知道当前应该执行哪一个 yield,取得哪一个值。 ????????从程序的角度讲,协程的核心就是迭代器。想要定义一个协程方法有两个因素,第一:方法的返回值为 IEnumerator 。第二,方法中有 yield关键字。当代码满足以上两个条件时,此方法的执行就具有了迭代器的特质,其核心就是 MoveNext方法。方法内的内容将会被分成两部分:yield 之前的代码和 yield 之后的代码。yield之前的代码会在第一次执行MoveNext时执行, yield之后的代码会在第二次执行MoveNext方法时执行。而在Unity中,MoveNext的执行时机是以帧为单位的,无论你是设置了延迟时间,还是通过按钮调用MoveNext,亦或是根本没有设置执行条件,Unity都会在每一帧的生命周期中判断当前帧是否满足当前协程所定义的条件,一旦满足,当前帧就会抽出CPU时间执行你所定义的协程迭代器的MoveNext。注意,只要方法中有yield语句,那么方法的返回值就必须是 IEnumerator ,不然无法通过编译。 ????????详细请看: ????????测试:
5. Invoke与InvokeRepeating????1. Invoke????????Invoke() 方法是?Unity3D?的一种委托机制 ????????如: Invoke("Test", 5); ? 它的意思是:5 秒之后调用 Test() 方法;
????2. InvokeRepeating????????InvokeRepeating("Test", 2 , 3);? ????????这个方法的意思是指:2 秒后调用 Test() 方法,并且之后每隔 3 秒调用一次 Test() 方法。 ????????被激活时设置了,但是此时将引擎对象设置为false,还会被执行。
????3. Invoke与协程的区别????????Invoke方法:执行没有被挂起,相当于设置完被调用函数的执行时间后即时向下执行。应用到每隔一段时间执行某个函数很方便。 ????????Coroutine方法:新开一条执行序列(跟新建线程差不多)并挂起,等待中断指令结束。开销不大。当需要挂起当前执行时使用。 ????????协程的效率比Invoke高。 ????4. ?正在运行的脚本,隐藏物体与禁止脚本导致OnDisable,Invoke与coroutine是否正常运行?代码: ????????脚本禁止:都会正常运行。 ? ????????如果把物体直接隐藏:Invoke正常运行,coroutine不会正常运行。 ????????原因: ????????因为游戏物体隐藏了,一切与游戏物体相关的脚本生命周期都会停止,协程自然也会停止?;???????? ????????如果游戏对象没有隐藏,只是将脚本隐藏,游戏对象照样可以通过反射获取协程迭代器对象继续协程的执行。 6. 对象移动方式?????1.Transform ????????通过 Update 函数每帧更新其位置来达到移动目的。 ?????????1.1 Transform.position ????????向量相加 ????????最基础的移动方式,每帧+=计算好的新位置,更加直观。??
?????????1.2 Transform.Translate ????????在平移的方向和距离上移动变换。 ????????每秒向某方向移动多少距离,此种方法和上一种没有太大区别,但当需要坐标转换时,使用此方法可省略转换步骤。 translate(V3 向量,坐标系(留空默认为 Space.Self));
? ?????2. Vector3 ????????Vector3 类型可以存储物体的位置、方向。 V3 自带的类方法通过对位置的一些运算得到相对平滑的参数,其移动本质还是修改物体的 position。 ????????2.1?Vector3.Lerp ????????两个向量之间的线性差值,适用于从某点移动到某点(或跟随某物体),缓动效果。非匀速。 Lerp(当前位置(V3),目标位置(V3),时间(float)) 时间越小,缓动效果越慢。
????????2.2 Vector3.Slerp ????????两个向量之间的球形(弧线)差值,适用于从某点移动到某点(或跟随某物体),缓动效果,当前位置与目标位置距离越远,效果越明显。非匀速。 Slerp(当前位置(V3),目标位置(V3),时间(float)) 时间越小,缓动效果越慢
????????2.3?Vector3.MoveTowards ????????和 Lerp 函数基本相同,但此函数多了一个最大速度限制,且是匀速朝目标运动,而 Lerp 和 Slerp 则是将抵达位置时放缓(减速)
????????2.4 Vector3.SmoothDamp ????????官方翻译为:“平滑阻尼”,无比丝滑的从 A 移动到 B 点,速度可控,比较适用于摄像机跟随,Lerp 也比较适用于摄像机跟随,这俩的区别在于 SmoothDamp(当前位置(V3),目标位置(V3),当前速度(ref:V3),所需时间(float),最大速度(float,可选),Time.deltaTime(默认)(可选)) ????????当前速度:一开始赋值为 0,每次调用该方法自动修改此参数,注意设为全局变量,且为 ref ????????所需时间:该值越小,越快抵达目标。
3. Rigidbody????????Rigidbody 组件通过物理模拟来控制一个物体的位置,当使用此组件控制物体移动时,应在 FixedUpdate 函数中更新数据,该方法会在每一次执行物理模拟前被调用,这样要比 Update 函数更加精确。 ????????3.1 AddForce ????????添加一个方向的力到刚体,刚体将开始移动,这种方式适合模拟外力作用下的刚体运动,如子弹。但注意,此力是累加的,不适合重复施加力来模拟物体! AddForce(有方向的力(V3),力的模式(ForceMode,默认:ForceMode.Force))
按秒移动,向刚体添加一个力,这里效果表示加一个力来对抗阻力?:mRigidbody.AddForce(transform.forward * mMoveSpeed); 让addforce后的物体立即停下:velocity.zero = 0; ????????3.2?MovePosition ????????移动刚体到一个新的位置,移动的同时受到物理模拟的影响。 MovePosition(新的位置(V3)),有重力影响。
????????将运动学刚体移动到某个位置
???????? ????????3.3 Velocity ????????瞬间给一个物体恒定的速度,将该物体提升到这个速度,保持。相比较 AddForce 更加适合跳跃功能。每次跳跃都是恒定高度。做跳跃的话:????
按秒移动,刚体的速度矢量。它表示刚体位置的变化率。
4.??Character?Controller????????角色控制器顾名思义,是 Unity 推出的特别用于角色移动的组件,使用角色控制器的物体有刚体的效果,但不会翻滚(意思是运动仅受限于碰撞体,不受其他因素影响),很适合角色移动。还可以设置斜坡参数,一定坡度自动抬升,本身也是个碰撞体。 ????????4.1 ?SimpleMove ????????以一定速度移动角色,以秒为单位,无需乘以时间,具备重力。 SimpleMove(有方向的力(V3))
????????4.2 ?Move ????????以一定速度移动角色,不具备重力,需要自行计算下落 Move(有方向的力(V3))
????????按帧移动,用附加的CharacterController组件来提供游戏对象的移动。因为这里移动不受重力影响,所以加一个向下的移动来模拟重力。
????????详细请看: 7. 获取对象方式????????7.1用Find查询????????GameObject.Find()通过对象名称(Find方法) ????????Transform.Find()通过对象名称(Find方法) ????????例子:
? ????????7.2用标签 Tag????????GameObject.FindWithTag 通过标签获取单个游戏对象(FindWithTag方法)。 ????????GameObject.FindGameObjectWithTag()通过标签获取单个游戏对象(FindGameObjectWithTag方法)。 ????????例子:
? ????????7.3用Type????????GameObject.FindObjectOfType()通过类型获取单个游戏对象(FindObjectOfType方法) ????????GameObject.FindObjectsOfType()通过类型获取多个游戏对象(FindObjectsOfType方法)7. transform.GetChild()通过索引获取单个游戏对象 ????????例子:
????????详细请看: 8. Ugui/Ngui渲染顺序
9. 寻路????????NavMesh是一种基于多边形网络的寻路导航系统,整个寻路分为导航网格的构建和寻路算法两个部分。 ????????9.1如何用 NavMesh 动态寻路
????????Navigation导航系统基础? ????????9.2 游戏中的寻路算法10. 画布的三种模式/缩放模式?????10.1屏幕空间-覆盖模式(Screen Space-Overlay)????????Canvas创建出来后,默认就是该模式,该模式和摄像机无关,即使场景内没有摄像机,UI游戏物体照样渲染。 ????????屏幕空间:电脑或者手机显示屏的2D空间,只有x轴和y轴。 ????????覆盖模式:UI元素永远在3D元素的前面。 ?????10.2屏幕空间-摄像机模式(Screen Space-Camera)????????设置成该模式后需要指定一个摄像机游戏物体,指定后UGUIl就会自动出现在该摄像机的"投射范围"内,和NGUI的默认Ul Root效果一致,如果隐藏掉摄像机,UGUI当然就无法渲染。 ????????这种模式可以用来实现在UI上显示3D模型的需求,比如很多MMO游戏中的查看人物装备的界面,可能屏幕的左侧有一个运动的3D人物,左侧是一些UI元素。通过设置Screen Space-Camera模式就可以实现上述的需求。 ?????10.3 世界空间模式(WorldSpace)????????设置成该模式后UGUIl就相当于是场景内的一个普通的“Cube游戏模型”,可以在场景内任意的移动UGUI元素的位置,通常用于怪物血条显示和VR开发。 ????????10.4缩放模式
????????Constant Pixel Size、Constant Physical Size实际上他们本质是一样的,只不过Constant Pixel Size通过逻辑像素大小调节来维持缩放,而Constant Physical Size 通过物理大小调节来维持缩放。 11. 游戏动画????????11.1 关节动画????????把角色分成若干独立部分,一个部分对应一个网格模型,部分的动画连接成一个整体的动画,角色比较灵活,Quake2中使用这种动画; ????????11.2骨骼动画????????广泛应用的动画方式,集成了以上两个方式的优点,骨骼按角色特点组成一定的层次结构,有关节相连,可做相对运动,皮肤作为单—网格蒙在骨骼之外,决定角色的外观; ????????11.3 单—网格模型动画(关键帧动画)????????由一个完整的网格模型构成,在动画序列的关键帧里记录各个顶点的原位置及其改变量,然后插值运算实现动画效果,角色动画较真实。 12. 不同分辨率保持UI一致性????????多分率下的适配问题主要从两个方向解决 ????????1.解决多分辨率下UI的相对位置保持不变,就是改变锚点位置就可以解决。 ????????2.解决多分辨率下UI的大小尺寸保持不变,也就是适配尺寸。Unity中Canvas的大小不能直接修改,需要用Canvas下面的一个组件CanvasScaler来进行修改。 ????????CanvasScaler中UI?Scale?Mode有三种模式,Constant?Pixel?Size、Scale?With?Screen?Size、Constant?Physical?Size,其中第二个就是根据屏幕分辨率来进行缩放适配。在这个模式下,有两个参数,一个是我们在开发过程中的标准分辨率,一个是屏幕的匹配模式,通过这里面的设置,就可以完成多分辨率下的适配问题。 ????????Unity3D手游保持不同分辨率的UI自适应: 13. Unity光源????????平行光: Directional Light ????????点光源: Point Light ????????聚光灯: Spot Light ????????区域光源: Area Light 14.射线????????14.1射线检测的原理????????射线是3D世界中一个点向一个方向发射的一条无终点的线,在发射轨迹中与其他物体发生碰撞时,它将停止发射。 ????????14.2射线Raycast原理????????从一个起点向一个方向发射—条物理射线,返回碰撞到的物体的碰撞信息。 15. Mono??????15.1 Net与Mono的关系????????Net是一个语言平台,Mono为.Net提供集成开发环境,集成并实现了.NET的编译器、CLR和基础类库,使得.Net暖既可以运行在windows也可以运行于linux,Unix,Mac OS等。 ??????15.2 Mono 和 Unity 的区别????????Unity 因为方便和跨平台选择了 C#作为主要的开发语言。而且 C#的跨平台是基于.Net Framework 框架下的(CIL,通用描述语言)和 CLR(通用运行环境的)。 在经过各种考量后,Unity 选择了开源,并且平台支持性很好的 Mono 这一开源 的.Net Framework 跨平台实现方案。 16. Image和Rawlmage的区别????????1.lmgae比Rawlmage更消耗性能。 ????????2.lmage只能使用Sprite属性的图片,但是Rawlmage什么样的都可以使用。 ????????3.mage适合放一些有操作的图片,裁剪平铺旋转什么的,针对Image Type属性。RawImage就放单独展示的图片就可以,性能会比Image好很多。 17. Unity中常用的函数????17.1鼠标
????????2. 实际使用:使用时一般都是成对使用 ????????OnMouseEnter,OnMouseOver,OnMouseExit 一组。比如模拟选中状态:鼠标进入时物体变色,鼠标退出时再变回来。 ????????OnMouseDown,OnMouseDrag,OnMouseUp 一组。比如射击游戏:鼠标按下拖拽时调整方向,抬起时发射子弹。 ????????当鼠标按下并停留在当前游戏对象上时,OnMouseOver,OnMouseDrag会同时触发。
????????总结为一局话就是:OnMouseXXX的原理是通过鼠标的射线检测来判断鼠标当前位置是否碰到了挂载脚本游戏对象的碰撞体。 ????17.2 碰撞与触发
????????PS:上面这六个方法,还有对应2D碰撞体的六个方法(如:OnCollisionEnter2D) 函数后面添加2D接口,触发条件和使用方式和3D一致。 使用时注意碰撞体和检测函数同步接口,即用2D碰撞体必须用2D函数。
????17.3 应用程序
????17.4 禁用销毁
????????详细请看: 18. 点击UI层后面的Button????????当我们需要点击一个button,而button与摄像机之间还有一个UI层,例如Plane,这时候点击就会失效,解决方法:
19. Mask????Mask的实现原理:
20. Unity的GC? ? 1. 贝姆垃圾收集器 ????????Untiy使用的GC机制是通过贝姆垃圾收集器(Boehm GC)来实现的,是应用在C/C++语言上的一个保守的垃圾回收器,同时也适用于其它执行环境的各类编程语言,比如我们使用的基于mono实现的C#。 ? ? 2.?回收机制 ????????Unity的GC的是采用?贝姆垃圾收集器?,本质上采用的是非分代非压缩的标记清除算法。 ????????它会在需要进行GC时占用主线程,进行遍历-标记-垃圾回收的过程,然后在归还主线程控制权。这会导致帧数的突然下降,产生卡顿(不过因为该实现是非压缩式的,所以卡顿现象相对较轻,但是对内存利用率进一步下降了,会有内存碎片的问题)。 ????????所以我们需要慎重地处理对象的创建(内存请求),还有释放(使用GC管理内存是没有主动释放内存的接口的,但是我们可以通过消除对某个对象的引用来做到这一点)。此外,Unity的代码分为两部分:托管与非托管,GC影响的只有托管部分的代码使用的堆内存。而且这个托管堆占用的地址空间不会返还给操作系统。 ????????标记清楚算法可以解决两个变量相互引用,产生标记的现象。 ? ? 3. 托管堆的垃圾回收机制????????Unity使用的垃圾机制是Boehm GC算法,他是非分代,非压缩的。非分代意味着每次回收都需要扫描整个堆,而非压缩则意味着内存分配后整个托管堆会存在间隙或者说内存碎片。这两个特点意味着Unity中托管堆的垃圾回收机制会耗时较长而且内存利用率存在着问题。 ? ? 4. 整个垃圾回收的流程????????1. 停止所有进行托管堆内存分配的线程。? ? ? ?? ????????2. 找到所有不再被需要的内存,将其标记为垃圾。 ????????3. 将所有被标记的内存释放到空闲内存。 ????????4. 恢复之前停止的托管堆内存分配的线程。 ? ? 5. GC优化????????GC对性能影响的原因(占用主线程进行大量工作),而优化GC即是减小占用GC占用主线程时花费的CPU时间,所以优化GC优化的是CPU时间,而非内存。 21. Animation和Animator的区别????????Animation和Animator 虽然都是控制动画的播放,但是它们的用法和相关语法都是大有不同的。Animation控制一个动画的播放,而Animator是多个动画之间相互切换,并且Animator有一个动画控制器,俗称动画状态机。 ????????Animator利用它做动画的切换是很方便的,但是它有一个缺点就是占用内存比Animation大。 22. Unity常用API????????详细请看: 23. Time.Deltatime????????表示从上一帧到当前帧时间,以秒为单位。(两帧之间调用的间隔。) ? ? ?作用 ????????解决在不同cpu频率下的设备,玩家移动,旋转等相关操作(和渲染帧有关的操作)可以保证在单位时间内移动的量是相等的。 ????????详细请看: 24. 动态加载资源的方式??????Assetsbundle ????????即将资源打成asset bundle放在服务器或本地磁盘,然后使用WWW模块get 下来,然后从这个bundle中load某个object,unity官方推荐也是绝大多数商业化项目使用的一种方式。 ??????Resource.Load ????????可以直接load并返回某个类型的Object,前提是要把这个资源放在Resource命名的文件夹下,Unity不管有没有场景引用,都会将其全部打入到安装包中 ??? ? AssetDatabase.loadasset ????????这种方式只在editor范围内有效,游戏运行时没有这个函数,它通常是在开发中调试用的。 25. unity中的UI层为什么要分为动态和静态????????动态分离出来也是为了减少绘制次数,动态的话?Canves会重新绘制,不分开就会重新绘制一遍静态和动态,增加DC。 26. Text?和?TMPtext的区别?优缺点????????Text是像素渲染放大之后就会模糊,使用Text父物体的放大缩小会影响子物体Text的清晰度,?TMPtext不会,它是网格渲染TMPtext会把字体生成一个类似于贴图的东西然后读取贴图的坐标来获取对应的文字,更换文字的消耗会比Text大,TMPtext适用于那种不会变动的文字,特别是在量大的情况下,性能比Text高一些,需要经常变动的问题用Text好点,TMPtext在字体库很大的情况下查找更换会比较慢。 27. 红点系统的实现????????思路: ????????红点系统基于MVC的思想,将分为三层:数据层,驱动层,显示层。 ????????1.数据层中的数据结构,考虑到需要层级的联系,所以以结点为核心,每个结点会持有其父结点和子结点,有点像双向链表的前驱后继,但是它构成的不是链表而是树。 ????????2.当一个结点状态发生变化,它会通知到其父结点,父节点会自行处理变化去通知它自己的父结点,有点递归的意思,如果是数量通知,子节点的消息会以此累计到自己的父节点中,以此类推,具体看需求。 ????????3.整个系统数据层驱动层与展示层是剥离的,展示层需要显示什么结点的内容,以该结点的key去注册,数据层与显示层实现了观察者模式,即可收到每次该结点状态变化的通知,并实时更新界面。 ????????详细请看: 28. 行为树与有限状态机????????有限状态机系统:是指在不同阶段会呈现出不同的运行状态的系统,这些状态是有限的、不重叠的。这样的系统在某一时刻一定会处于其所有状态中的一个状态,此时它接收一部分允许的输入,产生一部分可能的响应,并且迁移到一部分可能的状态。 ????????1). 基本节点是状态:他包含了一系列运行在该状态的行为以及离开这个状态的条件。 ????????2). 状态可以任意跳转,实现简单,但是对于大的状态机很难维护,状态逻辑的重用性低。 ????????3). 每一个状态的逻辑会随着一些新状态的增加而越来越复杂。维持状态的数量和状态逻辑复杂性是一个很大的难点。需要合理的分割以及重用状态。 ????????4). 状态机状态的复用性很差,一旦一些因素变化导致这个环境发生变化。你只能新增一个状态,并且给这个新状态添加连接他以及其他状态的跳转逻辑。 ????????5). 状态机的跳转条件一旦不满足,就会一直卡在某一个状态。 ????????行为树:一个流行的AI技术,涵盖了层次状态机,事件调度,事件计划,行为等一系列技术。实现AI的过程更加得有技巧,框架设计者较为全面考虑了我们可能会遇到的种种情况,把每种情况都抽象成了一个类型的节点,而我们要做的就是按照规范去写节点,然后把节点连接成一颗行为树。更加得具有面向对象的味道,行为模块间的藕合度相对较低。 ????????1). 高度模块化状态,去掉状态中的跳转逻辑,使得状态变成一个“行为”。 ????????2). "行为"和"行为"之间的跳转是通过父节点的类型来决定的。比如并行处理两个行为,在状态机里面无法同时处理两个状态。 ????????3). 通过增加控制节点的类型,可以达到复用行为的目的。 ????????4). 可视化编辑。 ???罗列一下行为树的概念:
优点: 1. 行为逻辑和状态数据分离,任何节点写好以后可以反复利用。 2. 重用性高,可用通过重组不同的节点来实现不同的行为树。 3. 呈线性的方式扩展,易于扩展。 4. 可配置,把工作交给designer。 5. 能够胜任"AI" “掉宝”等等场景。 缺点: 1. 每一帧都从root开始,有可能会访问到所以的节点,相对State Machine消耗更多的cpu。 2. 任何一个简单的操作都必须要使用节点。 ?????扩展:各种节点的详细描述: ? ? ?Selector Node 选择节点 ????????描述:从头到尾,按顺序选择第一个执行条件为真的子节点,遇到True停止。 ????????处理流程:当执行本类型Node时,它将从begin到end迭代执行自己的Child Node:如遇到一个Child Node执行后返回True,那停止迭代,本Node向自己的Parent Node也返回True;否则所有Child Node都返回False,那本Node向自己的Parent Node返回False。 ????Sequence Node 序列节点 ????????描述:从头到尾,按顺序执行每一个子节点,遇到False停止。 ????????处理流程:当执行本类型Node时,它将从begin到end迭代执行自己的Child Node:如遇到一个Child Node执行后返回False,那停止迭代,本Node向自己的Parent Node也返回False;否则所有Child Node都返回True,那本Node向自己的Parent Node返回True。 ????Parallel Node 并行节点 ????????描述:从头到尾,平行执行它的所有子节点。 ????????详细请看: 29. 动画缝合????????利用动画层级Animatoion中的Layer,设置替身模板Avatar Mask 中可以播放或者禁止的人物节点,这样该层动画只会影响人物节点的一部分。然后设置权重和设置对应的Mask来对不同的动画层覆盖操作。达到混合的效果。 30. 散弹角度实现机制????????以枪口方向为轴,上下或者左右为展开方向。获取夹角。利用点乘的方法。 ? ? ? ? 1. 通过Vector3.Dot(向量A,向量B)获取两个向量的点乘C。 ? ? ? ? 2. 然后通过Acos C 然后由弧度转换为角度即可。 ? ? ? ? 3. 弧度乘以Mathf.Rad2Deg得到角度; 31. 一个物体先朝向x轴旋转再朝向y轴旋转 与 一个物体先朝向y轴旋转再朝向x轴旋转,结果一样吗?为什么?????????结果不一样。因为transform本质是一个矩阵。矩阵乘法不支持交换律。 32. Unity和Android与iOS如何交互?????????UnitySendMessage(“Cube111”,"methodName111","传给unity。。。");
33. Unity的值类型与引用类型????????值(value)类型 :Unity中的vector3、quaternion是structs,它们是值。 ????????引用(feference)类型 :Unity中的transform、gameobject是类类型,所以它们是引用。引用类型是对数据存储位置的引用,引用类型指向的内存区域称为堆。 ????????在决定定义引用类型还是值类型时,关键因素是:如果逻辑上是固定大小不可变的值,就考虑定义成值类型,如果逻辑上是可引用的可变的对象,就定义成引用类型。例如字符串类型,它的大小是根据值的大小而改变的,所以它是引用类型。 ???????? ????????引用类型在堆上,值类型在栈上? ? ? ? ? 1. 引用类型的实例总是在堆上的没有错,但是方法内部声明的变量和方法参数在栈上。 而且实例变量的值总是存储在实例本身存储的地方。例如如一个类中有个int变量,虽然它是一个值类型,但它在堆上。
???????? ????????但是值类型也有值类型的好处,值类型的效率更高,而当我们需要从其它作用域修改一个值类型的数据时,我们需要显式传引用;也正因如此,很多数学类都使用结构体类型而非类类型,例如unity中的vector,quaternion等; ????????在C#中,结构体也有自己的构造函数、常量和方法等,尽管有些许语法区别,但是一个结构体也可以被视为一个轻量级的类;???????? ???????? ????????详细请看: 34. ScriptableObejct????????ScriptableObject是一个数据容器,它可以用来保存大量数据。 ????????主要的用处就是在项目中通过将数据存储在ScriptableObject对象,避免值拷贝来减少游戏运行中的内存占用。 ????????当你有一个预制体,上面挂了一个存有不变数据的MonoBehaviour 脚本时,每次我们实例化预制体时都将产生一次数据拷贝,这时我们可以使用ScriptableObject对象来存储数据,然后通过引用来访问预制体中的数据。这样可以避免在内存中产生一份拷贝数据。与MonoBehaviour 一样,ScriptableObject也继承自Unity基类object,但是与MonoBehaviour不同的是,ScriptableObject不能和GameObject对相关联,相反,通常我们会将它保存为Assets资源。 ????????在编辑器模式下,我们可以在编辑和运行时将数据保存到ScriptableObject,因为保存ScriptableObject需要用到编辑器空间个脚本,但是在开发模式下不能使用ScriptableObject来保存数据,但是你可以使用ScriptableObject资源中已保存的数据。 ????????详细请看: ScriptableObject - 镜子-眼泪 - 博客园ScriptableObject简单实现详解https://www.cnblogs.com/jzyl/p/14934661.html |
|
|
上一篇文章 下一篇文章 查看所有文章 |
|
开发:
C++知识库
Java知识库
JavaScript
Python
PHP知识库
人工智能
区块链
大数据
移动开发
嵌入式
开发工具
数据结构与算法
开发测试
游戏开发
网络协议
系统运维
教程: HTML教程 CSS教程 JavaScript教程 Go语言教程 JQuery教程 VUE教程 VUE3教程 Bootstrap教程 SQL数据库教程 C语言教程 C++教程 Java教程 Python教程 Python3教程 C#教程 数码: 电脑 笔记本 显卡 显示器 固态硬盘 硬盘 耳机 手机 iphone vivo oppo 小米 华为 单反 装机 图拉丁 |
360图书馆 购物 三丰科技 阅读网 日历 万年历 2024年11日历 | -2024/11/22 19:23:43- |
|
网站联系: qq:121756557 email:121756557@qq.com IT数码 |