个人Unity自用面经(未完)

目录标题


豆包 中等偏上—优秀 评价

1.在 2D 平台跳跃游戏项目中,你使用了对象池来生成和回收怪物包含阵亡的动画预制件。在对象池回收对象时,如何确保动画状态被正确重置,避免下次使用时出现异常?

答:我在泛型对象池定义之初就设置了一个私有的抽象Reset函数,对于后续继承它的对象池必须要实现它,然后在对外公开的回收预制体函数ReturnToPool中调用这个Reset函数,这样来保证他们状态复原,避免异常。比如我在Reset中重新设定这个预制体的动画机中所有的转换条件参数复原,Transform属性复原,并且在Reset函数里使用了Try和catch来捕获重置失败的预制体。

2.在僵尸吃脑子模拟项目中,你创建了继承于IAspect的aspect,并通过RefRW和RefRO定义访问的属性。能详细说说在实际使用中,RefRW和RefRO有什么区别吗?在什么场景下分别使用它们?

答:Ref RW对应的就是ref关键字, read and write,RO 对应的就是 read only,意思就是前者是一个可读写的属性,后者是一个只可读的属性,这要根据需求来用,比如我项目里写了僵尸的行走速度,我不希望他改变所以我把aspect里面对僵尸速度属性的引用设置为只读的意味着我不希望改变他,比如项目中墓碑的Transform属性,我希望每个墓碑生成的位置角度是不一样的所以我设置他为可读写的。

3.在 2D 平台跳跃游戏项目中,你使用对象池来生成和回收怪物预制件。在对象池的设计与实现过程中,如何确定对象池的初始容量和最大容量呢?

答:初步预估对象池容量
统计游戏数据:在设计阶段,仔细分析游戏场景和玩法,统计出游戏中不同类型对象(如怪物、子弹、道具等)同时出现的最大数量和常见数量。例如在一个射击游戏中,统计一场战斗里最多会同时存在多少颗子弹,一般情况下又会有多少颗子弹。
考虑扩展系数:为了应对游戏中可能出现的特殊情况,如玩家触发特殊技能、进入特殊关卡等导致对象数量突然增加,需要在最大数量的基础上乘以一个扩展系数(通常为 1.2 - 1.5),以此确定对象池的最大容量。初始容量可以设置为常见数量的均值。
游戏测试阶段的性能监测
选择合适的监测工具:在 Unity 中,可以使用内置的 Profiler 工具来监测对象池的使用情况,它能提供详细的内存使用信息、对象创建和销毁的频率等数据。
关注关键指标:重点关注对象池的扩容次数、闲置对象数量、对象创建和销毁的时间等指标。如果对象池频繁扩容,说明初始容量设置过小;如果大部分时间对象池都有大量闲置对象,说明最大容量设置过大。
根据监测数据进行动态调整
增大初始容量:如果发现对象池频繁扩容,导致游戏性能下降,可以适当增大初始容量。例如,将初始容量增加 20% - 30%,然后再次进行测试,观察性能是否有所改善。
减小最大容量:如果对象池大部分时间都有大量闲置对象,占用了过多的内存,可以考虑减小最大容量。每次减小的幅度不宜过大,建议在 10% - 20% 之间,然后重新测试,确保不会影响游戏的正常运行。

4.在 3D 回合制策略游戏中,你使用了状态机实现敌人的 AI,并且 AI 的行为带权。在不同情况下,不同动作的权值是如何确定的呢?

答:
我的项目中敌人和友军都是继承自player这个父类的,所以他们能使用的动作是一样的,对于敌人他有移动,射击,手雷。3个动作,我把移动的权值设置成10 - 可攻击范围内敌人的数量 * 3,这样如果范围内有敌人那么他们就不更容易去移动,对于射击权值就是 8,手雷权值是8 + (可攻击范围内敌人的数量 - 1) * 2,于是在有敌人且只有一个的情况下会使用射击,有敌人且有多个的情况下会使用手雷,没有敌人的情况下会使用移动,同时攻击还跟敌人剩余的血量有关,对于移动还要计算每个可到达的地点的权值不同于之前的权值系统,它会优先选择更多可接触敌人的地点到达,这些其实都只和设计者的需求来设定。

5.在僵尸吃脑子模拟项目里运用了 ECS 架构,你也清楚 ECS 架构适合并行计算。那在实际开发中,是怎样去利用 ECS 架构实现并行计算,进而提升游戏性能的呢?

答:
首先建立一个Job : IEntityJob,把这个job需要用到的所有东西比如EntityCommandBuffer.ParallelWriter如果不是并发的那么不用使用ParallelWriter(ecb用于更改实体组件,生成实体等)可以暂存某些指令等到某个时间点一起执行以免出现并发的线程争夺和数据错读问题,还有一些数据,或者实体。然后实现这个Job的Execute方法,如有需要还要提供sortKey这个参数,在调用这个作业的时候会自动检索含有Execute带有的组件的实体,并且在运行的时候给他发配一个sortKey。最后只需要在调用这个任务的system中new这个job,然后给他提供所需要的参数比如使用SystemAPI.Getsingleton,GetComponent等等,用来new这个job并且调用它,需要注意的是在EntityCommandBufferSystem创建EntityCommandBuffer的时候要AsParallelWriter否则会报错,这里state作用是在非托管世界申请一个命令缓冲区并且视为并发写者来缓存并执行并发的命令,因为要并发执行,最后在new的尾处.ScheduleParallel()进行并发执行任务。

避免在一个任务中修改另一个任务需要读取的数据

6.在 2D 平台跳跃游戏项目中,你使用了 TileMap 瓦砾地图系统构建地图。在使用过程中,如何实现地图的动态加载与卸载,以优化游戏内存占用?

答:
地图分块处理
划分地图区域:把整个游戏地图按照一定规则划分成多个小的地图块,比如以正方形或矩形区域为单位。每个地图块都可以独立加载和卸载。例如,在一个大型的 2D 平台跳跃游戏世界中,可以将其划分为多个 10×10 个 Tile 的地图块。
确定加载范围:依据玩家当前所在的位置和视野范围,确定需要加载的地图块。一般来说,除了玩家当前所在的地图块,还需要加载其周围的一些地图块,以保证玩家移动时地图的连贯性。比如,玩家在一个地图块中,那么可以同时加载其上下左右以及四个对角方向相邻的地图块。
实现动态加载与卸载机制
加载逻辑:当玩家接近某个未加载的地图块时,触发加载操作。可以使用 Unity 的场景加载 API(如 SceneManager.LoadSceneAsync )来异步加载地图块。异步加载不会阻塞主线程,能保证游戏的流畅性。在加载时,还可以显示一个加载提示,提升用户体验。
卸载逻辑:当某个地图块远离玩家的视野范围,并且在一段时间内不会被玩家访问到时,触发卸载操作。使用 SceneManager.UnloadSceneAsync 来异步卸载地图块,释放内存。
缓存机制
临时缓存:为了避免频繁的加载和卸载操作,可以设置一个缓存区,将最近使用过的地图块暂时保留在内存中。当玩家再次需要访问这些地图块时,可以直接从缓存中获取,而不需要重新加载。
缓存淘汰策略:由于缓存区的容量是有限的,当缓存区达到最大容量时,就需要移除一些数据来为新的数据腾出空间。常见的淘汰策略有先进先出(FIFO)、最近最少使用(LRU)等。

7.在 3D 回合制策略游戏中,你使用了状态机来管理角色的行为状态。当角色的状态比较复杂,存在多种状态之间的相互转换,并且有一些状态还存在子状态时,你是如何设计状态机以确保逻辑清晰,易于维护和扩展的呢?

答:我使用状态机系统来维护我的状态,状态机内部只有 state currentstate,两个公开的方法public void changeState(State stateName)和public void Initial,然后每个state都继承自Istate必须实现Istate里的抽象方法,Enter,Exit,Update,然后在FSM类里创建一个枚举类State用于枚举每个状态的名字,和一个字典关联 State state 和 Istate theState,然后FSM里包含对状态机的声明,并且有AddState方法用于往字典里添加状态,在声明fsm变量的脚本中的Onupdate调用currenState.Update,这样就可以确保状态之间的模块化和解耦而且扩展方便,维护方便。子状态也同样可以这样使用和添加,确保同一个时间只有一个状态在执行。

8.在僵尸吃脑子模拟项目里,你运用了 ECS 架构。当游戏场景中僵尸数量极多,比如上万只时,可能会面临性能瓶颈。你打算采取哪些策略来优化 ECS 架构下大规模僵尸的性能表现呢?

答:
空间分区与裁剪:
将游戏场景划分为多个空间区域,比如使用**四叉树(2D 场景)或八叉树(3D 场景)**结构。为每个僵尸分配所属的区域,当进行渲染、碰撞检测或 AI 计算时,只处理玩家所在区域及相邻区域内的僵尸。例如,玩家在一个特定房间内,只计算该房间及其相邻房间内的僵尸,避免对整个场景中所有僵尸进行不必要的操作。
对于视野范围外的僵尸,不进行渲染和复杂的 AI 计算,只保留基本的位置追踪等轻量级信息,当僵尸进入玩家视野范围时再进行完整的处理。
批处理与合并:
在渲染方面,将多个僵尸的渲染数据合并成一个批次进行绘制。利用 GPU 的批处理功能,减少 Draw Call 的数量。比如,可以将相同类型、相同材质的僵尸的顶点数据、索引数据等合并,一次性提交给 GPU 进行渲染,提高渲染效率。
对于僵尸的物理碰撞检测,可以将多个僵尸分组,对组内的僵尸进行统一的碰撞检测处理,而不是逐个僵尸进行检测,减少碰撞检测的计算量。
优化组件与数据结构:
确保僵尸的组件设计简洁,只包含必要的数据和功能。避免在组件中存储过多冗余或不常用的数据。例如,如果僵尸的某个属性只在特定情况下使用,可以考虑在需要时动态获取,而不是一直存储在组件中。
选择合适的数据结构来存储僵尸相关的数据。例如,使用数组而不是链表来存储僵尸列表,因为数组在随机访问和遍历方面通常具有更好的性能。同时,可以对数据进行预排序,以便在进行某些计算(如距离排序)时提高效率。
并行计算与多线程优化:
充分利用 ECS 架构的并行计算优势,将僵尸的 AI 计算、物理模拟等任务拆分成多个并行任务,利用多核 CPU 进行加速。例如,为每个僵尸的 AI 行为计算创建一个 Job,通过 ScheduleParallel() 方法并行执行这些 Job。
注意避免多线程之间的资源竞争和数据冲突。合理使用锁机制或无锁数据结构来保护共享资源。例如,对于僵尸的生命值等共享数据的修改,使用线程安全的方式进行操作。
LOD(Level of Detail)技术:
为僵尸设置不同的细节层次模型。当僵尸距离玩家较远时,使用低细节模型,减少模型的顶点数量和纹理复杂度,降低渲染成本。当僵尸靠近玩家时,切换到高细节模型,提供更好的视觉效果。
同样,对于僵尸的 AI 行为也可以设置不同的细节层次。例如,远处的僵尸可以采用简单的巡逻行为,而近处的僵尸则执行更复杂的追逐和攻击行为。

9.在你参与的 “3D 回合制策略游戏” 项目里,你使用了状态机实现敌人的 AI 且行为带权。在游戏运行过程中,如果玩家做出了一个游戏设计师未曾预料到的操作,导致敌人 AI 的权值计算出现异常,你会如何排查和解决这个问题?

答:
我应该会在敌人AI采取行动的使用使用Try和Catch去捕捉错误,如果没有捕捉到说明没有语法上或者访问越界等的问题而是逻辑上的问题,那么如果是后者只能去跟随敌人状态机进行一步一步的调试,如果它引起了空间或者性能问题那么可以使用性能检测工具profile来检测哪个函数或者哪个部分出现了内存性能异常。

10.在 “僵尸吃脑子模拟” 项目里,你使用了 ECS 架构并创建了多个继承于ISystem的系统。当多个系统之间存在数据依赖关系时,你是如何管理和协调这些依赖关系,以确保系统执行顺序正确且数据一致性的?

答:
在ECS架构中不像Unity自带一个脚本执行顺序的调整功能。在ECS架构中你运行项目的时候如果先后顺序有问题那么大概率会报错并且无法运行,届时你可以到Windows->Entities->System中查看每个系统的执行时间,但是这里不像unity原生开发框架可以直接拖动,你必须到每个系统中使用UpdateInGroup(typeof(InitializationSystemGroup))此处可以替换为很多ECS内定好的系统组或者UpdateAfter,Before某个System来调整它们的执行顺序。通过这个动作来保证依赖的关系不会出现问题,比如我项目中僵尸生成系统就定义了[UpdateAftertypedef(TombStoneSpawnSystem)]因为我僵尸生成的位置依赖于墓碑生成的位置。
避免循环引用导致相互依赖,可以设置中间层来接收相互依赖之间的数据避免直接依赖来解耦,或者调整循环依赖之间的关系,让其中一个不再引用环中的数据。
在这里插入图片描述

内容概要:本文档详细介绍了Android开发中内容提供者(ContentProvider)的使用方法及其在应用间数据共享的作用。首先解释了ContentProvider作为四大组件之一,能够为应用程序提供统一的数据访问接口,支持不同应用间的跨进程数据共享。接着阐述了ContentProvider的核心方法如onCreate、insert、delete、update、query和getType的具体功能与应用场景。文档还深入讲解了Uri的结构和作用,它是ContentProvider中用于定位资源的重要标识。此外,文档说明了如何通过ContentResolver在客户端应用中访问其他应用的数据,并介绍了Android 6.0及以上版本的运行时权限管理机制,包括权限检查、申请及处理用户的选择结果。最后,文档提供了具体的实例,如通过ContentProvider读写联系人信息、监听短信变化、使用FileProvider发送彩信和安装应用等。 适合人群:对Android开发有一定了解,尤其是希望深入理解应用间数据交互机制的开发者。 使用场景及目标:①掌握ContentProvider的基本概念和主要方法的应用;②学会使用Uri进行资源定位;③理解并实现ContentResolver访问其他应用的数据;④熟悉Android 6.0以后版本的权限管理流程;⑤掌握FileProvider在发送彩信和安装应用中的应用。 阅读建议:建议读者在学习过程中结合实际项目练习,特别是在理解和实现ContentProvider、ContentResolver以及权限管理相关代码时,多进行代码调试和测试,确保对每个知识点都有深刻的理解。
开发语言:Java 框架:SSM(Spring、Spring MVC、MyBatis) JDK版本:JDK 1.8 或以上 开发工具:Eclipse 或 IntelliJ IDEA Maven版本:Maven 3.3 或以上 数据库:MySQL 5.7 或以上 此压缩包包含了本毕业设计项目的完整内容,具体包括源代码、毕业论文以及演示PPT模板。 项目配置完成后即可运行,若需添加额外功能,可根据需求自行扩展。 运行条件 确保已安装 JDK 1.8 或更高版本,并正确配置 Java 环境变量。 使用 Eclipse 或 IntelliJ IDEA 打开项目,导入 Maven 依赖,确保依赖包下载完成。 配置数据库环境,确保 MySQL 服务正常运行,并导入项目中提供的数据库脚本。 在 IDE 中启动项目,确认所有服务正常运行。 主要功能简述: 用户管理:系统管理员负责管理所有用户信息,包括学生、任课老师、班主任、院系领导和学校领导的账号创建、权限分配等。 数据维护:管理员可以动态更新和维护系统所需的数据,如学生信息、课程安排、学年安排等,确保系统的正常运行。 系统配置:管理员可以对系统进行配置,如设置数据库连接参数、调整系统参数等,以满足不同的使用需求。 身份验证:系统采用用户名和密码进行身份验证,确保只有授权用户才能访问系统。不同用户类型(学生、任课老师、班主任、院系领导、学校领导、系统管理员)具有不同的操作权限。 权限控制:系统根据用户类型分配不同的操作权限,确保用户只能访问和操作其权限范围内的功能和数据。 数据安全:系统采取多种措施保障数据安全,如数据库加密、访问控制等,防止数据泄露和非法访问。 请假审批流程:系统支持请假申请的逐级审批,包括班主任审批和院系领导审批(针对超过三天的请假)。学生可以随时查看请假申请的审批进展情况。 请假记录管理:系统记录学生的所有请假记录,包括请假时间、原因、审批状态及审批意见等,供学生和审批人员查询。 学生在线请假:学生可以通过系统在线填写请假申请,包括请假的起止日期和请假原因,并提交给班主任审批。超过三天的请假需经班主任审批后,再由院系领导审批。 出勤信息记录:任课老师可以在线记录学生的上课出勤情况,包括迟到、早退、旷课和请假等状态。 出勤信息查询:学生、任课老师、班主任、院系领导和学校领导均可根据权限查看不同范围的学生上课出勤信息。学生可以查看自己所有学年的出勤信息,任课老师可以查看所教班级的出勤信息,班主任和院系领导可以查看本班或本院系的出勤信息,学校领导可以查看全校的出勤信息。 出勤统计与分析:系统提供出勤统计功能,可以按班级、学期等条件统计学生的出勤情况,帮助管理人员了解学生的出勤状况
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值