C# &Unity 唐老狮 No.2 模拟面试题

本文章不作任何商业用途 仅作学习与交流 安利唐老狮与其他老师合作的网站,内有大量免费资源和优质付费资源,我入门就是看唐老师的课程 打好坚实的基础非常非常重要:

Unity课程 - 游习堂 - 唐老狮创立的游戏开发在线学习平台 - Powered By EduSoho

如果你发现了文章内特殊的字体格式,那是AI补充的知识

目录

C#

[1.Equals可以判断一些引用类型是否相等 尤其是对象不同时](#1.Equals可以判断一些引用类型是否相等 尤其是对象不同时)

2.深浅拷贝主要区别为引用类型是否独立

[3.第二种速度更快 因为List涉及到了扩容](#3.第二种速度更快 因为List涉及到了扩容)

[4.B先打印 ,A:10 B:11](#4.B先打印 ,A:10 B:11)

[5.A 11 B11 因为是引用类型](#5.A 11 B11 因为是引用类型)

Unity

[1. Unity中当一个细小高速物体撞击另一个较大物体时,会出现什么情况?如何避免?](#1. Unity中当一个细小高速物体撞击另一个较大物体时,会出现什么情况?如何避免?)

[2. 请简述一下Prefab(预制体)的本质是什么?](#2. 请简述一下Prefab(预制体)的本质是什么?)

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

[4. 请简述一下对象池,在游戏开发中我们什么时候会用到它?](#4. 请简述一下对象池,在游戏开发中我们什么时候会用到它?)

[5. 什么是DrawCall?DrawCall为什么会影响游戏运行效率?如何减少DrawCall?](#5. 什么是DrawCall?DrawCall为什么会影响游戏运行效率?如何减少DrawCall?)


C#

1.Equals可以判断一些引用类型是否相等 尤其是对象不同时

对值类型 二者都可以使用

复制代码
static void test() {
    int a0 =1;
    int a1 =2;
    Console.Write(a0==a1?a0:a1);
    Console.Write(a0.Equals(a1));
}
test();

但是当对象比较变成不同的类 时 == 就不被允许了(除非operator重载运算符)

当然,你去比较两个相同类型的对象仍然是可以的

复制代码
a Obja0 = new a();
b Objb = new b();
a Obja1 = new a();
Obja0 = Obja1;

Console.Write(Obja0.Equals(Objb));
Console.Write(Obja0.Equals(Obja1));
Console.Write(Obja0  == Obja1);
特性 == 操作符 Equals 方法
本质 运算符(可重载) 虚方法(可重写)
默认行为 值类型:比较值;引用类型:比较引用地址 值类型:比较值;引用类型:比较引用地址
可自定义性 通过重载 operator == 改变行为 通过重写 Equals 方法改变行为
null 处理 可直接比较 null(如 obj == null 需先检查是否为 null,否则可能抛 NullReferenceException
多态性 静态绑定(编译时决定行为) 动态绑定(运行时根据实际类型决定行为)

另外对于string引用类型却有值类型的特殊性 ,Equals比较的是其字符串内容(值)

2.深浅拷贝主要区别为引用类型是否独立

cs 复制代码
public class MyClass : ICloneable
{
    public int Value { get; set; }
    public List<int> List { get; set; } = new List<int>();

    // 浅拷贝实现
    public object Clone()
    {
        return new MyClass
        {
            Value = this.Value,    // 值类型直接复制
            List = this.List       // 引用类型复制指针
        };
    }
}

// 使用示例
MyClass original = new MyClass 
{ 
    Value = 10,
    List = new List<int>() 
};

// 浅拷贝
MyClass shallowCopy = (MyClass)original.Clone();

// 修改拷贝对象
shallowCopy.Value = 20;       // 不影响 original.Value(值类型独立)
shallowCopy.List.Add(1);      // 会影响 original.List(共享同一个列表实例)
cs 复制代码
using System;
using System.Collections.Generic;

public class MyClass : ICloneable
{
    public int Value { get; set; }
    public List<int> List { get; set; }

    // 实现深拷贝
    public object Clone()
    {
        return new MyClass
        {
            Value = this.Value,  // 值类型直接复制
            List = new List<int>(this.List)  // 创建新列表实例(深拷贝关键)
        };
    }
}

// 使用示例
MyClass original = new MyClass 
{ 
    Value = 10,
    List = new List<int>() 
};

// 深拷贝
MyClass deepCopy = (MyClass)original.Clone();

// 修改拷贝后的对象
deepCopy.Value = 20;       // 不影响 original.Value
deepCopy.List.Add(1);      // 不影响 original.List
特性 浅拷贝(Shallow Copy) 深拷贝(Deep Copy)
复制层次 仅复制对象本身及其直接字段(一层) 递归复制对象及其所有引用字段的完整对象树
引用类型字段 复制引用地址(新旧对象共享同一引用对象) 创建新对象并复制内容(新旧对象引用完全独立)
性能 高效(仅复制一层) 较低效(需递归复制所有嵌套对象)
适用场景 引用字段不可变或无需独立修改时 引用字段需要完全独立修改时

3.第二种速度更快 因为List涉及到了扩容

关于扩容简单写法请看这篇之中的c#部分第五题:
C# &Unity 唐老狮 No.1 模拟面试题-CSDN博客

4.B先打印 ,A:10 B:11

异常捕捉的机制是先try然后接着finally执行捕获 再执行其他地方的代码 但是return是已经返回出去了i,因此是先return 再B处 再A处

5.A 11 B11 因为是引用类型

Unity

1. Unity中当一个细小高速物体撞击另一个较大物体时,会出现什么情况?如何避免?

会穿过去 ,或者卡在大球的某个部分抖动,解决方法:

1.将碰撞检测改为更好的方式:

2.射线检测

可以给小球加一个很短的射线检测 当撞击前就做出一定的预处理

这个方案由ai提供 我还真没用过

3.修改固定时间步长

Project Settings --> Time 中减少 Fixed Timestep 值(如从0.02改为0.01),提升检测频率

2. 请简述一下Prefab(预制体)的本质是什么?

本质是一个配置文件,里面有很多关于该预制体的参数和基本信息,甚至可以自行修改

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

支持,但是要注意unity本身就带有一个主线程,其大部分api都只能在主线程里面跑,如果在其他线程和主线程同时调用unity的一这些api(比如translate,GetComponent等等)会导致线程冲突报错 所以禁止直接调用Unity API ,但可通过 MainThreadDispatcher 将任务排队到主线程执行

cs 复制代码
// 示例:主线程调度器
public class MainThreadDispatcher : MonoBehaviour {
    private static Queue<Action> tasks = new Queue<Action>();
    void Update() {
        while (tasks.Count > 0) 
            tasks.Dequeue().Invoke();
    }
    public static void RunOnMainThread(Action action) => tasks.Enqueue(action);
}

同时还要注意多线程本身就应该注意的问题:

内存泄漏,是指要在合适的时机对后台关闭后台线程,不然这个线程将会一直运行 哪怕你停止运行了游戏 在Editor之中仍然在跑,直到这个线程持有了大量的资源,导致可用内存逐渐减少, 这种现象就是内存泄漏

避免死锁,即多个线程相互等待对方释放资源而陷入僵持状态

4. 请简述一下对象池,在游戏开发中我们什么时候会用到它?

知识加油站:

Unity 高级一些的对象池(初版)(非基础警告)_unity 高级对象池-CSDN博客

对象池也叫缓存池 是一个用于存储和拿出频繁销毁物体或对象的管理类

在大量且频繁创建与销毁的场景之中会用到,比如音效,子弹,大量敌人

5. 什么是DrawCall?DrawCall为什么会影响游戏运行效率?如何减少DrawCall?

知识加油站:这里挖个坑 关于shader基础知识的链接将会放在这里

DrawCall就是 CPU 向 GPU 发送指令,要求 GPU 对一组图元(如三角形、四边形等)进行渲染的操作,每一次对图形api的调用都会产生一次drawcall

如果大量的drawcall:

  • CPU 开销:每次 Draw Call 都需要 CPU 进行准备工作,如设置渲染状态、传递顶点数据、纹理数据等。大量的 Draw Call 会使 CPU 花费大量时间在这些准备工作上,从而减少了 CPU 用于处理游戏逻辑等其他重要任务的时间。
  • GPU 上下文切换:GPU 在处理不同的 Draw Call 时,可能需要切换渲染状态,如切换纹理、材质、着色器等。频繁的上下文切换会增加 GPU 的额外开销,降低渲染效率。
  • 带宽限制:Draw Call 需要在 CPU 和 GPU 之间传输数据,包括顶点数据、索引数据、纹理数据等。大量的 Draw Call 会导致数据传输量增大,可能会超出总线带宽限制,造成数据堵塞,影响渲染速度

减少:

**1.对UI进行剔除:**对于不在屏幕范围内或被其他 UI 遮挡的 UI 元素,不进行绘制,可以通过计算 UI 元素是否在视口内,以及使用遮挡剔除技术来实现,例如,在 Unity 中可以利用 Canvas Group 组件的 Alpha 值为 0 时自动进行剔除的特性,或者自定义脚本根据 UI 的可见性来控制是否渲染

2. 对网格进行合批(动态 在一定程度上unity自动处理,但是有很大限制,可以自己编写脚本处理

静态 只针对静态的物体,当勾选了static选项以后 unity会自动做处理)

3. 对图片进行打图集

唐老师在unity核心之中讲过打图集相关内容

也可以参考本篇**:** Unity UGUI 之 图集_unity 图集-CSDN博客

AI补充:

  • 使用批处理渲染器:一些渲染器提供了批处理功能,如 URP(Universal Render Pipeline)中的 SRP Batcher。它可以在不改变材质和模型的情况下,对物体进行批处理,提高渲染效率。
  • 优化材质和着色器:尽量减少材质和着色器的复杂度,避免使用过多的变体。过多的材质变体和复杂的着色器计算会增加 Draw Call 的开销。可以通过合并相似的材质,减少不必要的纹理采样和计算来优化。
相关推荐
Lee川5 小时前
优雅进化的JavaScript:从ES6+新特性看现代前端开发范式
javascript·面试
Lee川8 小时前
从异步迷雾到优雅流程:JavaScript异步编程与内存管理的现代化之旅
javascript·面试
晴殇i10 小时前
揭秘JavaScript中那些“不冒泡”的DOM事件
前端·javascript·面试
绝无仅有11 小时前
Redis过期删除与内存淘汰策略详解
后端·面试·架构
绝无仅有11 小时前
Redis大Key问题排查与解决方案全解析
后端·面试·架构
AAA梅狸猫12 小时前
Looper.loop() 循环机制
面试
AAA梅狸猫12 小时前
Handler基本概念
面试
Wect12 小时前
浏览器缓存机制
前端·面试·浏览器
掘金安东尼13 小时前
Fun with TypeScript Generics:玩转 TS 泛型
前端·javascript·面试
掘金安东尼13 小时前
Next.js 企业级落地
前端·javascript·面试