近期面试Unity游戏开发中遇到的问题

1.array和list的优缺点,使用场景

数组

1.数组需要预留空间,可能会造成内存浪费

2.要定义数组首先要有一段足够长的连续空间

3.数组大小事固定的,不支持动态的扩展

列表

内部维护一个数组,数组大小不是固定的,支持动态的扩展

使用场景

1.数组:数量几乎不会改变

2.列表:数量不确定

2.队列和栈的实际应用

构建对象池这种功能是适合使用队列和栈,因为并不在乎进出顺序,其性能较佳

3.字典有什么特点

1.Dictionary里面每一个元素都是以键值对的形式存在的

2.键必须是唯一的,而值不需要唯一

3.键和值都可以以任何数据类型存在

4.通过一个键值读取一个值的时间接近O(1)

C#中的Dictionary是一种键值对集合,它使用哈希表实现,在插入、删除和查找操作上具有高效的性能。

字典表示一种数据结构,这种数据结构允许按照某个键来访问元素。

内部是以key,value的形式存储数据,每个元素都是一个键值对

字典长度是不固定的,随着元素增减而改变

key相当于数组索引值 ,key需要自定义在一个字典中,key的定义不能重复,具有唯一性

优点:

1). 快速的查找:Dictionary内部使用哈希表来存储数据,可以通过键来快速查找对应的值,平均查找时间复杂度为O(1)。

2). 唯一键:Dictionary要求键的唯一性,保证了键的唯一性,防止重复的键的存在。

3). 内存效率:相对于其他集合类型,Dictionary在存储大量数据时,具有较低的内存占用。

缺点:

1). 内存消耗:由于Dictionary使用哈希表来存储数据,需要使用额外的内存空间来存储哈希表和键值对对象。

2). 无序集合:Dictionary中的元素是无序的,并不像SortedSet或List那样保持有序。

4.常用的设计模式

单例模式,状态模式,观察者模式,命令模式,工厂模式

5.工厂模式

工厂模式是一种创建型模式,为的是减少创建对象吧时,使用端与具体的类耦合关系,尤其是在有多重对象需要创建时,那么使用端就会与多个类之间产生耦合,工厂模式也算是符合迪米特法则,尽量让使用端金肯的指导更少的类,而通过工厂去与具体的类产生联系,只依赖于工厂和产品的抽象类,总的来说,就是把使用产品的各种业务逻辑和产品的创建分离开来。

6.单例模式

单例,模式是比较常见的一种设计模式,目的是保证一个类只能有一个实例,而且自行实例化并向整个系统提供这个实例,避免频繁创建对象,节约内存。

单例模式的应用场景很多,比如我们电脑的操作系统的回收站就是一个很好的单例模式应用,电脑上的文件,视频,音乐等被删除后都会进入到回收站中;还有计算机中的打印机也是采用单例模式设计的,一个系统重可以存在多个打印任务,但是只能有一个正在工作的任务;Web页面的计数器也是用单例模式实现的,可以不用把每次刷新都记录到数据库中。

一般应用在各种管理器中。

单例模式包含:

1.饿汉式

2.懒汉式

3.双检锁懒汉式

4.静态内部类单例式

5.枚举单例式

C#中的五种单例模式(SIngleton)_c# 单例模式-CSDN博客

7.怎么实现一个事件系统

使用一个字典维护所有的事件委托,对外提供注册事件,取消事件,触发事件

在事件系统中基于字典中的Key来确定,需要注册哪个Action,触发哪个Action

8.UI框架会使用什么设计模式

一般会使用MVC

9.如何使用NavMesh动态寻路

1.烘焙导航网格

2.需要导航的物体添加NavMeshAgent组件

3.运行时使用NavMeshAgent.SetDestionation函数进行导航

10.Unity的GameObject生命周期

GameObject 生命周期应该是指 MonoBehaviour 脚本的生命周期

主要生命周期函数:

Awake 脚本实例被创建时调用 用于游戏对象初始化,注意 Awake 函数是早于 Start 函数

OnEnable 当对象变为可用或激活状态时被调用 事件监听

Start Update 函数第一次运行前调用 用于游戏对象的初始化

FixedUpdate 每隔固定物理时间间隔调用一次 用于物理状态的更新

Update 每帧调用一次 用于更新游戏场景和状态

LateUpdate 每帧调用一次(在 update 之后调用) 用于更新游戏场景和状态,和摄 像机相关的更新

OnGUI 渲染和处理 OnGUI 事件

OnDisable 当对象变为不可用或非激活状态时被调用 事件移除

OnDestroy 当对象被销毁时调用

11.Mono和Unity的区别

Unity 因为方便和跨平台选择了 C#作为主要的开发语言。而且 C#的跨平台是基 于.Net Framework 框架下的(CIL,通用描述语言)和 CLR(通用运行环境的)。 在经过各种考量后,Unity 选择了开源,并且平台支持性很好的 Mono 这一开源 的.Net Framework 跨平台实现方案。

12.协程的原理以及底层的实现

StartCoroutine 接受到的是一个 IEnumerator ,这是个接口,并且是枚举器或 迭代器的意思。

yield 是 C#的一个关键字,也是一个语法糖,背后的原理会生成一个类,并且也 是一个枚举器,而且不同于 return,yield 可以出现多次。

yield 实际上就是返回一次结果,因为我们要一次一次枚举一个值出来,所以多 个 yield 其实是个状态模式,第一个 yield 是状态 1,第二个 yield 是状态 2,每次访 问时会基于状态知道当前应该执行哪一个 yield,取得哪一个值。

使用较多的“暂停 XX 秒” yield return new WaitForSeconds(0.5f),其实本质 上就是每一帧都来检查一次是否满足了计时,如果满足就说明 yield 的状态满足了, 进入下一个状态,至于 yield return null,为什么会有暂停一帧的效果,因为相当于 什么也没做,但是检查需要在下一帧进行

13.为什么Unity中很少使用多线程,多线程和协程都是非阻塞的,两者的优劣?

协程依然运行在主线程,只是逻辑上是非阻塞的而已。

Unity 引擎本身是多线程的,只是 C#脚本是运行在同一个线程中的。

因为游戏引擎是主循环结构,逻辑更新和画面更新时间点要求有确定性,如果逻 辑更新和画面更新中引入了多线程,就需要做同步,而这加大了游戏的开发难度。

14.Unity有哪些资源

GameObject ;Component;AdudioClip;AnimationClip;AniamtionController;各种Asset

15.Unity怎么管理Resources的

Resources 本质上就是一个缺省 Assetbundle,Resources 文件夹下的文件都会 打入整个 AB 包,并且在游戏启动时就加载整个 AB 包

16.Unity协程怎么用,协程的源码怎么写

定义一个函数,返回值为 IEnumerator,在其中使用 yield 关键字去做 WaitForSeconds()等行为

自定义一个协程,只需要新增一个 class,继承自 CustomYieldInstruction 并实 现 KeepWating

17.进程,线程,协程,Unity中协程的使用

进程

保存在硬盘上的程序运行以后,会在内存空间里形成一个独立的内存体,这 个内存体有自己独立的地址空间,有自己的堆,上级挂靠单位是操作系统。操作系统 会以进程为单位,分配系统资源(CPU 时间片、内存等资源),进程是资源分配的最 小单位。

线程

线程又叫做轻量级进程,是操作系统调度,是 CPU 调度的最小单位。

线程从属于进程,是程序的实际执行者。一个进程可以有多个线程,最少有 一个线程,但一个线程只能有一个进程。

协程

协程,又称微线程,纤程;是一种比线程更加轻量级的存在

线程的切换会保存到 CPU 的栈里,协程拥有自己的寄存器上下文和栈

协程最主要的作用是在单线程的条件下实现并发的效果,但实际上还是串行 的(像 yield 一样)

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

18.值类型和引用类型的主要区别是什么

  • 值类型(基本类型):数字(Number)、布尔(Boolean)、空值(null)、未定义(undefined)、转义字符、Symbol(ES6引入了一种新的原始数据类型,表示独一无二的值)。

  • 引用数据类型:对象(Object)、数组(Array)、函数(Function)。

  • 简单比较:值类型的变量是直接存储数据,而引用类型的变量是持有的是数据的引用,数据引用存储在数据堆中。

  • 区别

    (1) 存储位置不一样

    ① 值类型的变量会保存在栈内存中,如果在一个函数中声明一个值类型的变量,那么这个变量当函数执行结束之后会自动销毁

    ② 引用类型的变量名会保存在栈内存中,但是变量值会存储在堆内存中,引用类型的变量不会自动销毁,当没有引用变量引用它时,系统的垃圾回收机制会回收它

    (2) 复制方式不一样

    ① 值类型的变量直接赋值就是深复制,如 var a = 10; var b = a;那么a的值就复制给b了,b修改值不会影响a

    ② 引用类型的变量直接赋值实际上是传递引用,只是浅复制

     var arr = [10,20,30];
     var array = arr;
     array[0] = 1;
     console.log(arr,array);

    输出结果arr和array都会是[1,20,30],要想实现深复制,必须在堆内存中再开辟一块空间

    (3) 值类型无法添加属性和方法

     var per = "web";
     web.age = 10;
     web.eat = function(){
         console.log('eating');
     }
     console.log(web.age);
     console.log(web.eat);

    结果都会返回undefined

    (4) 引用类型可以添加属性和方法

     var per = {};
     per.age = 18;
     per.eat = function(){
         console.log("eated");
     }
     console.log(per.age);
     console.log(per.eat);

    结果person.age=18,person.eat返回一个函数

    (5) 值类型的比较是值的比较,只有当它们的值相等的时候它们才相等。比较的时候注意””和”=”,双等号()在做比较的时候做了类型转换,而全等号(=)是值和类型相等是才能相等

     var stu1 = '{}';
     var stu2 = '{}';
     console.log(stu1===stu2);

    结果返回true,两个相同字符串的比较,是值(‘{}’)的比较,完全相等

    (6)引用类型的比较是引用地址的比较

     var stu1 = {};
     var stu2 = {};
     console.log(stu1===stu2);

    结果返回false,两个空对象在堆内存中的地址不一样,所以即使两个一模一样的对象也不一定相等

19.委托

委托属于引用类型,引用类型的默认值是null,直接使用的话会报错空异常;所以在使用之前需要去判断委托对象(引用对象)是否为空

系统内置Action委托

系统内置Func委托

System.Func可以不带参数,但是必须带一个返回值

System.Func若是调用多个泛型委托定义,最后的参数的数据类型时函数的返回值类型需要保持一致;非最后一个泛型T的声明需要与实现函数的参数个数及类型保持一致

Unity游戏开发(C#语法):委托-CSDN博客

20.event事件

1),event事件只允许作为类的成员变量且仅在类的内部使用才可以,外部不得直接调用

2).当作为A类的成员,event事件在外部类赋值时,只能通过+=的方法;而对于普通的Action则可以=/ += -=的方式进行赋值

21.unity的物理引擎是什么,什么作用

在 Unity 3D 内的 Physics Engine 引擎设计中,使用硬件加速的物理处理器 PhysX 专门负责物理方面的运算。Unity 3D 的物理引擎速度较快,还可以减轻 CPU 的负担。

Unity 3D 中的 Rigidbody(刚体)可以为游戏对象赋予物理属性,使游戏对象在物理系统的控制下接受推力与扭力,从而实现现实世界中的运动效果。

22.ue的蓝图是什么

蓝图可视化脚本,简称“蓝图”,是UE中的一项强力工具,在蓝图中我们可以进行可视化编程,当我们在使用蓝图的时候相当于我们在写代码。UE中的蓝图文件相当于游戏内容中的容器。

23.Unity协程和线程的区别

协同程序(coroutine)与多线程情况下的线程比较类似:有自己的堆栈,自己的局部变量,有自己的指令指针(IP,instruction pointer),但与其它协同程序共享全局变量等很多信息。

协程(协同程序): 同一时间只能执行某个协程。开辟多个协程开销不大。协程适合对某任务进行分时处理。 线程: 同一时间可以同时执行多个线程。开辟多条线程开销很大。线程适合多任务同时处理。 1.协程,即协作式程序,其思想是,一系列互相依赖的协程间依次使用CPU,每次只有一个协程工作,而其他协程处于休眠状态。协程实际上是在一个线程中,只不过每个协程对CUP进行分时,协程可以访问和使用unity的所有方法和component 2.线程,多线程是阻塞式的,每个IO都必须开启一个新的线程,但是对于多CPU的系统应该使用thread,尤其是有大量数据运算的时刻,但是IO密集型就不适合;而且thread中不能操作unity的很多方法和component

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

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

24.时间复杂度

各位学弟学妹,别再看教材了,时间复杂度看这篇就好了_时间复杂度和运行时间-CSDN博客

25.C#如何调用Lua

Lua与C#的相互调用(xLua)_xlua c#调用lua-CSDN博客

26.各种排序方式及其时间复杂度

史上最全八大排序讲解时间复杂度篇(0基础都能看懂)_八大排序时间复杂度-CSDN博客

1.冒泡排序,O(N^2)

2.插入排序,O(N^2)

3.希尔排序,O(N logN)

4.选择排序,O(N logN)

5.基数排序,O(kN)

6.快速排序,O(N logN)

7,归并排序,O(N logN)

8.堆排序,O(N logN)

27.Unity中切换摄像机视角

Camera中的Depth调整为0的为主摄像机视角

附自己写的切换摄像机的代码。

using System.Collections;
using System.Collections.Generic;
using UnityEngine;

public class CameraController : MonoBehaviour
{
    public GameObject player;
    public Camera MainCamera;
    public Camera ThirdCamera;
   
   
    void Start()
    {
        MainCamera.depth = 0;
        ThirdCamera.depth = -1;
    }
    public void Camera()
    {
        if(MainCamera.depth==0)
        {
            MainCamera.depth = -1;
            ThirdCamera.depth = 0;
        }
        else
        {
            MainCamera.depth = 0;
            ThirdCamera.depth = -1;
        }
    }

}

当调用Camera方法时,即可切换摄像机视角。

28.热更新方案

整包:

策略:完整更新资源放在包内

优点:首次更新少

缺点:安装包下载时间长,首次安装时间久

分包:

策略:包内放少量或者不放更新资源

优点:安装包小,下载快,安装极速

缺点:首次更新时间久

29.堆和栈的区别

堆:

堆是计算机科学中的一种数据结构,用动态分配内存空间。用于存储程序运行时动态创建的对象和数据。与栈不同,堆的内存分配和释放不是由编译器自动管理,而是由程序员手动控制。

在堆中分配内存可以使用诸如malloc、new等函数或操作符。当不再需要这些内存时,程序员需要显式地释放它们,以避免内存泄漏。堆的好处是可以动态地分配和释放内存,使程序更加灵活。

堆还可以用于实现一些高级数据结构,如二叉堆、斐波那契堆等。这些数据结构在算法和数据处理中起到重要作用,例如优先队列、堆排序等。

栈:

栈是由编译器在需要时自动分配,不需要时自动清除的变量存储区。通常存放局部变量,函数参数等。栈有静态分配和动态分配,静态分配由编译器完成(如局部变量分配),动态分配由alloca函数分配,但栈的动态分配的资源由编译器进行释放,无需程序员实现。

  • 3
    点赞
  • 2
    收藏
    觉得还不错? 一键收藏
  • 0
    评论
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值