状态机的缓存
状态机缓存功能相当于我们只需要实现一次,可以在多个地方引用,也可以在别的状态机里面使用,而不是在里面再重新写一遍相应的功能。
我们可以在基础状态机的链接拉出一条线,搜索“缓存”
第一个就是新保存的缓存姿势,选中改个名称,这就是默认的基础姿势。
这样,我们就可以在其它状态机里面使用当前基础动画状态机产生的结果。
接着,创建一个新的状态机,用于实现特定的功能
在内部创建一个默认状态
在状态内部使用缓存姿势
这样,还是实现了之前的功能,但是,我们可以在功能状态机中,叠加其它的动画,实现更多情况下需要播放的动画。
持枪基础状态
先创建一个混合空间1D,这个用于存储在持枪状态下的基础姿势
在基础状态机里面,现在已经使用布尔混合了默认站立和蹲伏状态,我们再创建一个变量用于判断是否切换持枪状态,并将刚才制作的混合空间动画拖入
下面,我们要在角色蓝图里面实现武器装备的功能,现在还需要一个事件去触发武器装备功能,那就在增强输入里面创建一个装备武器功能,创建一个输入操作。
将刚才的按键增加到上下文,使用数字1键触发。在角色蓝图中,找到事件
在事件触发时,对动画蓝图的变量进行切换
运行测试,会发现,点数字1,可以对持枪状态和默认idle状态实现切换。
装备武器动画实现
在功能状态机里面,创建一个新节点,可以实现达到要求,可以切换到装备武器的动画状态
创建一个变量,是否需要装备武器,然后功能状态机中的基础切换到装备武器状态的切换条件设置它
回到默认的状态则是判断装备武器动画是否播放完毕,我们可以获取相关剩余动画时间,单位是秒
在装备武器动画剩余时间小于0.1的时候,我们设置回到默认状态
记得给装备武器状态添加动画
记得,装备武器动画只需要播放一次,不要开启循环动画
为了实现装备武器和收回武器的功能,我们还需要修改播放速率,1就是默认的装备武器,如果速率改为-1,将会回放动画,实现回收武器的效果
修改速率肯定无法在动画状态里面修改,我们需要将其公开为引脚,在角色蓝图内实现对速率的修改
动画前面会出现播放速率的引脚
我们可以使用一个变量去控制引脚的值,或者直接将其设置成提升变量。
这样,在角色蓝图内,即可根据角色装备武器还是收回武器,设置相应的动画。
在角色蓝图中,设置是否持有武器逻辑后面,添加对速率的修改
接着,在后面,设置装备武器变量
装备和收回都直接设置此变量,因为它们的区别只是播放速率的区别。
我们设置完成后,需要将这个值修改成不可装备武器,防止默认状态一直向装备武器状态切换。
测试发现,播放装备武器动画和默认状态切换有些生硬,那我们可以适当延长一些过渡时间
还有一个问题,就是我们在移动时,进行装备武器,会发现还是处于站立状态播放装备武器,需要我们实现按骨骼分层混合实现。
以默认缓存的动画为基础动画进行混合
要找到需要混合骨骼位置,因为装备武器动画主要是上半身,那么,我们需要找到上半身的根节点
在骨骼查看界面,可以查看所有骨骼
选中spine_01后,显示下面的所有骨骼
thigh_l是左腿
thigh_r是右腿
现在我们知道到了,上半身的根骨骼是spine_01,那么从这个骨骼开始混合。
复制名称
设置节点属性,在层设置上面增加一个数组,将骨骼名称添加进去,混合深度是混合到第几层,默认值0是所有层级。由于骨骼自身混合,所以在自身空间混合而不是在世界空间。
这样便实现了在移动中装备武器动作的实现。
换装功能实现
一般衣服都是已经绑定了相应的骨骼,我们需要做的是将其添加到模型节点下面,然后让骨骼运算影响它即可。
先选中衣服
在角色蓝图选中网格体,点击添加
这样添加骨骼网格体时,后面会带有相应选中衣服的名称
添加到骨骼网格体下面
这种状态只是将模型添加了上去,但是骨骼网格体还不会更新模型。
我们需要设置骨骼去更新它,在构件脚本中
添加设置引领姿势组件
让骨骼模型使用网格体的骨骼组件更新
如果你有多个模型添加
这样就实现了骨骼更新当前模型,如果你想创建不同的,那么只需要创建子类,然后修改节点相应的模型,就可实现换装功能。
插槽替换模型
除了衣服以外,还有一种就是我们需要替换各种各样的武器,比如刀剑,护盾等等,这种模型是不需要通过骨骼更新动画的,它只需要的是骨骼上的某一个位置,然后跟随着某根骨骼移动即可。比如,将剑放到手上,它只需要跟随着手的位置更新自己的位置即可。
要实现这个功能,我们需要在角色骨骼上面创建(插槽)。
为了方便设置插值的位置,我们还可以给插槽添加预览资产
为了更方便调整,我们还可以在右侧设置预览动画
然后将动画停在某一帧,来设置相应的位置
然后调节插槽的位置,实现它在相应的位置显示
最后一步,在角色蓝图内,网格体创建一个骨骼网格体子类,在插槽一栏中,父项套接字(这中文翻译的啥,应为为parent Socket)设置插槽的名称,最后将模型添加上去,就可以实现模型添加。
如何动态创建添加
我们使用节点从类生成Actor,可以把类实例化成一个实例
在类那里选择需要实例化的类,并创建一个变换(不创建会报错)
并将实例化的Actor添加到组件
父节点就是网格体,SocketName就是需要添加的骨骼节点的名称,我们不需要相对坐标,直接将Actor对齐到目标即可。
这就是我们手动实例化类进行逻辑添加的实现过程。项目运行起来,你会发现蓝图的实例被添加到了角色身上
武器蓝图制作
武器蓝图是我们需要创建的所有武器的基类,我们可以通过此类创建子类,来实现各种各样的武器。
首先创建一个Actor,作为所有武器的基类
然后基于这个基类,创建一个武器基类BP_Gun,然后基于武器基类再创建一个AKM的基类
这个节点创建好以后,我们将模型添加到蓝图里面,直接使用默认位置即可,因为我们在骨骼上面调试的时候,就是基于模型的默认值调整的位置。
然后根据上面的方式,可以将蓝图实例化然后按插槽的名称添加到角色身上。
实现角色从背后拿取武器
要实现让角色把背后的武器拿到手中,我们需要在播放从背后拿武器的时候,发送一个动画通知,在角色蓝图中,实现武器的插槽切换,也就是从背后的插槽切换到手上的插槽。
那么,首先我们要实现动画通知。那么创建蓝图动画通知AnimNotify
然后创建一个名字为
我们这里要对默认的函数进行重载,实现内部逻辑。
函数给我们提供了三个参数,触发事件的网格体组件,动画,通知事件参考类型
我们可以通过网格体组件获取到它的所有者
然后将类型转换为我们的角色蓝图类型,并可以获取到对应的动画蓝图
我们根据当前动画蓝图的状态,设置是将装备放到手上还是放到背上,通过将Actor添加到组件节点添加到相应的位置。
在动画里面,找到对应帧位置,右键添加通知
当手伸到后面的帧上面,添加通知状态
蹲伏状态拿武器
先创建一个混合动画,蹲伏状态拿着武器的默认idle状态,以及移动时的状态的混合
然后再基础状态机的基础状态里面,将持有武器蹲伏按布尔混合一下即可
在跳跃状态里面,也对是否持枪进行一下判断
在坠落里面,我们也需要根据持枪状态修改坠落的效果,让其保持持枪状态,而不是双手抬起
状态判断的修改
在触发跳跃和武器切换的时候,我们会进行状态的判断,防止出现抽搐的情况。我直接将其抽离成了一个函数
可以进行重复调用,而且还保证了节点的简洁。
应用的时候还是正常使用即可,修改一下状态。
修改地面摩擦力
为了实现移动时正常摩擦力,没有移动输入时,则降低摩擦力,增加惯性。
使用了增强输入就是好,就事件开始和结束事件,我们直接使用这两个链接即可。
瞄准功能的实现
瞄准功能是在持有武器时,提高命中的准确率。
通过增强输入,鼠标右键触发事件,然后判断当前是否处于持枪状态
然后判断当前是否可以切换到瞄准状态,然后退出后切换会null状态
使用时间轴的0-1切换使用插值,去修改弹簧臂的长度,来实现镜头的伸缩
运行发现,瞄准状态下,我们还可以看到角色的正面,原因在于,角色朝向是根据移动方向确定的,而不是根据相机的朝向确定的。所以,在瞄准状态时,我们需要将角色朝向修改为根据相机朝向移动,取消根据移动方向确定。
创建两个自定义事件,第一个是切换到瞄准状态动作,第二个是退出瞄准状态
获取两个设置事件的方式
角色朝向朝向运动方向需要在角色移动组件里面获得
射击瞄准状态下移动处理
现在在瞄准状态下,如果人往后走,我们还是会播放向前移动的动画,这样是不合理的。所以,我们需要实现脚的移动按照朝向进行侧移或者后已来兼容八个方向的移动。为了实现360度的移动,我们需要计算移动方向和朝向之间的夹角,在动画蓝图中,内置了一个计算方向的节点,可以根据角色的速度和朝向,获取到一个范围在[-180,180]的角度,我们可以根据这个数值去修改瞄准时移动需要播放的动画。
传入角色的速度和角色朝向,我们可以将计算得到的移动方向角度存储为变量,方便在状态机中使用。
注意,大家要多写注释,可以清楚知道变量是什么作用
下面,要制作混合动画,创建一个混合空间,用于处理瞄准状态下的移动的角度和速度的动画,我们需要设置两个值,一个是速度,和默认的速度值使用一个,另一个就是角度,用于实现前后左右八个方向移动时,脚能够播放正确的动画。
轴向就变为横轴就是移动角度,纵轴就是移动速度,我们需要将每种速度每种角度的动画都添加进去,idle状态也就是速度为0的使用一个动画即可,其它三种速度对应的动画,需要每种角度的都需要添加上。为什么只做到行走,现实生活中,瞄准射击状态下是无法射击的,如果要进入跑步状态,那么,我们切换到持枪行走状态即可。
随着连的节点越来越多,为了方便后面的调整,我将基本状态,持枪状态和瞄准状态制作了三个状态机,每个状态机里面设置可以跳跃。
在瞄准动作状态机里面,坠落和跳跃都用持枪状态的动画。在基本的移动状态中,将我们制作的瞄准状态混合动画添加进去,设置上我们之前制作的方向和角色默认速度。
可以看到,动画蓝图切换到瞄准状态动画需要一个布尔变量isAim,这个需要在角色蓝图里面设置。角色蓝图中,之前我们设置橘色切换瞄准状态那里,增加对动画蓝图的属性的设置。
进入场景测试,会发现实现了角色八方向的移动,以及根据速度行走的效果。但是你会发现想走还是使用的默认的速度,所以,我们还需要限制一下瞄准状态的移动速度。
在速度判断那里,增加了额外的通过布尔选择节点,如果在瞄准状态,移动速度就是行走速度。
最后在瞄准状态切换时间轴更新结束后,重新调用速度判断,更新速度。这样表现还有一些速度的惯性,比如瞄准状态切换会默认状态时,它会在动画切换完以后才恢复正常速度。
使用反向动力学解决无法双手握枪的问题
在头部瞄准偏移时,我们会发现左手会握不住枪,这是因为枪需要的是两个骨骼绑定,但是我们只能绑定一个,在播放动画时,会出现偏差。
这主要是我们在动画蓝图里面混合的瞄准偏移动画导致的
首先把它移动到瞄准偏移制作的动画前面,让其不再影响瞄准姿势,分别在idle和持枪状态添加。这样我们在转向完成后,使用FABRIK解决这个问题。
接下来我们使用前后延伸反向运动学(Forward And Backward Reaching Inverse Kinematics,简称 FABRIK)来解决双手握枪一个手握不住的问题。
在需要处理的位置,就是头部转向后面,创建一个FABRIK来处理
在FABRIK右侧的细节属性栏,有一个结束效果器,相当于设置它的执行范围,到哪里的骨骼结束,我们不需要公开引脚,取消公开为引脚,然后再细节栏设置
结束效果内需要添加执行器目标,这个就相当于需要跟随的目标,解算器就是左手,需要填入解算的骨骼
设置完成,选择编译,进入调试模式,选中持有武器状态
会发现两只手绑定到了一块
选中FABRIK以后,会发现我们有调试位置的箭头,拖拽到合适的位置,即可实现两个位置的绑定。
进入运行模式,会发现,这个问题被完美的解决了,两个节点位置偏移固定了
射击状态下的瞄准偏移
还是老样子,以正常状态为基础姿势
设置完成后打开里面一个查看
这样就是设置成功了。
接下来要创建一个瞄准偏移,之前我们创建过基础状态下的瞄准偏移,来实现了跟随相机,现在创建的是持枪瞄准状态下的瞄准偏移
左边的属性和之前一样
设置好动画以后,设置预览动画,就可以查看效果了
然后将射击状态的瞄准偏移添加进来,并复制刚才的FABRIK节点过来,解决双手偏移的问题
射击状态蹲伏动画
和基础瞄准状态一样,它也需要两个坐标轴,主要是为了解决蹲伏状态下瞄准移动时,脚要往正确的方向移动的问题。
首先创建一个混合空间,两个轴的值和基础瞄准状态的一样即可
拖的时候,推荐大家直接按着Shift键,这样它会更好的粘在分格的位置
设置完成动画后,记得按着ctrl查看一下动画是否有问题
然后使用按布尔混合姿势,根据是否蹲伏修改动画
射击动画的实现
射击功能的触发使用鼠标左键,在增强输入里面,增加一个输入
然后再角色蓝图中,调用射击事件时,首先判断是否能够切换到射击状态,然后再根据当前是否已经处于瞄准状态,如果没有则先切换到瞄准状态,然后后续再进行射击逻辑。
AIm Shoot Judgement是我封装的一个宏,宏的好处是可以自己定义执行链接,所以可以阻断后续的执行。之前我以为函数也可以的,最后测试发现是不行的,所以封装了宏。宏的缺点就是只能在蓝图内部使用。
判断里面条件是,需要角色已经装备了武器,并且在默认状态或者瞄准射击状态时,可以向后运行。
在射击完成后,我们还需要回到其它状态,能够回到的状态有两个,一个是基础持枪状态,另一个就是瞄准状态。所以我们还需要有一个变量进行判断,就是当前是否处于瞄准状态,这个值只有瞄准事件触发时设置。如果不是瞄准状态,使用定时器去去触发函数回到瞄准状态。
而这个是否处于瞄准状态的变量,只有瞄准事件触发
定时器的创建有多种方式
我们现在使用的是以函数名定义的定时器,需要保证写的名字和定义的函数或自定义事件的名称相同才可。
我们还可以通过函数名清除定时器
到这里,射击事件的前提处理已经处理完成,射击时在瞄准状态,以及退出时是否回到瞄准状态
这样制作完成后,我发现我的切换逻辑还是有些问题,就是左键点击,会直接射击,在射击时,按住鼠标右键,会拉近镜头,然后再松开,不管你是不是在射击,都会直接退出瞄准状态以及射击状态。
所以,我要思考如何解决这个问题,增加了一个变量,在射击时将其设置成true,退出时设置成false
然后再瞄准退出时进行判断,如果当前处于射击状态下,只恢复弹簧臂,而不是退出瞄准动画。
到此为止,算是真正的处理完成了瞄准和射击的状态的切换逻辑。
射击的后坐力动画添加
实现后坐力的动画,我们不能够直接播放动画去实现,这样的话,还需要制作和射击相匹配的移动以及蹲伏等相关的动画,逻辑太复杂,所以我们直接使用附加动画去实现相应的动画。
附加动画的制作,需要在动画里面设置附加设置,这个设置在之前也做过,只是用作于多方向切换。
在这里,我们使用站立的射击动画,附加到站立的默认姿势上面,附加动画,会把相同的部分剔除掉,然后播放不同的部分去实现
制作完成附加动画以后,需要寻找一个地方进行附加,在动画蓝图的功能状态机中,在基础状态进行附加,首先对动画进行按布尔混合,如果不是射击还是运行原来,如果是射击状态,那么就需要附加动画去附加。
我们需要添加附加动画,然后使用应用网格体空间additive动画,对默认动画影响
将原来的动画附加上射击动画
新创建一个变量,是否射击,这个在角色蓝图中进行设置,然后根据此变量是否附加
接着在角色蓝图中,创建一个自定义事件,用于触发射击事件
自定义事件触发将动画蓝图的变量设置为true
根据当前是否瞄准进行处理,如果已经处于瞄准状态,可以直接射击,没有处于瞄准状态,那需要先切换到瞄准状态,然后设置一个延迟0.4秒的定时器,进行触发射击。
停止射击时,我们需要取消射击动画,关闭相关动画。并且还要清除掉开始射击函数定时器,防止停止射击以后,还会触发定时器的问题。
有了这个变量,我们角色蓝图里面其实就不需要单独设置一个变量, 只需要使用动画蓝图的是否射击变量判断即可
现在,我们完成了角色射击动画制作和动作的切换逻辑,分为聚焦射击和默认射击,下面是射击的所有代码
下一篇,开始制作真实的射击效果。