上篇我写了一些自己在学习Unity的过程中,升级老的项目所碰到的一些问题以及解决方法。过程看起来比较简单,但是其实过程中我是走了很多弯路的。主要原因是我是刚刚才接触Unity,对它还不是很熟悉,另一方面如何升级Unity工程,这方面的资料是真的少的可怜(可能是我没找到),只能自己瞎摸索,好在我也搬过十年砖,这点小问题,应该没问题的吧。
下面开始正题,说说我都走了哪些弯路
1.没看manifest.json,没安装依赖包,导致项目里很多GameObject挂载的一些Components没有识别出来
与其说这个是没看manifest.json,到不如说是我对Unity工程的结构没有做好功课。在接触Unity之初,我也找过新手入门之类的文档,官方的Manual也大致浏览了一遍,大致知道Package Manager这个功能,也知道如何使用它安装依赖包,但是我没有在升级工程过程的第一步去做这个事情。结果Scene里面很多GameObject挂载的Component是无法识别出来的,如下图:
有两个Script类型的Component无法识别。无法在Scene中找到它的引用,也无法编辑Script。
到这里我就束手无策了。我没有继续硬刚,而是选择先解决其他问题,这个暂时先放着。
这种Script类型的Component问题,还有一种情况,就是能识别出脚本文件,只不过脚本里面有编译错误,如下图:
这里能识别出是Settings这个脚本文件,这个就比较好办了,起码我知道是哪里出了问题,不像上面那种情况,完全摸不着头脑。
2.没提前了解项目大致逻辑
我升级过好几个项目,耗时最长的应该算是AngryBots_ECS,项目
github
。这是一个教你如何将老的项目转换成新的DOTS项目,以及如何使用DOTS替代之前的低性能代码。我是在看DOTS和ECS相关的资料的时候知道这个项目的,看过这个项目的演示视频,映像最深的就是视频里做了一个对比,就是没有使用DOTS技术时,玩家发射比较多的子弹时,FPS就降到个位数,但是使用DOTS技术后,玩家很多颗子弹,屏幕上同时出现几万颗子弹都不会出现明显的性能下降,FPS依旧很稳定。所以我决定下载下来玩一下。 所以到目前为止我对这个项目的认识就是,它是一个射击类的项目,3D的,什么Render Pipeline我不知道,项目里既使用了DOTS技术,同时也包含了传统的GameObject,以及如何将两者结合。可以用键盘操作角色移动,游戏会随机生成怪兽,朝向玩家爬行,玩家开枪射击怪兽,子弹会显示弹道效果。 这里面还用到了PostProcessing,Cinemachine,物理引擎,粒子系统,还有一些设置是需要在Project Settings里做的,如果是新建工程的话,这些设置我可能就不知道怎么同步过来了。
3.对新技术了解程度不够深就开始修改工程
拿AngryBots_ECS这个项目来说,由于我对DOTS技术了解非常肤浅,只是大概知道ECS模式的知识,还有一点点Job System相关的知识。工程中有一些脚本使用的API,在新版本标记为Deprecated,我在使用新API去替换它时,忽略了一些很重要的细节,导致后面虽然工程能运行起来,但是有一些很诡异的bug,耗费很多时间最终才定位到。 比如下图这个:
这里使用的IJobForEach在新版本中标记为Deprecated,我准备使用Entities foreach替换它,然而在替换的时候忽略了很重要的细节,就是这个代码本来只应该对有EnemyTag的Entity起作用,但是我在新写的Entities foreach里忘了这个关键点,虽然代码能运行起来,但是却非常诡异。那就是当Player活着的时候,Player打出去的子弹始终在Player的腰部,无法射出去,但是Player死后,子弹却能正常的飞行出去。所以我就一直在找哪些地方的逻辑和Player的Dead状态有关。下图是在代码里查找IsPlayerDead引用的结果:
一共有6个地方,其中Enemy相关的两个可以直接排除,Settings是定义这个方法的地方,也排除,就剩下CollisionSystem、PlayerTransFormUpdateSystem、TurnTowardsPlayerSystem三个了。 当然还有很重要的就是PlayerMovementAndLook,这里是有PlayerDied相关的逻辑。
最开始怀疑是碰撞系统导致,我的思路大概是这样的,Player或者的时候是参与碰撞检测的,而死了之后不参加碰撞检测。有可能子弹在发射的时候,出生的点就立即和Player发生碰撞,导致子弹要被销毁掉。
于是我通过各种办法修改子弹的发射点,比如修改Player中的子弹发射点SpawnPoint的位置,同时还有直接在代码中强行给子弹实例化时的初始点加偏移量,如下:
当然这些都没有成功,子弹依旧在Player的腰间闪烁并于2s之后消失。
接下来我又尝试直接将Player设置为不参与碰撞检测,同时不应用重力(应用重力但是又碰撞,地板对Player就不起作用,Player直接自由落体了),依然没有作用。
Player这边能做的尝试都试过了。那我就往CollisionSystem.cs上找问题。
CollisionSystem里和PlayerDied相关的逻辑:
1.如果Player已死,则只检测Enemy和Bullet 2.如果Player还活着,检测Enemy和Bullet,同时还要检测Player和Enemy的碰撞
压根就没有Player和Bullet的碰撞,虽然是这么说,但是我还是抱着试一试的心态,在这里不论isPlayerDead与否,都直接return jobHandle,然而并没有什么用,所以这个系统没什么问题。
最后就只剩下TurnTowardsPlayerSystem了。 这里有一个背景我先说明一下,因为在排查这个问题的时候,工程里的ECS相关的代码我是修改过的,因为ECS相关的Package是新的,而代码里使用的API都是很老的,所以最开始工程是有编译错误和警告的,那么我最先解决这些问题,所以修改了很多代码(学艺不精,改出了很多问题T,哎,都是泪)。 还有一个事情就是我没有在最开始使用Git来管理工程,这样我就无法准确知道我到底修改了哪些代码,只有到后来我用了一个笨办法,就是一边用SublimeText打开原始的老工程,一般用VS修改这新工程,对比着看 。当然这个是后话了。开始的时候就没想到是我修改代码改出来的bug,一直以为是代码本身的问题,主要是我改代码的时候也没改逻辑,只是换API而已,蜜汁自信。但是我又一直有个疑问,为什么人家用同样的代码就能运行起来呢,照理说,这代码逻辑应该没问题啊。所以这代码到底有没有问题?管他三七二十一,上手改一改,看看效果。
这是原始代码。从类名我们可以推测出它是处理游戏里的对象转向玩家的逻辑,也就是所有敌人都朝向玩家,它只负责调整朝向,就这么简单。我们可以看它的OnUpdate方法,如果玩家已死,就什么都不做直接返回inputDeps,否则就运行TurnJob。意思就是如果玩家死了,那么敌人就不需要朝向玩家了,它们保留这玩家dead那一瞬间,它们各自的朝向就行。 终于找到问题的根源了,那怎么改呢? 当时是因为IJobForEach这个接口Deprecated所以我才觉得改成Entities foreach,但是我还不知道怎么在Entities foreach的时候过滤掉非EnemyTag的entities,所以暂时还是还原代码,后面学会了新的API后再改。 到这里子弹不飞的bug算是解决了吧。那么我接下来再去解决其他问题。
其他问题
镜头不跟随Player的问题
就是我用wasd或者方向键控制玩家在平台上移动时,镜头要跟随玩家,保证玩家一直在屏幕中心。如果没有这个逻辑,那么镜头一直保持不动,玩家移动到镜头视野之外的话,就看不到玩家在干什么了,如何杀敌呢?
通过观察scene的hierarchy,我发现Cameras里有两个Camera,一个是虚拟的摄像机VCam(Virtual Camera),还有一个就是主摄像机(Main Camera),VCam后面写了Follow Player,就是它了。 看到这我还是无从下手,因为我还不知道这两个Camera具体是如何协同工作的,也不知道这个项目用的是什么技术(后来才知道用的是Cinemachine),因为这种镜头跟随效果可以用代码实现,也可能用其他方法实现,具体还有哪些,我是真不知道啊,完全的小白。
那么我选中VCam,在Inspector中看到它有个Script Component没有被识别出来,就是在文章开头我提到的,不知道Script的文件名的那种,如下图:
我只能开动脑筋想办法弄明白这个到底是怎么回事。
我的想法是这样的,Scene里保存了所有的东西,既然Unity知道这个VCam挂载了一个Script类型的Component,那么肯定有地方记录了这个信息,然后Unity解读到了,但是Unity又不认识这个Script是什么,很奇怪是不是?那我就想,如果我自己找到这个记录了Scene里所有信息的文件,打开看看,兴许能找到点什么信息。于是我用SublimeText打开了ECS Shooter.unity文件:
打开后长这样:
很好,YAML文件,虽然不是很熟悉,但是看起来还是很亲切的。
线性存储结构表示树状结构,那么节点里包含父子节点信息:
符合常理。接下来我们就直接找到VCam,上图里就包含了它,它有两个Component,220979867和220979868,分别是Transform和一个不知道是什么类型的Script,这不正是我要找到吗,没想到这么顺利。
一开始我就盯着fileID看,发现这个fileID 11500000在scene里搜不到,guid也搜不到,我就怀疑是不是工程里就是把这个script文件给搞丢了?同时我又反驳这个怀疑,别人为啥能运行,就你下载的工程不能运行?于是我google了一下这个fileID,有篇文章大致讲了,应该说它讲了,但是我大致理解了fileID不可靠,用guid匹配才准确,也有道理哈。可是我用guid也搜不到啊,这就比较尴尬了。直到后面我往下看到了Cinemachine,突然茅塞顿开,里面回过头去看老工程的manifest.json文件,果然依赖了Cinemachine,突然开心的像个300斤的胖子。
同样的Main Camera下面也挂载了Cinemachine相关的两个script,如图:
我用同样的方法解决了它。
PostProcessing问题
这个问题说实话,我到现在还没解决。虽然我把下面这个问题给解决了,但是我配置的Bloom效果并没生效
所以我又怀疑是不是Project Settings方面少了什么东西,因为工程是我新建的,可能很多设置并没有同步到新工程里来。后面我再查一下到底是怎么回事,一方面查一下PostProcessing需要在什么样的工程里才能用,另外一方面可以查查老工程里的ProjectSettings文件夹里的那些配置文件。如果有知道的小伙伴,请留言告诉我。
Shader问题
升级后,Ground和Player都是红色的,明显是渲染不正确,还有Bullet和Enemy这两个是Prefab也渲染不正确
我就分别找到它们,查看它们的Shader,凭感觉修改一下,先保证能渲染出来。其实应该有一个对照表,我懒得去找了,因为我都不知道它之前用的是什么Shader,就算有升级Shader的对照表,我也不知道查什么,所以干脆凭感觉调一调(偷个懒还很有理由)。 如果你知道正确的Shader,也请留言,谢谢。
1769

被折叠的 条评论
为什么被折叠?



