欢迎来到光光的奇妙冒险,我是你们的煎饼光子老师。
今天是我们的第11期试题总结。
C#部分:
1、文件中保存了文本信息,但是打开后却是乱码,一般是什么原因造成的?
答案:
序列化和反序列化字符串时使用的编码格式不统一
2、C#中new关键字的作用(至少说出3种)
答案:
1. 创建新对象
2. 子类函数声明时加上new关键字,可以隐藏掉父类方法
3. 泛型约束中使用new关键词,表示需要无参构造
※3、同步方法和异步方法的区别是什么?
异步编程是什么意思?
对于我们来说,什么时候需要使用异步编程?(至少说出3种)
答案:
同步方法:
当一个方法被调用时,调用者需要等待该方法执行完毕后返回才能继续执行
异步方法:
当一个方法被调用时立即返回,并获取一个线程执行该方法内部的逻辑,调用者不用等待该方法执行完毕
异步编程:
在日常开发时把一些不需要立即得到结果且耗时的逻辑设置为异步执行,这样可以提高程序的运行效率,避免由于复杂逻辑带来的的线程阻塞
什么时候需要使用异步编程:
1.复杂逻辑计算时,比如寻路算法等
2.网络下载、网路通讯
3.资源加载时
等
※4、回调函数指什么?一般在什么时候使用?(至少说出3种使用场景)
答案:
回调函数指在程序设计中,将一个函数作为参数传递给另一个函数,并在另一个函数执行完毕后被调用的函数,在C#中,一般以委托形式出现
什么时候使用:
1.异步编程:异步逻辑执行完毕后,再执行回调函数
2.事件中心
3.UI界面中的空间逻辑回调,比如按钮点击
等等
5、如何用一个int变量,记录32种状态?(注意:状态可以并存)
答案:
int在C#中占4个字节,共32位
我们可以按位记录状态,每一位代表一个状态,1为存在,0为不存在
Unity部分:
1、请解释Unity中的Prefab是什么,以及它在游戏开发中的作用是什么?
在Unity中,Prefab是一种游戏对象的预制件或者模板。它允许你在编辑器中创建一个游戏对象,并将其保存为Prefab,以便在需要时可以实例化多个相同的对象。当你在场景中使用一个Prefab实例时,它将保留与原始Prefab相同的组件、属性和位置,使得你可以轻松地创建和管理大量相似的游戏对象。
Prefab在游戏开发中的作用非常重要,因为它们允许你创建可重用的游戏对象,并且可以在开发过程中快速迭代和修改。例如,当你需要在游戏中生成大量相似的敌人时,使用一个敌人Prefab可以使得你仅需创建和修改一个敌人对象,而不必重复编写和调整代码。此外,Prefab还允许你在编辑器中预览和调整游戏对象的属性和组件,使得你可以快速地进行修改和测试,从而加快开发进程。
2、在Unity中,什么是Shader?它有什么作用,以及如何编写一个基本的Shader?
在Unity中,Shader是一种用于定义渲染对象的程序。它描述了对象的外观、材质和光照效果。在渲染场景时,每个对象都会使用其对应的Shader来生成像素颜色,并最终呈现到屏幕上。在Unity中,可以使用着色器语言(ShaderLab)和高级着色器语言(HLSL)编写自定义的Shader。
Shader在游戏开发中具有非常重要的作用。它们控制了游戏对象的外观和性能,并且可以根据需要创建各种各样的视觉效果,比如透明度、反射、阴影、发光等等。使用自定义Shader还可以实现一些特定的效果,例如水波纹、烟雾、火焰等等。
下面是一个简单的Shader示例,该Shader可以使物体变成红色:
arduino
Copy code
Shader "Custom/RedShader" {
SubShader {
Pass {
CGPROGRAM
#pragma vertex vert
#pragma fragment frag
struct appdata {
float4 vertex : POSITION;
};
struct v2f {
float4 vertex : SV_POSITION;
};
v2f vert (appdata v) {
v2f o;
o.vertex = UnityObjectToClipPos(v.vertex);
return o;
}
fixed4 frag (v2f i) : SV_Target {
return fixed4(1.0, 0.0, 0.0, 1.0);
}
ENDCG
}
}
}
在这个例子中,我们使用ShaderLab语言定义了一个名为"Custom/RedShader"的Shader。它只有一个Pass,并且使用CGPROGRAM指令告诉Unity使用CG语言编写着色器代码。着色器有两个结构体,分别描述了输入和输出的数据格式。在vert函数中,我们将输入的顶点坐标转换为裁剪空间坐标。在frag函数中,我们将输出固定为红色。
※3、在Unity中,什么是常见的性能优化技巧?请举例说明。
主要是两个方面,一是内存上,二是cpu/gpu性能上
首先内存上,尽量要占用少,尽量要减少GC
以下是可采取的措施:
使用对象池:对象池是一种常见的技术,用于缓存和重复使用游戏对象,而不是频繁地创建和销毁它们。使用对象池可以减少内存分配和垃圾回收的开销,从而提高游戏性能。
减少资源占用:在开发过程中,应该尽量避免使用过多的高分辨率纹理和复杂的模型。可以使用纹理压缩、减少纹理尺寸、使用轻量级的模型等方式来减小资源占用。
及时销毁不再使用的对象:当游戏中不再需要使用某些对象时,应该及时销毁它们,以释放它们占用的内存。尤其是一些长时间存在的对象,如粒子系统、音频和视频资源等,都应该及时销毁。
使用异步加载:如果游戏中需要加载大量的资源,可以使用异步加载技术。异步加载可以减少游戏卡顿和内存占用,从而提高游戏性能。可以使用Unity提供的异步加载API或者自定义异步加载方式来实现异步加载。
使用资源打包:在打包游戏时,可以使用资源打包技术来减少游戏的内存占用。资源打包可以将多个资源打包成一个单独的文件,从而减小游戏的内存占用。可以使用Unity提供的Asset Bundle功能或者自定义打包方式来实现资源打包。
然后是cpu/gpu性能上,以下是可以采取的措施:
减少Draw Call:在Unity中,每次渲染一个物体都会使用一个Draw Call。过多的Draw Call会导致渲染性能下降,因此应该尽量减少它们的数量。可以通过合并网格、使用物体批处理和减少物体数量等方式来减少Draw Call。
使用级别LOD:如果场景中有大量的物体,可以使用级别LOD技术来优化性能。通过在远离玩家的位置使用低分辨率的网格,可以降低渲染开销,提高性能。
合理使用资源:在开发过程中,应该尽量避免使用过多的高分辨率纹理和复杂的模型。可以使用纹理压缩、减少纹理尺寸、使用轻量级的模型等方式来减小资源占用。
使用光照贴图:在游戏中,光照是非常重要的,但是使用动态光照会带来很大的渲染开销。因此,可以使用光照贴图来减少动态光照的数量。光照贴图可以在编辑器中生成,并且可以有效地提高游戏的性能。
使用对象池:对象池是一种常见的技术,用于缓存和重复使用游戏对象,而不是频繁地创建和销毁它们。使用对象池可以减少内存分配和垃圾回收的开销,从而提高游戏性能。
4、在Unity中,什么是协程(Coroutine)?它有什么作用,以及如何使用它?
协程(Coroutine)是一种在Unity中常用的编程技术,用于在运行时控制代码的执行顺序。协程可以将代码执行分为多个阶段,可以在其中暂停和恢复代码执行,从而实现异步执行和任务管理等功能。
协程的主要作用包括:
延迟执行:协程可以延迟执行某个任务,从而在指定时间后执行相应的操作。
异步执行:协程可以在后台执行任务,从而避免卡顿和阻塞主线程。
任务管理:协程可以管理多个任务,从而实现更灵活和可控的代码执行顺序。
在Unity中,协程的使用非常简单,可以使用C#的yield语句来实现协程。以下是一个使用协程延迟执行某个操作的示例:
csharp
Copy code
IEnumerator DelayCoroutine(float delayTime)
{
yield return new WaitForSeconds(delayTime);
Debug.Log("Delayed log after " + delayTime + " seconds");
}
在上面的示例中,使用了yield return new WaitForSeconds(delayTime)来等待一段时间,然后再执行后续的代码。可以在其他的代码中使用StartCoroutine来启动协程。
csharp
Copy code
StartCoroutine(DelayCoroutine(3.0f));
以上代码将会在3秒后输出一条日志信息。通过使用协程,我们可以方便地控制代码执行顺序和实现异步执行等功能
5、解释一下Unity中的渲染管线(Rendering Pipeline)是什么,如何使用它,并举例说明它在游戏开发中的应用场景。
几何图形的准备:将场景中的几何图形转换为渲染引擎可以理解的形式,例如将3D模型转换为网格数据(Mesh)和材质信息。
光照计算:计算场景中每个几何图形的光照效果,包括直接光照和间接光照。
视点变换:根据摄像机的位置和方向将场景中的几何图形转换为摄像机的视图空间(View Space)坐标系下的形式。
投影变换:将摄像机的视图空间坐标系下的几何图形转换为投影坐标系下的形式。
图像空间计算:将投影坐标系下的几何图形转换为屏幕上的像素坐标。
着色:根据材质信息和光照信息对几何图形进行着色,计算每个像素的颜色值。
合成:将所有的像素颜色值按照一定的顺序合成为最终的图像,输出到屏幕上。