FPS游戏项目人物系统阶段总结
该项目阶段主要完成了人物的各类基本逻辑,包括移动、奔跑、移动视角、瞄准、射击、换弹等,有默认、行走、奔跑、瞄准四种状态;同时完成了武器的各类逻辑包括开火、停火、换弹、射线检测、命中特效等,有默认、开火、换弹三种状态,分为武器基类(枪械通用模板)和VIRTUS子类(具体枪械);制作了简易的UI,用于显示当前武器和子弹数量。
这个项目大部分的逻辑实现还算比较基础,所以就挑一些细节和新学到的思路记录,以及总结自己遇到的问题和自己新加的功能。
人物
- 移动:控制器+类型转换来获取玩家控制器,使用获取控制器而不是获取玩家控制器,是为了避免出现联机时,因为玩家index在逻辑里写死了,然后去获取其他玩家的角色的情况出现,直接获取控制器就不会出现这种情况;为什么要加一个类型转换呢,有时可能会出现让AI去控制角色的情况,加上类型转换是为了保证,只有真正的玩家控制角色时,才会绑定增强输入本地玩家子系统。
- 玩家移动方向:方向当然是摄像机的向前向量,但是如果获取全部方向的向量的话,就会出现玩家抬头或者低头是走不动的情况出现,所以我们只获取垂直于z轴(Yaw)的方向向量,其他方向设置为0,这样无论玩家视角上下有多大的角度都不会影响水平方向的移动。
- 摄像机视场(FOV):类似于一个以摄像机为顶点向外扩散的金字塔形区域,被称为视锥体,FOV的数值越大,水平方向张开的角度就越大,看到的画面范围就越广。当调小FOV数值时,截取范围会变窄,但是被截取的场景要填满整个屏幕,所以引擎会把这部分拉伸铺开,从而产生放大的效果。此外,FOV可以在局内动态调整,也就实现了倍镜放大缩小的效果。
武器
- 命中检测:与我之前做的2D游戏不同,这种游戏主要使用射线追踪来判定是否打中了东西,打中了什么东西,在哪里打中了东西等等,然后生成对应的效果。
- 后坐力:其实很简单,就是每次开枪时给摄像机pitch一个向上的角度,然后给yaw左右小幅度的随机角度。
- 动画通知:是一种将逻辑事件与动画序列同步的机制,可以在动画播放时的某一特定时刻自动触发特定的效果或代码逻辑。在此项目阶段中,用于确保更新子弹数量的时刻和新弹匣插进枪械中的时刻相同。
- 蓝图接口:用于发送消息,来触发后续逻辑。本项目中用于当玩家开火射击时,调用开火接口通知武器要执行开火逻辑,武器接收到后便执行开火相关逻辑。还用于我自己添加的通知玩家武器换弹结束,可以重置音效播放了。具体写在后面。
遇到的问题及解决方法
- 判断节点的上下顺序问题:具体哪个位置触发的忘记了,总之特别搞,蓝图中像
<、>等比较节点是有顺序的,比如>,就是上面的节点如果大于下面的节点则为真,我之前搞反了,导致判断条件一直不对。 - 更新当前弹匣和总备弹时,总备弹数量不变的问题:一开始是先更新当前弹匣,总备弹再减去弹匣容量和当前弹匣的差,这时发现因为更新顺序的问题,每次总备弹减去的都是0,要先更新总备弹,再更新当前弹匣。
新添加功能:开火后长按鼠标左键不松手,换弹后能直接衔接射击
实现:很简单,只需要在角色 EnhancedInputAction IA_Fire 的 Trigger 引脚后连上开火的信号就行,但是因为老师的结构是没考虑到这方面的功能的,所以后续引发了一些bug。
实现过程:在自己测试的时候发现,无法保持换弹前后左键不动一直开火,感觉手感怪怪的,所以打算做这个。正如上面所说,实现很简单,但是出现了第一个问题,我射空弹匣后会一直播放空弹匣的音效,非常鬼畜,这是我想到用 Do Once 来限制音效播放只能有一次。但是 Do Once 没有 Reset 信号进入,且Actor未销毁重刷时,只会执行一次后面的逻辑,导致了空弹匣音效只能播放一次。于是我想直接加个 Reset Sound 自定义事件,来让玩家那边调用此事件决定什么时候 reset Do Once。之后想到,应该是一次换弹前只能触发一次音效(长按时),而每次点按都应该触发音效,所以在角色 EnhancedInputAction IA_Fire 的 start 引脚连接的射击逻辑最后加上 Reset Sound 就行了。单次触发的问题解决了,但是长按的问题还是没解决,突然我想到可以做一个接口,让武器换完弹后通知角色,于是在角色蓝图新建 resetsound 布尔变量,当武器换完弹时,把它设置为 true,当角色接收到枪械换弹结束的信号时,若 resetsound 为 true,则执行 Reset Sound 事件,然后把 resetsound 设为 false,这样就保证了一次换弹只能触发一次音效。
因为我一开始写新功能的时候前置判断很多,我在复盘的时候发现判断似乎没有必要,于是全删了,测试完之后发现也没有问题,结果导致了我另一个bug,也就是长按开火换弹再射空弹匣后第一次点按没有音效的问题也一并修好了。其实我也解决了这个bug,但是再次复盘时发现似乎不会出现这个bug,于是删除了我之前写好的方法,发现bug消失了。也是很神奇了。
这个项目更接近开发时的项目管理和规范,而且要做的地方很多,除去单纯的逻辑,还有动画、特效与蓝图的耦合,总体来说受益匪浅,基本学会了蓝图的用法,接下来准备开始U++的学习了。