上一篇我们实现了角色射击相关的动画以及切换逻辑,并将武器相关的模型添加到角色身上。
这一篇开始制作武器相关的功能。
制作子弹父类
首先创建一个actor类,命名为BP_Bullet,这个作为子弹的通用父类,在里面创建子弹通用的功能实现。
然后在里面创建一个子弹的碰撞体,作为碰撞检测,被子弹的碰撞体接触到的敌方角色将会受到子弹的伤害。
碰撞体有三种,球型,立方体和胶囊
对于子弹,我们选择球型或者胶囊体都可以,在这里,我用了球型,然后在碰撞题啊下面添加一个网格体,作为子弹模型的位置。
碰撞体作为碰撞检测,静态网格体只是为了作为子弹的展示,所以需要将其的碰撞检测关闭
接着,再添加一个发射物移动组件,给子弹提供移动
然后给移动组件配置初始速度,子弹的速度可以达到700米每秒,ue里面的单位是毫米,所以再加三个零。
然后再项目设置中,打开碰撞栏,添加碰撞相关的通道,这样做的目的是为了减少不必要的碰撞检测,提高性能。碰撞体,可以根据你的对象类型以及通道来进行筛选。
接着,将子弹的碰撞体的碰撞预设改为自定义,不使用系统预设的那些
在碰撞已启用选项设置启用碰撞,这样可以实现碰撞时进行检测
接下来,要将碰撞类型改为我们设置的Bullet类型,并将场景内的物体设置成阻挡,忽略是不会触发事件,碰撞只是产生碰撞事件,但还是会穿越物体,阻挡是触发碰撞以后,就会停止移动。
在事件列表创建事件命中事件,命中事件可以子弹接触到物体以后,将执行此事件,并将数据返回。
相关返回的参数有自身组件,碰撞物体对象以及组件,自身是否移动,以及碰撞位置和朝向等信息
在子弹命中处生成弹孔
实现子弹命中处生成弹孔的功能,我们需要用到系统内置的贴花功能。
首先创建一个贴花材质,贴花的材质只是简单的使用了一张纹理贴图,将材质修改成了贴花材质
纹理,只有alpha通道有值,可以作为透明强度,这样就表现出来了弹孔的效果,以及被子弹击中熏黑的效果
在命中事件触发后,使用内置节点 生成贴花,可以配置项,贴花材质,尺寸,位置,旋转,以及显示时间,到期自动销毁
设置当前的值,让贴花在击中位置生成,然后将击中的法向转换为当前贴花的旋转角度,存在时间设置20,如果为0,将永久存在
实现不同的表面产生不同音效
这个功能在于子弹命中不同的表面产生不同的音效,或者角色走在上面产生不同的脚步声。我们在ue里面可以通过物理材质来实现当前的效果。
打开项目设置的物理,添加一些不同的物理表面类型
Metal 金属
Gravel 碎石表面
Concreate 水泥表面
Wood 木头
Rock 石头表面
Grass 草地
接下来,创建一个函数,用来判断不同的物体击中不同的表面后产生的音效
函数添加一个参数命名为Hit,将外部碰撞得到的结果传递给函数,类型需要修改为命中结果。
然后使用中断命中结果,可以从参数中提取数据
将下方箭头打开,可以查看到更多的数据
接下来使用按通道进行球体追踪,我们可以剔除掉那些别的通道的模型
你需要给他一个起点和终点,以及检测的半径,还有检测的通道是我们之前定义的通道。
大家要注意检测相应和物体响应的区别,检测相应这里区域会被当前节点影响,物体响应只是物体和物体之间的碰撞的检测。
然后获取第一个结果的表面类型
它是一个枚举值,我们可以通过获取到枚举值进行判断,根据值的结果进行分线程执行
接着,我们可以通过分支去播放不同的粒子特效以及声效
首先创建粒子特效,创建再位置处生成发射器
我们需要修改它的粒子,位置以及朝向,这两个使用击中的位置和击中的法向转成旋转角度即可。
粒子特效的效果下图显示。
我们还需要在击中处播放一个音效,使用播放位置处音效,顺便我把播放粒子特效和音效封装成了一个函数,这样方便代码结构的查看。
然后,根据枚举调用相应的函数参数,它们的区别就是特效和音效不同,我们可以根据注释查找相应的节点去修改即可。
接下来在事件列表调用此函数,并将命中结果传递过去
创建物理材质
我们只创建了不同的物理表面,但是还没有创建物理材质。
右键找到物理,物理材质,物理材质用于定义与场景动态交互时物理对象的相应。
我们将设置的物理类型物理材质全部创建出来
进入一个,首先你要将它的表面类型修改成对应的类型
设置好对应的类型,我们需要将物理材质给予材质去设置,这里要区分好物理材质和材质,材质是用于表现模型表面的显示效果的,物理材质则是用来区别物理基于物理运行的数据。渲染中讲的物理材质是基于真实物理的光照模型进行渲染的材质。这里大家要分清楚。
你打开一个普通材质,会发现左侧可以设置物理材质
让其表现不同的物理,我们需要将其添加到场景的模型上面,最简单的就是创建立方体,并拖拽上去
这样就实现了对材质的物理材质添加。而且还方便后面的测试。
模拟子弹冲击的物理效果
如果子弹攻击并击杀了丧尸,我们需要让丧尸有一种被子弹击退的效果,那就需要去模拟物理效果。
在子弹命中以后,我们首先判断命中结果的组件是否存在
然后使用为模拟物理现象判断当前是否可以物理模拟
只有开启了物理模拟,我们才可以使用进行物理模拟(有点像废话)
然后获取子弹的速度,作为给物理模拟对象的冲量,并添加给模拟对象,获取的速度是一个三维向量,既有速度也有方向
最后,记得,将自身销毁掉
完整截图
增加子弹音效
增加子弹的音效,在事件开始运行时,播放音效,我们将在一个位置处播放音效,这个是3d音效,有距离和方向的感觉。
我将音效资源设置成变量,可以在子类设置,并将actor的位置设置给音效。
创建一个特定武器子弹的子类
上面将父类的内容创建完成,接下来要创建一个专属于特定武器的子类,这里要做AKM的,所以就制作一个AKM的子弹类。
创建子类,可以创建蓝图然后搜索父类的名称
或者直接右键点击父类,选择创建子类
创建完成子类打开,你有可能是一个纯数据蓝图,如果只需要修改相关的参数即可,父类的变量可以在默认里面直接修改,并只影响子类。
如果打开就是一个正常蓝图的样式,那选中左侧的最上层,在右侧也可以修改
甚至,你在左上角,我的蓝图那里,显示继承变量,也可以直接去修改变量
实现武器的射击功能
要实现射击功能,我们需要在武器蓝图里面实现三个自定义函数,开始射击,射击,结束射击。开始射击主要为了实现自动射击和手动射击的逻辑,射击就是为了实现一些射击的逻辑,结束射击就是为了结束自动射击。
首先实现射击事件,在射击事件中,我们需要子弹的创建,抛弹壳特效和枪口喷火特效。
首先我们需要获取到相应的世界空间坐标系下的位置,然后在当前位置生成相应的内容,武器是骨骼模型,上面有切换子弹动画,我们在枪口创建了一个插槽,
在武器蓝图中,我们使用获取插槽变换节点,获取世界场景的变换
空间变换这里空间从武器局部位置变换到世界场景坐标变换
创建子弹,我们使用 生成Actor节点,这个可以从类创建对应的actor,我们将class提升为变量,在子类里面去赋值,变换直接使用骨骼插槽的场景空间的变换赋值,缩放就直接定义即可,碰撞直接设置为默认,使用子弹类的定义。
抛弹壳特效的位置,我们在枪的抛弹壳的位置创建一个箭头组件,将其可视化设置为否,只需要使用它的变换信息,然后获取场景坐标变换
下面是通过箭头组件位置创建了抛弹壳的特效,和枪口喷火特效。喷火特效还是使用的枪口位置的世界变换位置。
设置武器射击动画,动画也设置成了变量,供子类设置。
在开始射击事件这里,我们首先调用一下射击,触发时直接射击一次
然后使用节点以事件设置定时器,进行循环调用射击,定时器的Event值链接到射击的右上角的口,这样就确定了两个相连,我们也可以使用以函数名。
在停止射击事件这里,主要是为了清除定时器,这里我们使用定时器返回的值,然后使用节点
这样,射击的基础逻辑实现完成。
创建一个子类,设置相关参数
这些制作完成以后,需要在角色蓝图中对齐进行调用
然后停止射击事件,调用武器的停止射击事件
弹壳的落地音效
之前实现给子弹击中目标增加了击中特效,但是没有讲解如何增加音效,这里以制作弹壳落地音效讲解。音效文件导入到unreal你需要将音频的格式转换成wav格式。
一般为了让音效听上去不那么趋同,在制作音效时,会制作在相同情况下使用的多种音效。
然后,在通过混合器,实现音效的随机播放。我们会制作Sound Cue文件来实现
弹壳落地分为两种音效:一种是掉落在地上以后直接弹起的清脆响声,另一种是最后结束弹跳时的一阵清脆的触地的声音。
接下来实现简单的随机音效,首先在一个音效文件上面右键,下拉里面有一个创建cue
或者直接右键,找到音效菜单里面也有
然后选中当前所有需要随机的文件,拖入到cue里面,右键输入随机,添加一个随机节点,将其链接起来
或者你选中所有的声波播放器,然后在右侧将随机拖入中间,会自动生成连线
然后将调制器添加进来,调制器的功能可以随机音量的大小
这样就实现的随机音效和音量大小的功能。我们还可以点击左上角的按钮,实时调试
然后,我们又修改了音量,这个可以控制所有的音效的音量,并设置的音效衰减
还有音效并发功能,暂时还没用到
音效衰减文件我们可以右键创建
音效衰减文件有很多配置项可调,主要是为了模拟真实环境中的效果,比如距离越远声音越小,被物体遮挡,也会减小声音
接着,在武器蓝图中增加音效的播放事件,我们在抛弹壳粒子特效的返回结果拖出一条线,找到 On Particle Collide事件,这个可以实现粒子的碰撞事件
创建完成,会自动给你生成两个节点,一个调用节点,另一个是数据获取节点,我们在获取节点主要获取的是粒子碰撞物体的位置信息,用于在当前位置播放音效。
实现了这一步以后,我们还需要实现一下循环调用,子弹落地,如果地面比较坚硬,会出现多次反弹的情况,在多次反弹情况中,我们使用第一种反弹的音效,结束时使用另一种反弹的音效。而多次循环的实现,我们使用一个新节点DO N,这个节点懂代码的同学应该理解相当于循环函数那种,并且我们可以延时调用,N就是我们的调用次数,Reset就是重置当前的批次,我们设置为3,就是执行次数Counter不大于等于3 时,会一直执行,然后我们使用分支判断,如果小于3,值的就是1 2 时,播放反弹音效,如果等于3,就播放结束音效,来结束当前的抛弹壳音效。
所以,相当于,开三枪的时候播放弹壳结束音效,其它播放弹壳反弹音效。
枪的自动手动切换功能
首先创建一个变量作为控制当前是否为自动,在开始射击进行分支
如果是自动射击,则按原来的逻辑,设置定时器,按射速持续调用定时器,如果不是,那么,将调用角色的停止射击。
这里角色设置可以选择两种方式,一种是在武器蓝图中,去获取场景中的Player类,获取第一个实例,如果有多个实例就不好区分了
另外一种就是在创建武器实例的时候,将角色赋值给武器
武器有了相应的属性设置,我们可以在角色内设置事件触发相应逻辑,先播放切换特效,然后根据当前是否为自动模式,设置成相反的值,如果是全自动,则停止射击,关闭全自动射击。
后坐力功能实现
实现后坐力功能,我们需要用到添加控制器输入节点
节点的介绍上也说了,将输入的值去影响ControlRotation,就是在基础上加上此值,并且在pawn上的值相乘的结果。在ue4的版本显示这几个值,但是在ue5里面我没有找到,如果大家找到了记得告诉我一声
这个节点会让我们传入一个值,这个值会乘以pawn上面设置的缩放系数,得出的结果赋值给控制器的旋转
武器后坐力这里,我们制作两个事件,一个生成后坐力,另外一个是回弹的效果
第一个函数在自动射击事件后面调用即可,每次射击都会触发回弹效果。
后坐力回弹效果则是在触发完成后坐力以后,通过后坐力触发回弹效果,我们还使用了一个时间轴去让回弹效果有一个缓慢的过渡。下面的运行流程是后坐力时间触发,从时间轴最初的值开始回弹(因为后坐力事件在自动射击时触发很频繁,为了防止抖动太剧烈)update的时候,根据时间轴运行的方向(快进是正向,快退是反向)来设置角色控制器的值,播放完成以后,判断是否是正向,正向将调用后坐力回弹事件,然后反向播放时间轴,而且还取后坐力的负值,让武器回弹到原来的位置。
时间轴的设置
在后坐力更新时,我们也设置水平抖动,这个不需要有回弹效果,只需要以微小的值进行变动即可
这样,就简单的实现了后坐力效果。
换弹功能实现
首先创建三个变量
子弹数量 为当前的弹夹中还存有几发子弹
子弹总数量 为每个弹夹内的子弹总数
弹夹数量 为角色身上有多少个弹夹
具体流程是 角色蓝图触发换弹操作→触发拔下弹夹操作动画,将弹夹从枪上面拿下→触发从后背拿出新的弹夹动画将新弹夹放到手上然后装到枪上面→在枪的类上面,将枪的子弹数量恢复至最大数量。
首先实现角色蓝图触发换弹操作,操作之前需要有几点需要判断,首先判断当前是否持枪,状态处于默认状态或者瞄准射击状态(开枪的时候也可以换弹)
之前写的宏里面稍微改了改,因为这个默认设置瞄准射击状态,我增加一个输入,这个默认为true,不影响其它的节点使用,也可以给换弹用
接下来判断弹夹子弹是否是满的,满的就不要换了,然后判断是否还有富余的弹夹
如果条件都满足(拿着枪,没在其它状态,缺子弹,有弹夹),那么就将状态设置成换弹状态,射击的时候也可以换弹(那就那射击状态也关闭)
完成以后,发现,没有换弹动画可播放,接下来,要制作动画。
有了变量,我们在射击时,也需要对当前的变量进行判断,判断弹夹中是否还有子弹,所以,每次射击时,判断一下当前弹夹数量。
如果当前弹夹没有子弹,将触发停止射击事件,然后播放一次弹夹已经空的特效,这里只播放一次的实现,使用了DO ONCE节点,在执行了一次没有重置之前,这个节点后面的节点不会再执行。在弹夹有子弹的时候,我们入重置这个节点
然后每次射击完成,我们还需要减少子弹数量
这是使用了自减节点,意思就是自身的数值减去1
创建弹夹类
我们只创建的武器类,但是武器身上还没有弹夹,在这里,创建一下弹夹。新创建一个actor,我们在这个弹夹类里面只需要添加一个显示模型即可,在父类里面,我们也不需要着急去设置模型,去子类里设置即可。
记得将模型的碰撞修改,因为我们要在更换弹夹后模拟它的物理效果,并且不要和pawn类型的物体产生碰撞,会出现和角色持续碰撞bug
接着,在弹夹里面增加一个弹夹分离事件,用于在被从枪上面拿下来以后,我们需要让其有一个符合物理效果的坠落,以及在一定时间以后,会自动销毁。
接着创建一个AKM武器的弹夹子类,我们在里面设置模型,它与弹夹父类的唯一区别。
为了实现后面的逻辑,我们还需要在角色身上和武器身上创建相应的插槽,用作于弹夹的挂点。
在武器上面,有对应的骨骼位置,我们不需要额外的创建插槽,可以直接添加预览弹夹查看效果
在角色身上,我们需要在左手上面创建一个插槽,用于调整位置,最主要是在从枪上面拔出弹夹时,位置要对应上
弹夹相关的设置基本上就完成了,后面我们要实现换弹动画,并在动画运行时,处理相关逻辑。
实现换弹动画蓝图
首先说一下,在动画播放中,我们需要实现的东西,
丢掉枪上的弹夹
创建一个新弹夹
然后将新弹夹装到枪上
触发换弹动画结束通知,结束换弹逻辑
这一套逻辑实现,我们通过动画通知去实现,然后在相应的位置播放音效,就大功告成
创建完成在动画蓝图里面,功能状态机里,增加一个可切换的状态,切换条件就是创建一个新变量,是否可以换弹,可以换弹则切换到换弹动画,这个值为false时,回到默认状态
换弹动画,还是使用之前的按骨骼分层,我们只实现上半身播放换弹即可,下半身是移动是站立还可以继续进行
只要在动画蓝图中播放当前动画,里面的通知就会触发,播放音效,触发通知。这也是动画去触发蓝图事件的一个途径,你在状态机里面是无法对蓝图数据进行修改的和事件触发的。
我们需要在角色蓝图中,对动画蓝图的是否换弹的变量进行修改,触发换弹逻辑后,将变量设置为true,让状态机切换到换弹状态,并播放换弹动画。
增加一个换弹结束事件,在换弹动画结束时,通过动画通知调用其,退出换弹模式。
在动画通知哪里,我们创建四个动画通知,前面开头说的四个逻辑触发
第一个逻辑是将枪上的空弹夹取出
先实现一下通知的逻辑,在通知中,我们获取到触发通知的所有者,然后获取到武器,并调用武器上面设置的拔下弹夹事件。
武器类里,我们需要实现拔下弹夹事件,事件里,我们先把弹夹附加到角色的手上,延迟一定时间以后,然后再触发弹夹上的弹夹分离事件,弹夹分离事件在制作弹夹时已经制作完成。
第二个逻辑是动画播放到左手放到腰后面时
当动画播放到手放到腰后时,触发第二个通知,这个通知会触发角色的生成新弹夹事件
然后在角色的生成新弹夹事件中,基于弹夹类创建一个新弹夹实例,并且附加到手上,然后减少一个拥有的弹夹数量。
第三个逻辑是实现弹夹的装配
当角色动画在第二个逻辑创建了弹夹,播放到装填位置时,我们需要实现将弹夹装配到武器上面。所以需要一个装备弹夹通知,通知中只是触发了武器中的换弹结束事件
然后,在武器上面创建结束换弹事件,事件执行将弹夹从角色的手上安装到武器上面
最后一个逻辑,是在换弹动画播放完毕时触发
这个逻辑主要是为了退出角色的换弹状态,在动画蓝图中的状态机里,无法进行数值执行操作,所以,我们需要在动画结束时创建一个动画通知告知蓝图。
在角色蓝图创建换弹结束,修改换弹变量为false,以及修改状态