SEO基础

SEO基础

Products

当前位置:首页 > SEO基础 >

如何为北京手机专业网站增加WordPress导航以提高用户体验?

96SEO 2026-02-19 10:36 6


如何为北京手机专业网站增加WordPress导航以提高用户体验?

2.Unity3D中的碰撞器和触发器的区别#xff1f;3.物体发生碰撞的必要条件#xff1f;4.简述Unity3D支持的作为脚本的语言的名称#xff1f;5.

一般用来放些什么打包的时候会有什么影响107.怎么判断两个平面是否相交?不能用碰撞体,说出计算方法108.MeshCollider和其他Collider的⼀个主要不同109.当⼀个细⼩的⾼速物体撞向另⼀个较⼤的物体时会出现什么情况如何110.在Unity中如何是西安相机跟随角色111.在Unity中如何加载异步资源112.在Unity中如何实现角色动画113.在Unity中如何加载并播放音频114.如何在Unity中实现粒子效果?115.在Unity中如何实现游戏的平台差异化处理116.在Unity中如何实现游戏对象之间的通信117.如何在Unity中实现多人联网游戏118.为何大家都在移动设备上寻求U3D原生GUI的替代方案119.举例Unity的四个特殊文件夹分别是干什么用的120.Unity调整旋转121.本地坐标系

世界坐标系

1.Unity3d脚本从唤醒到销毁有着一套比较完整的生命周期列出系统自带的几个重要的方法。

Awake

编辑器-初始化-物理系统-输入事件-游戏逻辑-场景渲染-GUI渲染-物体激活或禁用-销毁物体-应用结束主要函数介绍

Reset

是在用户点击检视面板的Reset按钮或者首次添加该组件时被调用。

此函数只在编辑模式下被调用。

Reset最常用于在检视面板中给定一个最常用的默认值。

Awake

用于在游戏开始之前初始化变量或游戏状态。

在脚本整个生命周期内它仅被调用一次当脚本设置为不可用时运行时Awake方法仍然会执行一次。

Awake在所有对象被初始化之后调用所以你可以安全的与其他对象对话或用诸如

这样的函数搜索它们。

每个游戏物体上的Awke以随机的顺序被调用。

因此你应该用Awake来设置脚本间的引用并用Start来传递信息

,Awake总是在Start之前被调用。

它不能用来执行协同程序。

Start

在behaviour的生命周期中只被调用一次。

它和Awake的不同是Start只在脚本实例被启用时调用。

你可以按需调整延迟初始化代码。

Awake总是在Start之前执行。

这允许你协调初始化顺序。

FixedUpdate

当MonoBehaviour启用时其在每一帧被调用。

处理Rigidbody时需要用FixedUpdate代替Update。

例如:给刚体加一个作用力时你必须应用作用力在FixedUpdate里的固定帧而不是Update中的帧。

(两者帧长不同)。

Update

官网上例子是摄像机的跟随都是所有的Update操作完才进行摄像机的跟进不然就有可能出现摄像机已经推进了但是视角里还未有角色的空帧出现。

OnGUI

渲染和处理GUI事件时调用。

这意味着你的OnGUI程序将会在每一帧被调用。

要得到更多的GUI事件的信息查阅Event手册。

如果Monobehaviour的enabled属性设为falseOnGUI()将不会被调用。

OnDisable

不能用于协同程序。

当对象变为不可用或非激活状态时此函数被调用。

OnDestroy

当用户停止运行模式时在编辑器中调用。

当web被关闭时在网络播放器中被调用。

当Is

Triggerfalse时碰撞器根据物理引擎引发碰撞产生碰撞的效果可以调用OnCollisionEnter/Stay/Exit函数当Is

Triggertrue时碰撞器被物理引擎所忽略没有碰撞效果可以调用OnTriggerEnter/Stay/Exit函数。

如果既要检测到物体的接触又不想让碰撞检测影响物体移动或要检测一个物件是否经过空间中的某个区域这时就可以用到触发器。

两个物体都必须带有碰撞器Collider其中一个物体还必须带有Rigidbody刚体。

Unity的脚本语言基于Mono的.Net平台上运行可以使用.NET库这也为XML、数据库、正则表达式等问题提供了很好的解决方案。

Unity里的脚本都会经过编译他们的运行速度也很快。

这三种语言实际上的功能和运行速度是一样的区别主要体现在语言特性上。

Unity支持的语言C#JavaScrip(不在使用)

mono是.net的一个开源跨平台工具就类似java虚拟机java本身不是跨平台语言但运行在虚拟机上就能够实现了跨平台。

.net只能在windows下运行mono可以实现跨平台编译运行可以运行于LinuxUnixMac

6.OnEnable、Awake、Start运行时的发生顺序哪些可能在同一个对象周期中反复的发生

Awake–OnEnable-StartOnEnable在同一周期中可以反复地发生!

LateUpdate是在所有的Update结束后才调用比较适合用于命令脚本的执行。

官网上例子是摄像机的跟随都是所有的Update操作完才进行摄像机的跟进不然就有可能出现摄像机已经推进了但是视角里还未有角色的空帧出现。

平行光Directional

能进⾏增量旋转避免万向锁给定⽅位的表达⽅式有两种互为负欧拉⻆有⽆数种表达⽅式

10.CharacterController和Rigidbody的区别

Rigidbody具有完全真实物理的特性而CharacterController可以说是受限的的Rigidbody具有一定的物理效果但不是完全真实的。

在游戏运行时实例化prefab相当于一个模板对你已经有的素材、脚本、参数做一个默认的配置主要用于经常会用到的物体做成一个集合方便反复使用以便于以后的修改同时prefab打包的内容简化了导出的操作便于团队的交流。

保存在硬盘上的程序运行以后会在内存空间里形成一个独立的内存体这个内存体有自己独立的地址空间有自己的堆不同进程间可以进行进程间通信上级挂靠单位是操作系统。

一个应用程序相当于一个进程操作系统会以进程为单位分配系统资源CPU

线程从属于进程也被称为轻量级进程是程序的实际执行者。

线程是操作系统能够进行运算调度的最小单位。

它被包含在进程之中是进程中的实际运作单位。

一条线程指的是进程中一个单一顺序的控制流一个进程中可以并发多个线程每条-

每个独立的线程有一个程序运行的入口、顺序执行序列和程序的出口但是线程不能够独立执行必须依存在应用程序中由应用程序提供多个线程执行控制。

线程拥有自己独立的栈和共享的堆共享堆不共享栈线程亦由操作系统调度(标准线程是的)。

协程

协程与协程之间是并行执行与主线程也是并行执行同一时间只能执行一个协程提起协程自然是要想到线程因为协程的定义就是伴随主线程来运行的。

一个线程可以拥有多个协程协程不是被操作系统内核所管理而完全是由程序所控制。

协程和线程一样共享堆不共享栈协程由程序员在协程的代码里显示调度。

在Unity中只有主线程才能访问Unity3D的对象、方法、组件。

当主线程在执行一个对资源消耗很大的操作时在这一帧我们的程序就会出现帧率下降画面卡顿的现象!

那这个时候我们就可以利用协程来做这件事因为协程是伴随着主线程运行的主线程依旧可以丝滑轻松的工作把脏活累活交给协程处理就好了简单来说协程是辅助主线程的操作避免游戏卡顿。

协程是通过迭代器来实现功能的通过关键字IEnumerator来定义一个迭代方法。

StartCoroutine

C#的一个关键字也是一个语法糖背后的原理会生成一个类并且也是一个枚举器而且不同于

returnyield

实际上就是返回一次结果因为我们要一次一次枚举一个值出来所以多个

yield

当代码满足以上两个条件时此方法的执行就具有了迭代器的特质其核心就是

yield

之后的代码。

yield之前的代码会在第一次执行MoveNext时执行

yield之后的代码会在第二次执行MoveNext方法时执行。

而在Unity中MoveNext的执行时机是以帧为单位的无论你是设置了延迟时间还是通过按钮调用MoveNext亦或是根本没有设置执行条件Unity都会在每一帧的生命周期中判断当前帧是否满足当前协程所定义的条件一旦满足当前帧就会抽出CPU时间执行你所定义的协程迭代器的MoveNext。

注意只要方法中有yield语句那么方法的返回值就必须是

IEnumerator

协程即协作式程序其思想是一系列互相依赖的协程间依次使用CPU每次只有一个协程工作而其他协程处于休眠状态。

协程实际上是在一个线程中只不过每个协程对CPU进行分时协程可以访问和使用unity的所有方法和component。

同一时间只能执行某个协程。

开辟多个协程开销不大。

协程适合对某任务进行分时处理。

线程多线程是阻塞式的每个IO都必须开启一个新的线程但是对于多CPU的系统应该使用thread尤其是有大量数据运算的时刻但是IO密集型就不适合而且thread中不能操作unity的很多方法和component。

同一时间可以同时执行多个线程。

开辟多条线程开销很大。

线程适合多任务同时处理。

线程和协同程序的主要不同在于在多处理器情况下从概念上来讲多线程程序同时运行多个线程而协同程序是通过协作来完成在任一指定时刻只有一个协同程序在运行并且这个正在运行的协同程序只在必要时才会被挂起。

Invoke

脚本的生命周期里的Start、Update、OnGUI、FixedUpdate、LateUpdate中被调用Invoke();

Time.ScaleTime

Invoke方法执行没有被挂起相当于设置完被调用函数的执行时间后即时向下执行。

应用到每隔一段时间执行某个函数很方便。

Coroutine方法新开一条执行序列跟新建线程差不多并挂起等待中断指令结束。

开销不大。

当需要挂起当前执行时使用。

18.正在运行的脚本隐藏物体与禁止脚本导致触发OnDisable时Invoke与coroutine是否正常运行

如果把物体直接隐藏Invoke正常运行coroutine不会正常运行。

原因因为游戏物体隐藏了一切与游戏物体相关的脚本生命周期都会停止协程自然也会停止

如果游戏对象没有隐藏只是将脚本隐藏游戏对象照样可以通过反射获取协程迭代器对象继续协程的执行。

三个阶段

20.Unity3d的物理引擎中有几种施加力的方式分别描述出来

rigidbody.AddForcerigidbody.AddForceAtPosition

21.

自身旋转transform.Rotate()绕某点旋转transform.RotateAround

22.Unity3d提供了一个用于保存和读取数据的类(PlayerPrefs)请列出保存和读取整形数据的函数

PlayerPrefs类是一个本地持久化保存与读取数据的类PlayerPrefs类支持3中数据类型的保存和读取浮点型整形和字符串型。

分别对应的函数为

SetInt();保存整型数据GetInt();读取整形数据SetFloat();保存浮点型数据

GetFlost();读取浮点型数据SetString();保存字符串型数据

GetString();读取字符串型数据

Imgae比RawImage更消耗性能Image只能使用Sprite属性的图片但是RawImage什么样的都可以使用Image适合放一些有操作的图片裁剪平铺旋转什么的针对Image

Type属性RawImage就放单独展示的图片就可以性能会比Image好很多

24.在场景中放置多个Camera并同时处于活动状态会发生什么

受Camera覆盖各场景物件均同时实时绘制主Camera视场里有多个Camera的渲染合集。

可以用depth深度Layer层

Culling

25.如何销毁一个UnityEngine.Object及其子类

使用Destroy()方法;

关节动画把角色分成若干独立部分一个部分对应一个网格模型部分的动画连接成一个整体的动画角色比较灵活Quake2中使用这种动画骨骼动画广泛应用的动画方式集成了以上两个方式的优点骨骼按角色特点组成一定的层次结构有关节相连可做相对运动皮肤作为单一网格蒙在骨骼之外决定角色的外观单一网格模型动画由一个完整的网格模型构成在动画序列的关键帧里记录各个顶点的原位置及其改变量然后插值运算实现动画效果角色动画较真实。

27.请描述为什么Unity3d中会发生在组件上出现数据丢失的情况

一般是组件上绑定的对象被删除了导致组件找不到该对象了而出现数据丢失现象。

或者对象在Editor外部被删除和移动位置。

语法不同处

抽象类中所有成员修饰符都可以使用接口中所有的成员都是对外的所以不需要修饰符修饰。

用法不同处

抽象类的子类与父类的关系是泛化关系耦合度较高而实现类和接口之间是实现的关系耦合度比泛化低。

一个类只能继承一个类但是可以实现多个接口。

将Assets和Library一起迁移导出包package用unity自带的assets

Server功能

30.Unity3D是否支持写成多线程程序如果支持的话需要注意什么

支持如果同时你要处理很多事情或者与Unity的对象互动小可以用thread,否则使用coroutine。

Unity3d没有多线程的概念不过unity也给我们提供了StartCoroutine协同程序和LoadLevelAsync异步加载关卡后台加载场景的方法。

注意仅能从主线程中访问Unity3D的组件对象和Unity3D系统调用。

C#中有lock这个关键字,以确保只有一个线程可以在特定时间内访问特定的对象

31.如何让已经存在的GameObject在LoadLevel后不被卸载掉

DontDestroyOnLoad(transform.gameObject);

Transform

几何意义得到一个与这两个向量都垂直的向量这个向量的模是以两个向量为边的平行四边形的面积点乘

几何意义可以用来表征或计算两个向量之间的夹角以及在b向量在a向量方向上的投影

叉乘得到的向量垂直于原来的两个向量标准化向量用在只关系方向不关心大小的时候

34.

使用动态字体时Unity将不会预先生成一个与所有字体的字符纹理

布局元素的位置即屏幕分辨率变化的情况下布局元素的位置可能固定不动导致布局元素可能超出边界

布局元素的尺寸即在屏幕分辨率变化的情况下布局元素的大小尺寸可能会固定不变导致布局元素之间出现重叠等功能。

为了解决这两个问题在Unity

UGUI体系中有两个组件可以来解决问题分别是布局元素的Rect

Scale

Size其中第二个就是根据屏幕分辨率来进行缩放适配。

在这个模式下有两个参数一个是我们在开发过程中的标准分辨率一个是屏幕的匹配模式通过这里面的设置就可以完成多分辨率下的适配问题。

36.请简述OnBecameVisible及OnBecameInvisible的发生时机以及这一对回调函数的意义

当物体是否可见切换之时。

可以用于只需要在物体可见时才进行的计算。

37.

如果动态物体共用着相同的材质那么Unity会自动对这些物体进行批处理。

动态批处理操作是自动完成的并不需要你进行额外的操作。

区别动态批处理一切都是自动的不需要做任何操作而且物体是可以移动的但是限制很多。

静态批处理自由度很高限制很少缺点可能会占用更多的内存而且经过静态批处理后的所有物体都不可以再移动了。

instantiate最简单的一种方式以实例化的方式动态生成一个物体。

Assetsbundle即将资源打成

asset

下来然后从这个bundle中load某个objectunity官方推荐也是绝大多数商业化项目使用的一种方式。

Resource.Load:可以直接load并返回某个类型的Object前提是要把这个资源放在Resource命名的文件夹下Unity不管有没有场景引用都会将其全部打入到安装包中AssetDatabase.loadasset

这种方式只在editor范围内有效游戏运行时没有这个函数它通常是在开发中调试用的。

Unity3D支持C#、javascript等cocos2d-x

并且免费Unity3D支持iOS、Android、Flash、Windows、Mac、Wii等平台的游戏开发cocos2d-x支持iOS、Android、WP等。

获取GetComponent增加AddComponent删除Destroy

Near、Far两个值时应该注意什么?

简而言之GPU的图形处理流水线完成如下的工作并不一定是按照如下顺序。

顶点处理这阶段GPU读取描述3D图形外观的顶点数据并根据顶点数据确定3D图形的形状及位置关系建立起3D图形的骨架。

在支持DX8和DX9规格的GPU中这些工作由硬件实现的Vertex

Shader定点着色器完成。

光栅化计算显示器实际显示的图像是由像素组成的我们需要将上面生成的图形上的点和线通过一定的算法转换到相应的像素点。

把一个矢量图形转换为一系列像素点的过程就称为光栅化。

例如一条数学表示的斜线段最终被转化成阶梯状的连续像素点。

纹理帖图顶点单元生成的多边形只构成了3D物体的轮廓而纹理映射texture

mapping工作完成对多变形表面的帖图通俗的说就是将多边形的表面贴上相应的图片从而生成“真实”的图形。

TMUTexture

mapping

unit即是用来完成此项工作。

像素处理这阶段在对每个像素进行光栅化处理期间GPU完成对像素的计算和处理从而确定每个像素的最终属性。

在支持DX8和DX9规格的GPU中这些工作由硬件实现的Pixel

Shader像素着色器完成。

最终输出由ROP光栅化引擎最终完成像素的输出1帧渲染完毕后被送到显存帧缓冲区。

总结GPU的工作通俗的来说就是完成3D图形的生成将图形映射到相应的像素点上对每个像素进行计算确定最终颜色并完成输出。

使用本身的GUI、UGUI把摄像机的Projection(投影)值调为Orthographic(正交投影)不考虑z轴使用2d插件如2DToolKit、NGUI

44.将Camera组件的ClearFlags选项选成Depth

45.在编辑场景时将GameObject设置为Static有何作用

设置游戏对象为Static将会剔除或禁用网格对象当这些部分被静态物体挡住而不可见时。

因此在你的场景中的所有不会动的物体都应该标记为Static。

46.将图片的TextureType选项分别选为Texture和Sprite有什么区别

48.

对于AddComponent添加的脚本其AwakeStartOnEnable是在Add的当前帧被调用的

其中AwakeOnEnable与AddComponent处于同一调用链上Start会在当前帧稍晚一些的时候被调用Update则是根据Add调用时机决定何时调用如果Add是在当前帧的Update前调用那么新脚本的Update也会在当前帧被调用否则会被延迟到下一帧调用。

50.层剔除

12|18;表示开启Layer2和Layer8。

LayerMask

mask

Space-Overlay)Canvas创建出来后默认就是该模式该模式和摄像机无关即使场景内没有摄像机UI游戏物体照样渲染屏幕空间电脑或者手机显示屏的2D空间只有x轴和y轴覆盖模式UI元素永远在3D元素的前面屏幕空间-摄像机模式(Screen

Space-Camera)设置成该模式后需要指定一个摄像机游戏物体指定后UGUI就会自动出现在该摄像机的“投射范围”内和NGUI的默认UI

Root效果一致如果隐藏掉摄像机UGUI当然就无法渲染世界空间模式(WorldSpace)设置成该模式后UGUI就相当于是场景内的一个普通的“Cube

游戏模型”可以在场景内任意的移动UGUI元素的位置通常用于怪物血条显示和VR开发

Property:

因为它编程快速简单易于调试性能高与人类思维相似从而便于梳理灵活且容易修改FSM的描述性定义

一个有限状态机是一个设备或是一个模型具有有限数量的状态。

它可以在任何给定时间根据输入进行操作使得系统从一个状态转换到另一个状态或者是使一个输出或者一种行为的发生一个有限状态机在任何瞬间只能处于一种状态。

State

状态基类定义了基本的EnterUpdateExit三种状态行为通常在这三种状态行为的方法里会写一些逻辑。

每个State都会有StateID状态id可以是枚举等FSMControl控制该状态的状态控制器的引用Check方法用来进行状态判断并返回StateID通过FSMControl驱动FSMControl包含了一下FSMMachine封装层。

FSMMachine驱动它的State列表Update方法调用当前State的Check方法来获得StateID当currentState的Check方法返回的StateID和当前StateID不同则切换状态。

这是一个简单的FSM状态机系统根据需要自己写个Control继承FSMControl来驱动状态。

因为Check是State的职责所以每一个不同对象的行为如Human的Idle和Dog的Idel区分肯定也不同。

因此需要分别去写HumanIdleState和DogIdleState。

如果还有CatFish可想而知代码量会有多么庞大。

因此我将FSMControl抽象为一个公共基类把State的Check具体实现作为FSMControl的Virtual方法。

这样在IdleState里的Check方法就不用写具体的状态切换判断逻辑而是调用它FSMControl子类自己写的继承自FSMControl的Control类的重写方法

这样每次添加的新对象只要有Idle这个状态就可以用一个公用的StateIdle状态切换的逻辑差异放在Control层

53.行为树与有限状态机

有限状态机系统是指在不同阶段会呈现出不同的运行状态的系统这些状态是有限的、不重叠的。

这样的系统在某一时刻一定会处于其所有状态中的一个状态此时它接收一部分允许的输入产生一部分可能的响应并且迁移到一部分可能的状态。

基本节点是状态他包含了一系列运行在该状态的行为以及离开这个状态的条件。

状态可以任意跳转,实现简单,但是对于大的状态机很难维护状态逻辑的重用性低。

每一个状态的逻辑会随着一些新状态的增加而越来越复杂。

维持状态的数量和状态逻辑复杂性是一个很大的难点。

需要合理的分割以及重用状态。

状态机状态的复用性很差一旦一些因素变化导致这个环境发生变化。

你只能新增一个状态并且给这个新状态添加连接他以及其他状态的跳转逻辑。

状态机的跳转条件一旦不满足就会一直卡在某一个状态。

行为树一个流行的AI技术涵盖了层次状态机事件调度事件计划行为等一系列技术。

实现AI的过程更加得有技巧框架设计者较为全面考虑了我们可能会遇到的种种情况把每种情况都抽象成了一个类型的节点而我们要做的就是按照规范去写节点然后把节点连接成一颗行为树。

更加得具有面向对象的味道行为模块间的藕合度相对较低。

行为和行为之间的跳转是通过父节点的类型来决定的。

比如并行处理两个行为在状态机里面无法同时处理两个状态。

对于有限状态机而言必须明确状态的转换方式对于行为树必须明确状态前提前提条件。

每一个行为必须有“前提条件”

行为树的运算也是通过帧循环的update来驱动不一定是每帧都update但是要周期性update。

每一次run从根节点(root)开始每一运行都会选择一个可行的子节点运行这种选择可以是随机方式也可以是预设好优先条件。

行为树由叶子节点和中间节点组成叶子节点是最基本的行为(如跑动攻击)中间节点代表逻辑单元(巡逻逃跑)。

高等级的行为中间节点是否执行成功依赖于他们的孩子节点是否执行成功。

除了选择(selector)一个单独的子节点行为一个节点还可能顺序(sequence)or并行(concurrent)得运行他的所有子节点。

一个行为除了有前提条件可能还有上下文条件(父节点or孩子节点可能存储一定的状态变量)。

能够胜任AI

Text是像素渲染放大之后就会模糊使用Text父物体的放大缩小会影响子物体Text的清晰度

TMPText不会它是网格渲染TMPText会把字体生成一个类似于贴图的东西然后读取贴图的坐标来获取对应的文字更换文字的消耗会比Text大。

TMPText更适用于不会变动的文字特别是在量大的情况下性能比Text高一些需要经常变动的问题用Text好点TMPText在字体库很大的情况下查找更换会比较慢。

数据层中的数据结构考虑到需要层级的联系所以以结点为核心,每个结点会持有其父结点和子结点,有点像双向链表的前驱后继,但是它构成的不是链表而是树。

当一个结点状态发生变化,它会通知到其父结点,父节点会自行处理变化去通知它自己的父结点,有点递归的意思如果是数量通知子节点的消息会以此累计到自己的父节点中以此类推具体看需求。

整个系统数据层驱动层与展示层是剥离的,展示层需要显示什么结点的内容,以该结点的key去注册,数据层与显示层实现了观察者模式即可收到每次该结点状态变化的通知并实时更新界面。

Animation和Animator

虽然都是控制动画的播放但是它们的用法和相关语法都是大有不同的。

Animation控制一个动画的播放而Animator是多个动画之间相互切换并且Animator有一个动画控制器俗称动画状态机。

Animator利用它做动画的切换是很方便的但是它有一个缺点就是占用内存比Animation大。

根据骨骼动态整体实现表层Mesh相对普通mesh由不同面片堆砌根据骨骼结构对顶点的变换计算出不同的蒙皮最终进行模型的渲染

59.ScriptableObejct

ScriptableObject是一个数据容器它可以用来保存大量数据。

主要的用处就是在项目中通过将数据存储在ScriptableObject对象避免值拷贝来减少游戏运行中的内存占用。

当你有一个预制体上面挂了一个存有不变数据的MonoBehaviour

脚本时每次我们实例化预制体时都将产生一次数据拷贝这时我们可以使用ScriptableObject对象来存储数据然后通过引用来访问预制体中的数据。

这样可以避免在内存中产生一份拷贝数据。

与MonoBehaviour

一样ScriptableObject也继承自Unity基类object但是与MonoBehaviour不同的是ScriptableObject不能和GameObject对相关联相反通常我们会将它保存为Assets资源。

在编辑器模式下我们可以在编辑和运行时将数据保存到ScriptableObject因为保存ScriptableObject需要用到编辑器空间个脚本但是在开发模式下不能使用ScriptableObject来保存数据但是你可以使用ScriptableObject资源中已保存的数据。

60.unity常用资源路径有哪些

Application.streamingAssetsPath;

//StreamingAssets文件夹的绝对路径要先判断是否存在这个文件夹路径

//资源数据库

AssetDatabase.GetAllAssetPaths;

AssetDatabase.GetAssetPath(object)

//刷新

AssetDatabase.GetDependencies(string);

//获取依赖项文件

//类库对Asset文件夹下的文件进行操作获取相对路径获取所有文件获取相对依赖项

Directory

在主线程运行的同时开启另一段逻辑处理来协助当前程序的执行协程很像多线程但是不是多线程Unity的协程实在每帧结束之后去检测yield的条件是否满足。

62.什么叫做链条关节

Joint可以模拟两个物体间用一根链条连接在一起的情况能保持两个物体在一个固定距离内部相互移动而不产生作用力但是达到固定距离后就会产生拉力。

63.物理更新一般放在哪个系统函数里

FixedUpdate每固定帧绘制时执行一次和Update不同的是FixedUpdate是渲染帧执行如果你的渲染效率低下的时候FixedUpdate调用次数就会跟着下降。

FixedUpdate比较适用于物理引擎的计算因为是跟每帧渲染有关。

Update就比较适合做控制。

Intermediate

Language特指在.NET平台下的IL标准其实大部分文章中提到的IL和CIL表示的是同一个东西即中间语言。

IL是一种低阶lowest-level的人类可读的编程语言。

我们可以将通用语言翻译成IL然后汇编成字节码最后运行在虚拟机上。

也可以把IL看作一个面向对象的汇编语言只是它必须运行在虚拟机上而且是完全基于堆栈的语言。

IL有三种转译模式

Just-in-timeJIT编译在编译的时候把C#编译成CIL在运行时逐条读入逐条解析翻译成机器码交给CPU再执行。

Ahead-of-TimeAOT编译在编译成CIL之后会把CIL再处理一遍编译成机器码在运行的时候交给CPU直接执行Mono下的AOT只会处理部分的CIL还有一部分CIL采用了JIT的模式。

Full

AOT

完全静态编译在编译成CIL之后把所有的CIL编译成机器码在运行的时候直接执行这个模式适用于iOS操作系统。

运行时的主要作用是提供程序运行所需要的环境和基础设施通过为程序提供内存分配、线程管理、类型检查、对象实例化和垃圾回收等操作来支持程序的运行公共语言运行时Common

Language

RuntimeCLR是整个.NET框架的核心它为.NET应用程序提供了一个托管的代码执行环境。

它实际上是驻留在内存里的一段代理代码负责应用程序在整个执行期间的代码管理工作比较典型的有内存管理、线程管理、安全管理、远程管理、即时编译、代码强制安全类检查等

66.Mono和IL2CPP有什么区别为什么要使用IL2CPP

C#主要运行在.NET平台上但.NET跨平台支持不好。

Mono是.NET的一个开源跨平台的实现它包含一个C#编译器mono运行时CLR和一组类库Mono使得C#有了很好的跨平台能力。

C#这种遵循CLI规范的高级语言会被编译器编译成中间语言ILCIL当需要运行它们时就会被实时地加载到运行时库中由虚拟机动态地编译成汇编代码JIT并执行。

IL2CPP的编译和运行过程首先还是由Mono将C#语言翻译成ILIL2CPP在得到中间语言IL后将它们重新翻译成C代码再由各个平台的C编译器直接编译成能执行的机器码。

为什么要使用IL2CPP

Mono虚拟机维护成本过大。

Mono版本授权受限。

提高运行效率。

换成IL2CPP以后程序的运行效率有了1.52.0倍的提升。

托管代码托管代码就是执行过程交由运行时公共语言运行时CLR管理的代码。

不管使用的是哪种实现例如Mono、.NET

Framework或.NET

5)。

CLR负责提取托管代码、将其编译成机器代码然后执行它。

除此之外运行时还提供多个重要服务例如GC管理、安全边界、类型安全把托管代码理解成IL中间语言也行非托管代码非托管代码会直接编译成目标计算机的机器码这些代码包含C/C或C#中以不安全类型写的代码。

非托管代码不受CLR管理需要手动释放内存一般情况下我们使用托管代码来编写游戏逻辑非托管代码通常用于更底层的架构、第三方库或者操作系统相关接口

Mono将Simple

GCSGen-GC设置为默认的垃圾回收器当我们向垃圾回收器申请内存时如果发现内存不足就会自动触发垃圾回收或者也可以主动触发垃圾回收垃圾回收器此时会遍历内存中所有对象的引用关系如果没有被任何对象引用则会释放内存。

SGen-GC的主要思想是将对象分为两个内存池一个较新一个较老那些存活时间长的对象都会被转移到较老的内存池中去。

这种设计是基于这样的一个事实程序经常会申请一些小的临时对象用完了马上就释放。

而如果某个对象一段时间没被释放往往很长时间都不会释放。

IL2CPP的虚拟机的内存管理仍然采用类似Mono的方式因此程序员在使用IL2CPP时无须关心Mono与IL2CPP之间的内存差异。

使用某客户端的计算结果或由服务器决定计算结果只计算一次且认定这个值为准确值把这个值传递给其他设备或模块。

改用int或long类型来替代浮点数把浮点数乘以10的幂次得到更准确的整数再进行计算由于整数的计算是确定的因此就不会存在误差但要注意计算结果可能超出上限。

用定点数替代浮点数定点数把整数部分和小数部分拆分开来都用整数的形式表示缺点是由于拆分了整数和小数两个部分都要占用空间所以受到存储位数的限制。

大部分项目都会自己实现定点数无论是整数部分还是小数部分都用整数表示并封装在类中。

因此需要重载所有的基本计算和比较符号也可以使用开源的定点数库。

用字符串代替浮点数缺点是CPU和内存的消耗特别大只能做少量高精度的计算。

70.什么时候用结构体什么时候用类

用到继承和多态时用类。

结构体复制或者作为参数传递时不会改变原来对象的值如果需要这种特性可以使用结构体。

类对象是引用传递会改变原来对象的值。

因为值类型复制的特性如果结构体定义了很多字段复制的成本就会很高所有结构体适用于数据量小的场景。

DestroyImmediate是立即销毁立即释放资源做这个操作的时候会消耗很多时间的影响主线程运行。

Destroy是异步销毁一般在下一帧就销毁了不会影响主线程的运行。

获取RectMask2D或者Mask的RectTransform接着去调用GetWorldCorners获得该UI在世界坐标的信息坐标然后设置参数给Shader让其根据Rect坐标进行裁剪。

而Shader的实现很简单将超出部分的透明度设置为0。

73.UGUI和NGUI区别

UGUI通过MaskRectMask2D来裁剪而NGUI通过Panel的Clip。

NGUI的渲染前后顺序是通过Widget的depthdepth可以手动设置而UGUI渲染顺序根据Hierarchy的顺序越下面渲染在顶层元素depth是动态算出来的。

所以在制作功能界面时DrawCall控制

NGUI

Tool可以显示drawcall信息哪些东西合并成了一个drawcallUGUI没有这种功能。

UGUI不需要绑定CollidersUI可以自动拦截事件而NGUI需要绑定UICamera用射线判断点击的物体并通过SendMessage调用OnClick()

OnPress()等函数而SendMessage利用反射机制。

UGUI的Navgation在Scene中能可视化。

UGUI界面展示是在Canvas下而NGUI是在UIRoot下。

UGUI使用RectTransform控制元素的位置缩放等信息NGUI没有用到这个组件。

NGUI全部是用C#开发的UGUI底层代码可以基于C进行原生的编程。

元素的更新方式不同NGUI的UIPanel会在LateUpdate里遍历所有的widget如果有widget发生变化则触发更新即使没有变化的UI元素也会有正常的轮询操作的开销。

UGUI是通过两个队列m_LayoutRebuildQueue和m_GraphicRebuildQueue分别记录Layout和Graphic发生变化的UI元素在渲染之前会在这个回调函数Canvas.SendWillRenderCanvas里去处理这两个队列里的元素即分别进行Rebuild。

NGUI是必须先打出图集然后才能开始做界面。

这一点很烦因为始终都要去考虑你的UI图集。

比如图集会不会超1024

图集该如何来规划等等。

而UGUI的原理则是让开发者彻底模糊图集的概念让开发者不要去关心自己的图集。

做界面的时候只用小图而在最终打包的时候unity才会把你的小图和并在一张大的图集里面。

然而这一切一切都是自动完成的开发者不需要去care它。

网格更新机制不同NGUI可以只更新单个DrawCallUGUI必须重建整个Canvas。

UGUI。

在动态HUD界面如血条伤害数字弹出的一些文本等的网格更新控制UGUI

NGUI因为UGUI网格合并这块的算法是用C做的所以会比在C#做的快很多而且C#难免会触发一些堆内存的问题NGUIUIPanel.LateUpdate两种更新方式

UIPanel.FillDrawCall

更新单个DrawCallUIPanel.FillAllDrawCall

更新所有DrawCall

WaitingForJobPutGeometryJobFenceBatchRenderer.Flush开了多线程渲染之后

Unity在制作一个图元或者一个按钮或者一个背景时都会先构建一个方形网格网格的绘制单位是图元(点线三角面)再将图片放入网格中。

可以理解为构建了一个3D模型用一个网格绑定一个材质球材质球里存放要显示的图片。

渲染过程UI元素都继承自UIWidgetUIPanel遍历自己子物体的UIWidget组件放入到一个List中按照depth排序。

List中相邻元素如果materialtextureshader相同就传递它们的materialtextureshaderGeometry缓存都传给同一个UIDrawCall否则就再创建一个新的UIDrawCall。

每次有新的UIDrawCall产生UIPanel就会调用上一个UIDrawCall的UpdateGeometry()函数来创建渲染所需的对象。

这些对象分别是MeshFilterMeshRender和最重要的Mesh(Mesh的顶点UVColor法线切线还有三角面)。

UIDrawcall是渲染UI元素的载体UIPanel生成UIDrawcallUIDrawcall是一个组件挂载在一个GameObject这个GameObject上再挂载MeshRender、Mesh、MeshFilter、材质等Unity组件通过这些组件将UI元素渲染出来。

我们在Editor中是看不到这个GameObject的是因为创建的时候设置了HideFlags.HideAndDontSave。

UGUI的depth是动态算出来的按照Hierarchy的节点顺序从上向下进行depth分析最下层的元素depth

0元素相交会先判断是否能合批材质id一样图片id一样才能合批比如元素A和元素B相交且B盖住了A如果AB可以合批那么depthB

depthA否则

1如果一个元素盖住了多个元素则选取下面depth最大的元素进行合批判断。

从规则中可以看出depth值与是否相交有关与是否为子节点无关。

相同depth的元素会根据Material

ID和Texture

ID就是其字体的ID进行升序排序。

UGUI的渲染过程和NGUI类似UI组件的基类是GraphicGraphic保存了当前元素的mesh和materialGraphic实现接口ICanvasElement主要用于重绘CanvasRenderer用于传递这些数据给CanvasCanvasRenderer并不是直接渲染而是交给CanvasCanvas还要做合批等操作Canvas会对节点下的Graphic进行合批所以一个Graphic设置dirty整个canvas都需要重新计算合批。

76.如何让粒子在界面上正确显示

Layer参数如果特效粒子勾选Render属性这个特效就会有Order

Layer的概念就会跟Canvas的order进行混合影响显示层级。

在Prefab根节点上挂Sorting

Group,然后根据情况设置Order

Layer。

每个特效挂上脚本脚本中的类继承MaskableGraphic重写OnPopulateMesh函数该类是模拟Particle将其转换成UGUI的Graphic融入到UGUI体系所以可以将其当做lmage一样控制。

77.

mesh与shareMeshmaterial与shareMaterialmaterials和sharedMaterials的区别

mesh和material都是实例型的变量对mesh和material执行任何操作都是额外复制一份后再重新赋值即使只是get操作也同样会执行复制操作。

也就是说对mesh和material进行操作后就会变成另外一个实例虽然看上去一样但其实已是不同的实例了。

sharedMesh和sharedMaterial与前面两个变量不同它们是共享型的。

多个3D模型可以共用同一个指定的sharedMesh和sharedMaterial当你修改sharedMesh或sharedMaterial里面的参数时指向同一个sharedMesh和sharedMaterial的多个模型就会同时改变效果。

也就是说sharedMesh和sharedMaterial发生改变后所有使用sharedMesh和sharedMaterial资源的3D模型都会表现出相同的效果。

materials与sharedMaterials类似只不过变成了数组形式。

materials和sharedMaterials可以针对不同的子网格material和sharedMaterial只针对主网格。

也就是说material和sharedMaterial等于materials[0]和sharedMaterials[0]。

78.欧拉角四元数旋转矩阵优缺点

缺点单个四元数不能表示在任何方向上超过180度的旋转。

四元数的数字表示不直观。

缺点元素多存储空间大

由于它们被引用因此GC将不会收集它们这样它们将永久保存并占用内存。

当你以某种方式分配非托管内存没有垃圾回收并且不释放它们。

过度使用委托会导致内存泄漏多播委托会引用多个方法而当这个方法是实例方法(非静态方法)的话也就是说这个方法隶属于一个对象。

一旦我们使用委托引用这个方法的话那么这个对象就必须存在于内存当中。

即便没有其他地方引用这个对象因为委托的关系这个对象也不能释放。

因为一旦释放委托就不再能够间接调用到这个方法了所以没有正确删除委托的方法会导致内存泄漏。

静态对象没有及时释放。

如何避免

在架构上多添加析构的abstract接口提醒团队成员要注意清理自己产生的“垃圾”。

强化生命周期的概念无论是代码对象还是资源都有它存在的生命周期在生命周期结束后就要被释放。

如果可能需要在功能设计文档中对生命周期加以描述。

Assembly

Activator.CreateInstance(type);使用原型模式克隆。

反序列化

81.假设一个回合制战斗战斗过程均由客户端计算请问使用什么方式使得服务器可以验证此场战斗的数据是合法的?

最简单的方式根据公式计算当前队伍的伤害上限只要低于此伤害上限就认为战斗数据合法。

可以将整个战斗过程上传到服务器进行验算。

数值计算涉及到随机结果的情况下客户端、服务器使用同一随机种子及随机算法保证数值结果的正确合法性。

简单工厂模式把对象的创建封装到类中根据不同的参数生成不同的对象如根据建筑的类型生成不同的建筑。

观察者模式C#的event。

状态模式使用有限状态机将行为抽象成一个个状态通过状态管理器控制状态之间的转换同一时间只能处于某一个状态。

组合模式将一些功能抽象成一个个组件对象创建时根据需求添加不同的组件增强代码复用性。

单例模式全局为一游戏中的管理器。

外观模式对多个子系统进行封装通过外观类来获取这些系统减少系统的互相依赖减少和其他系统的耦合。

策略模式定义了一组同类型的算法在不同的类中封装起来每种算法可以根据当前场景相互替换从而使算法的变化独立于使用它们的客户端。

命令模式将一个命令封装为一个对象从而实现解耦改变命令对象撤销功能原型模式在不需要创建新对象的情况下复制现有对象并根据需要修改一些属性

83.Assetbundle

AssetBundle.LoadFromFile(Application.streamingAssetsPath

/cube);

收到的数据包不完整这种现象称之为黏包。

出现黏包的原因当发送端缓冲区的长度大于网卡的MTU网络上传送的最大数据包时tcp会将这次发送的数据拆成几个数据包发送出去。

tcp的协议数据不会丢没有收完包下次接收会继续上次继续接收己端总是在收到ack时才会清除缓冲区内容。

数据是可靠的但是会粘包。

解决办法

首先将所有接收到的字节流塞入缓冲池根据包头信息判断是否能获取当前完整协议包若能获取完整则根据协议头提取数据。

此时若有缓冲池还有其他协议数据若能继续提取就继续不能则跳过继续等待接收新字节流塞入缓冲池。

循环1和2

86.有限状态机和行为树区别

有限状态机将游戏AI行为分为一个一个的状态状态与状态之间通过状态管理器切换某一个时刻只能处于其中一种状态状态机的问题随着状态的增多需要考虑任意两个状态之间是否可以切换逻辑复杂复用性不好如果设计一个全新的敌人又需要重写一套状态节点和切换逻辑

行为树把行为抽象成一棵树它是一种“轮询式机制”即每次更新都会遍历树判定逻辑是否成立是否该继续往下执行。

行为树从上到下从左到右遍历节点行为树的每个节点会有返回一个执行状态一种设置方式是

三种状态Running代表正在运行SuccessFailure对应执行成功和失败综合来看行为树更适合描述角色在复杂环境下的行为。

状态机更适用于处理简单的状态转换并且适合处理基于输入驱动的场景

public

必须要静态类中的静态方法第一个参数的类型是要扩展的类型并且需要添加this关键字以标识其为扩展方法

Kinematic

Kinematic时将会忽略外部对此刚体的作用重力以及addforce或者其他物体对此物体的冲撞但是此刚体仍然主动对外部非Kinematic刚体产生物理作用

89.

纹理是最基本的数据输入单位游戏领域基本上都用的是位图。

此外还有程序化生成的纹理

Procedural

坐标、贴图输入输出控制等等。

材质是一个数据集主要功能就是给渲染器提供数据和光照算法。

贴图就是其中数据的一部分根据用途不同贴图也会被分成不同的类型比方说

Diffuse

垂直同步是一种调整显示器和GPU之间帧率同步的技术。

在启用垂直同步时GPU将帧率锁定为与显示器刷新率相同的数值。

例如如果你的显示器刷新率是60Hz那么GPU会将帧率锁定为60fps启用垂直同步有以下影响

减少画面撕裂如果游戏的帧率无法达到显示器的刷新率那么垂直同步将会导致帧率下降。

这是因为在垂直同步的情况下每当显示器完成一次刷新图形卡必须等待下一次刷新才能开始呈现下一个帧因此在某些情况下帧率将被降低到不到60帧以下

混合树(Blend

Tree)是一种将多个动画片段以位置、速度、角速度为依据经行线性混合的方式可以将几个动画文件很好的融合在一起还可以通过动画层(Layer)的方式实现每一个动画层只对动画主体的部分进行控制其他部分通过遮罩屏蔽

timeScale改变时会对以下值产生影响time、deltaTime、fixedTime以及fixedUnscaledDeltaTimetimeScale会影响

FixedUpdate

的执行速度当timeScale为0时FixedUpdate完全停止。

但不会影响Update、LateUpdate的执行速度如果Update、LateUpdate中使用了deltaTime则也会影响这部分逻辑的执行timeScale

不会影响

Coroutine本身的执行速度。

当timeScale为0时如果Coroutine中yield了某个WaitForSeconds或者WaitForFixedUpdate那么该Coroutine会在此处停下。

如果想要等待一个不受timeScale影响的时间请用WaitForSecondsRealtime

93.Unity3D

instantiate最简单的一种方式以实例化的方式动态生成一个物体。

Assetsbundle即将资源打成

asset

下来然后从这个bundle中load某个objectunity官方推荐也是绝大多数商业化项目使用的一种方式。

Resource.Load:可以直接load并返回某个类型的Object前提是要把这个资源放在Resource命名的文件夹下Unity不管有没有场景引用都会将其全部打入到安装包中AssetDatabase.loadasset

这种方式只在editor范围内有效游戏运行时没有这个函数它通常是在开发中调试用的。

94.第一次执行GameObject.Instantiate的时候有明显卡顿该怎么解决

Instantiate的卡顿与三部分开销相关相关资源加载、脚本组件的序列化和构造函数的执行并且绝大部分原因均是相关资源加载导致。

所以我们的建议如下

Profiler

具体的CPU分配情况如果是资源加载导致的性能瓶颈则一方面通过简化资源来缓解CPU耗时压力另一方面通过

AssetBundle

实例化操作的局部耗时更加平滑如果是脚本组件序列化导致的性能瓶颈则可尝试减少脚本中的序列化信息如果是构造函数的执行导致的性能瓶颈一般只能在策略上进行规避比如降低

Instantiate

、CrossFade淡入淡出切换动画、IsPlaying是否正在播放某个动画

动画层作为一个具有层级动画编辑概念的工具可以用来制作和处理任何类型的动画

98.Material

物理材质物理材质描述如何处理物体碰撞摩擦弹性。

Material

材质材质类为了获得一个对象使用的材质可以使用Renderer.materia

99.LayerMask.NameToLayer()这个方法有什么作用

LayerMask

的使用是按位操作的LayerMask.NameToLayer(“Players”)

100.Unity3d中static

Batching不需要任何操作只要共享材质(即使是不同的Mesh模型也可以)就会自动被合并。

可以自由移动旋转。

但有以下使用要求

模型文件共计点数不超过900。

重复使用同一个Mesh不计单个物体可以不超过300点Shader可以有法线UV。

但如果Shader使用了UV0

UV1两套UV,或

者Tangent切线的话单个物体只能不超过180点游戏对象使用相同模型和材质时只有相同缩放(即xyz等比缩放,浮点尾数可以有细微差)的会被合并。

111与111

2,2,2与2,22.0001场景烘焙烘焙后同材质将不会被烘焙。

lightmap

所以使用lightmap的物体不会被合并Shader不能使用多Pass:多Pass的Shader会破坏Dynamic

Batching

原理运行游戏后将一组游戏对象的多个模型会被动态合并为1个。

这组游戏对象所有使用同一材质的

在一个DrawCall来完成。

这些游戏对象运行后无法移动缩放旋转。

但是Drawcall一定是最大化合并的

并且不受动态合并的诸多限制见下文详述。

注意即使物体都使用了同样的模型在batch后每一个物体都会创建一份模型对应的geometry,在新的Combined

Mesh里。

所以过多的batch会增加内存占用。

例如场景里的树群就不适合Static

Static勾了即可代码中使用UnityEngine.StaticBatchingUtility实现(可以在任何平台调用):

Static)放入统一一个root

2)StaticBatchingUtility.Combine(root);

区别勾选Batching

Static完全自动合并,在MeshFilter里显示的是Combined

StaticBatchingUtility合并到一个游戏对象下。

合并后可以移动父节点游戏对象

有什么区

Awake先执行。

Update是在每次渲染新的一帧的时候才会调用FixedUpdate是在固定的时间间隔执行不受游戏帧率fps的影响FixedUpdate的时间间隔可以在项目设置中更改Edit-Project

Setting-time

102.Unity3D中的协程coroutine和C#线程之间的区别是什么

多线程程序同时运行多个线程而在任一指定时刻只有一个协程在运行并且这个正在运行的协

同程序只在必要时才被挂起。

除主线程之外的线程无法访问Unity3D

LoadLevelAsync异步加载关卡后台加载场景的方法。

StartCoroutine

为什么叫协同程序呢所谓协同就是当你在StartCoroutine

LoadLevelAsync

则允许你在后台加载新资源和场景所以再利用协同你就可以前台用loading

103.localPosition

localPosition自身位置相对于父级的变换的位置。

Position在世界坐标transform的位置

104.Vector3.forward与Vector3(0,0,1)是一样的意思对吗

String

**);106.Unity3d中resources目录一般用来放些什么打包的时候会有什么影响

resource一般用来放置一些需要动态加载的资源打包程序的时候会将Resource目录下的全部文件都加密压缩打进包内这样再想使用assetbundle方式打小包的话就不行了

对于两个平面AxByCzD0与axbyczd0只要(A,B,C)与(a,b,c)不成比例这两个平面就是相交的。

108.MeshCollider和其他Collider的⼀个主要不同

MeshCollider是⽹格碰撞器对于复杂⽹状模型上的碰撞检测⽐其他的碰撞检测精确的多但是相对其他的碰撞检测计算也增多了所以⼀般使⽤⽹格碰撞也不会在⾯数⽐较⾼的模型上添加⽽会做出两个模型⼀个超简模能表⽰物体的形状⽤于做碰撞检测⼀个⽤于显⽰。

109.当⼀个细⼩的⾼速物体撞向另⼀个较⼤的物体时会出现什么情况如何

穿透碰撞检测失败

Collider或者其他合适的碰撞器Collider来更精确地描述物体形状以避免穿透。

限制最大速度

如果物体的速度非常高可能会导致穿透等问题。

你可以通过代码来限制物体的最大速度或者使用Rigidbody的Interpolate属性来减缓高速移动时的问题。

调整物理材质

使用合适的物理材质设置摩擦力和弹性系数以便得到期望的碰撞效果。

你可以在Physics

Collision

Detection连续碰撞检测启用它可以减少高速物体的穿透问题。

Dynamic

在unity3d中物体发⽣碰撞的整个过程中有⼏个阶段分别列出对应的阶段函数

进⼊碰撞当collider/rigidbody开始触动另⼀个rigidbody/collider时OnCollisionEnter被调⽤。

逗留碰撞

每个collider/rigidbody触动rigidbody/collider将在每帧调⽤OnCollisionStay。

通俗的说

⼀个碰撞器或刚体触动另⼀个刚体或碰撞器在每帧都会调⽤OnCollisionStay直到它们之间离开不接触。

退出碰撞

rigidbody/collider时OnCollisionExit被调⽤。

可以通过将相机的位置设置为角色的位置加上一个偏移量从而实现相机跟随角色的效果

111.在Unity中如何加载异步资源

可以使用Unity的Coroutine和AsyncOperation来实现异步资源加载。

使用Coroutine可以在单个帧上分解加载工作而AsyncOperation则可以返回加载进度和资源对象

112.在Unity中如何实现角色动画

COntroller来实现角色动画。

Animatior组件用于控制角色的动画播放状态并可以在不同的动画状态之间进行过度.

113.在Unity中如何加载并播放音频

Source的属性如Clip和Volue。

可以控制加载和播放音频。

114.如何在Unity中实现粒子效果?

可以使用Unity的ParticleSystem组件来实现粒子效果。

通过调整ParticleSystem的属性如发色和位置速度大小和生命周期可以创建各种不同的粒子效果

可以使用Unity的宏定义或则预编译指令来实现游戏在不同平台下的差异化处理。

在Unity中可以通过消息系统委托和事件等机制实现对象之间的通信。

比如可以使用SendMessage函数向游戏对象发送消息通过委托和事件可以实现订阅和发布的消息传递。

可以使用Unity的UNET或则第三方网络库如Photon,Mirror等来实现多人联网游戏。

不美观OnGUI很耗费时间使用不方便

StreamingAssets:文件夹中的文件目录结构和文件会被原封不动地打包进安装包中Resources:需要动态加载的资源存放的位置Editors:编辑器特殊编辑工具存放的位置Plugins:插件存放的位置

120.Unity调整旋转

优点旋转轴可以是任意向量缺点旋转其实只需要知道一个向量一个角度(共4个信息值)但矩阵却用了16个元素(矩阵法消耗时间和内存)、

欧拉角旋转

优点容易理解形象直观表示更方便只需要三个值(分别对应x、y、z轴的旋转角度)缺点欧拉角这种方法是要按照一个固定的坐标轴的顺序旋转的因此不同的顺序会造成不同结果欧拉角旋转会造成万向锁现象这种现象的发生就是由于上述固定的坐标轴旋转顺序造成的。

理论上欧拉角旋转可以靠这种顺序让一个物体旋转到任何一个想要的方向但如果在旋转中不幸让某些坐标轴重合就会发生万向锁现象这时就会丢失一个方向上的旋转能力(两个旋转轴(环)重叠)也就是说在这种状态下我们无论怎么旋转(还是按照原先的旋转顺序)都不可能得到某些想要的结果除非打破原先的旋转顺序或者同时旋转三个轴。

由于万向锁的存在欧拉旋转无法实现球面平滑插值。

万向锁的简单解决办法构造一个不同的旋转层级顺序但是万向锁总是会在某一个顺序发生调整旋转顺序不是根本解决办法。

Unity使用的是Z-X-Y顺规即旋转顺序为z轴、x轴、y轴虽然某些情况下会出现万向锁但是这种顺规出现万向锁的概率最小万向锁解决办法将欧拉角转换为四元数对四元数进行Slerp插值再将这一系列四元数转换为对应的欧拉角然后作用于需要进行旋转的对象。

这种做法缺点在于消耗内存但是可以使物体任意旋转灵活度高。

使用欧拉旋转出现旋转路径偏移的根本原因在万向锁情况下对欧拉角的插值不是线性的。

(突变)静态欧拉角其旋转轴使用的是静止不同的参考系。

动态欧拉角使用object本身的坐标系因而会随着object旋转而旋转。

(局部坐标系会随着对象的旋转而旋转)

四元数旋转

优点可以避免万向锁只需要一个4维的四元数就可以执行绕任意过原点的向量的旋转方便快捷在某些实现下比旋转矩阵效率更高而且四元数旋转可以提供平滑插值。

缺点比欧拉旋转稍微复杂了一点因为多了一个维度理解更困难不直观。

121.本地坐标系

世界坐标系世界坐标是指物体在场景中的坐标当某个物体没有父物体时它的position即为世界坐标的positionrotation同理本地坐标是物体相对于它的父物体的坐标而言这个相对坐标是以父物体本身为坐标轴进行计算的与世界坐标没有必然联系。

而对于没有父物体的物体可以认为不存在本地坐标这种说法。

本地坐标系当某个物体有父物体时它的inspector栏transform中的position实际是localposition即本地坐标。

使用TransformPoint方法将本地坐标系转为世界坐标系



SEO优化服务概述

作为专业的SEO优化服务提供商,我们致力于通过科学、系统的搜索引擎优化策略,帮助企业在百度、Google等搜索引擎中获得更高的排名和流量。我们的服务涵盖网站结构优化、内容优化、技术SEO和链接建设等多个维度。

百度官方合作伙伴 白帽SEO技术 数据驱动优化 效果长期稳定

SEO优化核心服务

网站技术SEO

  • 网站结构优化 - 提升网站爬虫可访问性
  • 页面速度优化 - 缩短加载时间,提高用户体验
  • 移动端适配 - 确保移动设备友好性
  • HTTPS安全协议 - 提升网站安全性与信任度
  • 结构化数据标记 - 增强搜索结果显示效果

内容优化服务

  • 关键词研究与布局 - 精准定位目标关键词
  • 高质量内容创作 - 原创、专业、有价值的内容
  • Meta标签优化 - 提升点击率和相关性
  • 内容更新策略 - 保持网站内容新鲜度
  • 多媒体内容优化 - 图片、视频SEO优化

外链建设策略

  • 高质量外链获取 - 权威网站链接建设
  • 品牌提及监控 - 追踪品牌在线曝光
  • 行业目录提交 - 提升网站基础权威
  • 社交媒体整合 - 增强内容传播力
  • 链接质量分析 - 避免低质量链接风险

SEO服务方案对比

服务项目 基础套餐 标准套餐 高级定制
关键词优化数量 10-20个核心词 30-50个核心词+长尾词 80-150个全方位覆盖
内容优化 基础页面优化 全站内容优化+每月5篇原创 个性化内容策略+每月15篇原创
技术SEO 基本技术检查 全面技术优化+移动适配 深度技术重构+性能优化
外链建设 每月5-10条 每月20-30条高质量外链 每月50+条多渠道外链
数据报告 月度基础报告 双周详细报告+分析 每周深度报告+策略调整
效果保障 3-6个月见效 2-4个月见效 1-3个月快速见效

SEO优化实施流程

我们的SEO优化服务遵循科学严谨的流程,确保每一步都基于数据分析和行业最佳实践:

1

网站诊断分析

全面检测网站技术问题、内容质量、竞争对手情况,制定个性化优化方案。

2

关键词策略制定

基于用户搜索意图和商业目标,制定全面的关键词矩阵和布局策略。

3

技术优化实施

解决网站技术问题,优化网站结构,提升页面速度和移动端体验。

4

内容优化建设

创作高质量原创内容,优化现有页面,建立内容更新机制。

5

外链建设推广

获取高质量外部链接,建立品牌在线影响力,提升网站权威度。

6

数据监控调整

持续监控排名、流量和转化数据,根据效果调整优化策略。

SEO优化常见问题

SEO优化一般需要多长时间才能看到效果?
SEO是一个渐进的过程,通常需要3-6个月才能看到明显效果。具体时间取决于网站现状、竞争程度和优化强度。我们的标准套餐一般在2-4个月内开始显现效果,高级定制方案可能在1-3个月内就能看到初步成果。
你们使用白帽SEO技术还是黑帽技术?
我们始终坚持使用白帽SEO技术,遵循搜索引擎的官方指南。我们的优化策略注重长期效果和可持续性,绝不使用任何可能导致网站被惩罚的违规手段。作为百度官方合作伙伴,我们承诺提供安全、合规的SEO服务。
SEO优化后效果能持续多久?
通过我们的白帽SEO策略获得的排名和流量具有长期稳定性。一旦网站达到理想排名,只需适当的维护和更新,效果可以持续数年。我们提供优化后维护服务,确保您的网站长期保持竞争优势。
你们提供SEO优化效果保障吗?
我们提供基于数据的SEO效果承诺。根据服务套餐不同,我们承诺在约定时间内将核心关键词优化到指定排名位置,或实现约定的自然流量增长目标。所有承诺都会在服务合同中明确约定,并提供详细的KPI衡量标准。

SEO优化效果数据

基于我们服务的客户数据统计,平均优化效果如下:

+85%
自然搜索流量提升
+120%
关键词排名数量
+60%
网站转化率提升
3-6月
平均见效周期

行业案例 - 制造业

  • 优化前:日均自然流量120,核心词无排名
  • 优化6个月后:日均自然流量950,15个核心词首页排名
  • 效果提升:流量增长692%,询盘量增加320%

行业案例 - 电商

  • 优化前:月均自然订单50单,转化率1.2%
  • 优化4个月后:月均自然订单210单,转化率2.8%
  • 效果提升:订单增长320%,转化率提升133%

行业案例 - 教育

  • 优化前:月均咨询量35个,主要依赖付费广告
  • 优化5个月后:月均咨询量180个,自然流量占比65%
  • 效果提升:咨询量增长414%,营销成本降低57%

为什么选择我们的SEO服务

专业团队

  • 10年以上SEO经验专家带队
  • 百度、Google认证工程师
  • 内容创作、技术开发、数据分析多领域团队
  • 持续培训保持技术领先

数据驱动

  • 自主研发SEO分析工具
  • 实时排名监控系统
  • 竞争对手深度分析
  • 效果可视化报告

透明合作

  • 清晰的服务内容和价格
  • 定期进展汇报和沟通
  • 效果数据实时可查
  • 灵活的合同条款

我们的SEO服务理念

我们坚信,真正的SEO优化不仅仅是追求排名,而是通过提供优质内容、优化用户体验、建立网站权威,最终实现可持续的业务增长。我们的目标是与客户建立长期合作关系,共同成长。

提交需求或反馈

Demand feedback