在这篇文章中我们将在C++中实现一个简单的近战连招系统。另外,为满足我们的需要我还将展示一个动画混合的基本技巧。
下面是小编整理好的一套C/C++资料,加小编C/C++编程学习群:825414254,获取系统性学习C/C++的学习资料
QQ截图20190309205647.jpg你会注意到我们只需敲30行左右的代码,其余的内容都在编辑器中使用简单的通知完成。所有的代码都能在我的github repo中找到。
在创建我们的系统之前,先看看我的最终结果(你的结果可能会不一样——我将在后面解释为什么,现在先别着急)
该教程假设你已熟悉以下术语:
- Persona编辑器
- 动画序列
- 混合空间
- 状态机
这倒不是说如果你不精通以上术语你就不能创建这个系统。如果你知道这些“东西”是什么以及它们的用法,那么你就可以继续阅读了!
制作一个所需资源的列表
这是为了创建视频中的系统所需资源的一个列表:
- 一个骨骼网格物体(作为我们的角色)
- 三个动画
a. 闲置(Idle)动画
b. 奔跑动画
c. 攻击动画
视频结尾部分展示的连击其实是一个包含三次击打效果的动画。但是,正如所展示的那样,我根据一个动画创建了三个连击动作。这背后的逻辑非常简单,你可以将一个动画分成几部分并告诉引擎你想播放哪部分。这是我使用的完整攻击动画:
理解动画混合的概念
到目前为止你也许在想为什么我的攻击动画和我的最终结果会那么不一样。这和我实现的动画混合以及我想要的动画有关。动画混合可以使你同时播放两个(或更多个)动画。看到我的最终结果你也许会认为这很糟糕。其实并不是那样的!
如果你仔细看第二个视频,你会注意到我选择的攻击动画也移动了我的角色的腿。由于我想在奔跑的时候播放那个动画,我需要使用动画混合,在这个项目中这会有一些不足。这时候就需要动画设计师了。如果你的团队中有一个专门的动画师,他也许可以给你一个同时包含跑步和攻击的动画,会带来一种更吸引人且更平滑的效果!
收集所需资源
正如上文提到的那样,你的结果也许会不一样。这是因为我不能分享我所使用的骨骼网格物体和动画,不过这里有一个该问题的备用解决方案!
打开Mixamos的官方网站然后:
- 创建一个免费账号
- 选择你喜欢的角色
- 为你喜欢的角色选择三个动画然后将它们“连接”到你的角色
Mixamo将立刻提供给你一个下载地址,其中包含你的角色和他/她的动画!请注意上述提及的所有服务都是限时免费的。
注意:之前我遇到过两个有问题的模型,所以如果你不能导入你下载的角色只需选择另一个。
创建一个第三人称模板项目,导入你的角色和它的动画,我们就可以开始了!
理解该系统的逻辑
在开始敲代码之前,让我们先分析一下该系统背后的逻辑。为了达到视频中的效果,我们将使用一些动画通知来通知代码如果角色“在正确的时间”按下了攻击按钮那么它将根据已经播放的动画进行一次连击(在这里即为连续攻击)。当然,我们将决定合适的“正确时间”。
所以比如说,如果我们已经进行了两次攻击那么当我们在正确的时间按下攻击键时我们可以继续下一次攻击。
创建动画实例类以及对动画蒙太奇(Animation Montage)的解释
基于动画实例类(Anim Instance class)新建一个C++类,将其命名为MyAnimInstance。然后在其头文件中添加以下代码:
image.png
转到该类的源文件并添加以下实现:
image.png
在继续之前,保存你的代码然后我们退一步先解释一下上述代码的意义。
布尔型变量bAcceptsSecondAttackInput和bAcceptsThirdAttackInput是我们用来决定角色是否能够进行二次或三次进攻的标志。这些变量通过Persona编辑器中的动画通知被设置为是。如果这些变量为否,那么角色将只能进行基本攻击。
“UAnimMontage”是动画蒙太奇的一个引用。在本教程中,我们把动画蒙太奇理解为一个在某事发生时(在本教程中即当我们的角色进行攻击时)实际播放的动画。
我们在后面实现攻击函数,它将包含连击的逻辑。
准备我们的角色并设置输入
打开你的项目设置然后添加一个动作映射(Action Mapping):
image.png
然后打开你的角色的头文件并加入以下函数声明:
image然后打开你的角色的源文件并包含以下头文件:
image完成后,转到SetupPlayerInputComponent函数并像这样添加你的动作映射:
image一定要将“PerformMeleeHit”改成你的动作映射的名称。
另外,为攻击函数提供以下实现:
image保存并编译你的代码。
拓展我们的动画实例类
基于你导入的骨骼以及创建的类新建一个动画蓝图。这是我的截图:
image然后在事件图表中加入以下逻辑:
image理解缓存动作(Cached Pose)的作用
切换到你的动画图表中并添加一个新的状态机。然后根据你添加的状态机创建一个新的缓存动作,如下图所示:
image在继续之前,我们先解释一下缓存动作是什么以及我们为什么使用它。
如上面提到的那样,我们需要一个简单的动画混合。也就是说,我们想要暂时“存储”当前正在播放的动画来同时播放更多我们想要播放的动画。如果你尝试将你的状态机连接到多个节点,编辑器会断开之前的连接然后将状态机连接到你点击的节点上。这就是为什么我们将动画存储到一个缓存动作然后使用该动作来混合我们的动画。但是到底为什么不能将所有内容都连接到我们的状态机呢?呵呵,答案很简单,就是不行!
当我解释完下一小节后一切都会真相大白了。现在先按我说的走。
创建多个槽(slot)
当你存储完你的缓存动作后,点击右键然后使用你创建的缓存动作。然后创建以下节点:
image这意味着从之前保存的缓存动作(包含状态机)我们将得到当前在默认槽中播放的动画。
但是等一下,什么是默认槽(Default Slot)?注意我们希望在角色移动的同时播放攻击动画,也就是说我们需要将我们角色的骨骼分成两个部分(槽)。在这个例子中我们需要两个槽:
-
一个包含奔跑动画的槽(默认槽)
-
一个包含攻击动画的槽
当你创建完默认槽节点后,点击选择它然后在细节面板中点击图中所示按钮:
image然后如下图所示,点击添加槽按钮并创建你的新槽:
image我将我的槽命名为UpperBody(上半身)。当创建了动画蒙太奇后我们将通知编辑器只在Upperbody槽中播放指定动画!
当你添加完你的新槽后,选择默认槽节点然后将它的名称设置为UpperBody。
实现动画混合
当你添加了想要的槽后,创建以下图表:
imageLayered blend per bone(基于每个骨骼的分层混合)节点执行了实际动画混合。上图就好像是对编辑器说了以下句子:
“使用默认槽中正在播放的动画,同时播放当前在Upperbody中播放的动画”
希望你注意到了上图中多个指向骨骼名称的红色箭头。如果你向上滚动到动画混合部分的概念,你会记得我们谈到过将骨骼分为两部分。骨骼名称实际代表了骨骼被分开的位置。请注意根据你选择的动画你的骨骼名称也许会不一样。
打开你的静态网格物体的骨骼资源然后点击显示(Show)菜单。然后点击骨骼名称(Bone Name)选项:
image使用以下截图来找到符合你需求的骨骼名称:
image我表达不出在Layered blend per bone节点的细节面板中包含骨骼名称有多重要。如果你忽略了这一步,你的UpperBody槽动画将不会播放但是你的代码能够正常运行。
建立一个基本的混合空间
在编辑器中点击右键然后新建一个1D混合空间。在零点处添加闲置动画,在最大值处添加奔跑动画,如下图所示:
image为了设置动画,只需将想要的动画从面板中拖拽过来就好了。动画将“锁定”在可用数值上。
1D混合空间将确保你在闲置和奔跑动画之间有一个平滑的过渡。如果你计划在发行的游戏中支持游戏手柄,那么你需要在中间包含一个行走动画来处理摇杆输入!
保存你的混合空间然后切换到你的蓝图动画实例。
然后在你的状态机中实现以下逻辑:
image image设置你的角色
切换到第三人称角色蓝图然后指定你自己的静态网格物体和动画蓝图生成的类(Anim Blueprint Generated Class),如下图所示:
image至此如果你在编辑器中开始游戏,你会看到闲置/奔跑的动画。我们快要完成该项目了!
注意:第三人称模板有一个内置的跳跃动作。如果你使用当前状态机尝试跳跃,你的角色很有可能在下降的同时保持行走的状态。我在本教程中不会讲解跳跃动作的内容,但是如果你想了解如何实现该功能,请查看这篇文章!
创建动画蒙太奇
在你的内容浏览器中点击右键新建一个动画蒙太奇。然后将你的攻击动画拖拽到“蒙太奇”片段中:
image别忘了将UpperBody槽分配给你的动画。记住我们希望在移动的时候进行攻击!
当你添加了你的动画并选择了UpperBody槽后,新建两个蒙太奇片段(section)。如我在之前提到的,蒙太奇片段是我们将动画分成的不同部分。
然后:
-
将默认片段重命名为FirstAttack
-
将第二个片段命名为SecondAttack
-
将第三个片段命名为ThirdAttack
如果编辑器很乱的话,点击片段区域内的“清理”按钮。这是你应该得到的最终结果:
image然后选择SecondAttack片段,将其放置在你的二次攻击的开头位置。对ThirdAttack也这样做。如果你觉得有必要的话,点击相应片段上的“预览”按钮来预览你的片段。我知道这部分可能会让你感到困惑,但是如果你需要一个图片参考,以下是我的攻击片段:
image image当你完成了以上蒙太奇片段后,新建两个动画通知,将它们命名为EnableSecondAttackInput和EnableThirdAttackInput并将它们分别放在第一个和第二个片段之间的某处。如果你想要创建一个对于时机的把握要求更高的连招,你可以将它们放在靠近片段的结尾处。这是我的时机及通知的截图:
image带有数字2的绿色按钮对应着SecondAttack蒙太奇片段,带有数字4的绿色按钮对应着ThirdAttack蒙太奇片段。我们的蒙太奇已经准备好了!
完成我们的动画蓝图
在我们的动画蓝图中分配你的攻击蒙太奇。别忘了点击编辑默认(Edit Default)按钮。
image另外,别忘了为我们的通知添加功能:
image完成我们的攻击代码
打开你的动画实例类的源文件然后使用以下实现替换我们之前添加的GLog:
image在测试之前,确保你的FName和你的蒙太奇片段的名称相同。
你已经实现了一个基本的连招系统!恭喜!
网友评论