虚幻五从零开始做一个动作类游戏(纯蓝图)

今天,我们开始做一个动作类游戏。

美术资源

我们先下载今天要用到的美术资源。

链接:https://pan.baidu.com/s/1Vci83yoTRvViXIXElZ4k0g?pwd=tynm

提取码:tynm
image

新建项目。
image

把美术资源拖进项目。
image

创建角色

我们创建个文件夹,就叫Player。
image

创建角色蓝图。
image

我们再创建一个玩家控制器。
image
image

这时候我们再添加一个游戏模式。
image
image

然后我们改下GameMode的类默认值细节的设置。
image

编译保存。然后改一下默认游戏模式。改成我们刚建的。
image
image

返回资源浏览器。编辑PlayerChar。给它添加个模型。
image

调整下位置,旋转。
image

选中胶囊体组件,把胶囊体半高改成92。
image

然后添加摄像机。
image

然后调整下弹簧臂的位置。
image

编译保存运行。
image

移动

编辑PlayerChar。添加自定义事件。
image
image
image

增加ScaleValue变量编译。
image

保存编译。返回项目设置。
image

添加轴映射。
image
image

然后我们打开Controller。
image

编辑。
image

编译保存。现在角色可以向前向后移动了。左右也是。
image

然后再在项目设置里加一个轴。
image

然后控制器也加上左右。
image

前后左右都没有问题。现在回到项目设置添加视角。
image
image

返回playerchar。
image
image
image
image
image

编译保存运行。ok行走没问题了。

移动动画

现在要创建动画蓝图了。
image
image

打开动画蓝图编辑。保存。
image

新建一个混合空间。
image
image
image

点击编辑混合空间。在资产详情里修改水平坐标。
image
image

拖动idle_eqip_01到最左。
image

然后把walk_eqip_front拖到速度为1时的地方。
image

让速度到3时跑。
image

保存。等于走有三种状态。

然后再打开动画蓝图。
image

点开状态机。
image

添加状态。
image
image

进去Idle/Run状态。
image

把Speed提升为变量。
image

然后点击事件图表。
image
image
image
image
image

保存,打开playerchat。点网格体。设置动画类。
image

编译保存,运行。现在可以跑了。

现在输入我们加一个慢走。
image

打开玩家PlayerCharController。编写走路。
image
image
image

编译保存运行。现在可以慢慢地走了。

武器
现在我们加一下武器。在playerChar中加一个骨骼网格体。
image

然后父项插槽选Sword_1。资产也选一下。
image
image
image

编译保存运行。
image

连招系统

攻击

找到这个动作。
image

然后创建动画蒙太奇。
image
image

然后绑定下按键。
image

然后打开PlayerChat。添加自定义事件。
image
image

然后我们找到角色的控制器。加上攻击。
image

运行发现胶囊体没有跟角色移动。找到动画,启动根运动。
image

现在胶囊体会跟角色移动了。角色会跟着攻击动画移动。打开PlayerChar。让角色每次攻击都能连续。不会因双次按下攻击按键而抽搐。增加一个变量,用来判断是否在攻击中。
image
image
image
image

完整蓝图。
image

现在连点不会抽搐了。

连招

删掉攻击的逻辑,开始编写连招逻辑。
image

增加变量。并使用数组。
image
image

这里要多少个连击动作,就加多少个数组就可以了。
image

接着,我们找到连击动作。
image

创建动画蒙太奇。
image

然后找到Combo_01动画。
image

我们分解下连招动画。找到第一下下剑时的结束时间。调整结束时间。
image

然后做连招第二下的动画。
image
image

然后做连招第三下的动画。
image
image

然后做连招第四下的动画。
image
image

所有分解的招式。
image

然后返回PlayerChar。编辑连招逻辑。

然后找到刚创建的数组变量。
image

把四个连招动作按顺序赋予数组。
image

然后我们添加一个变量,用来计数攻击次数。
image

初始值设为-1。
image

然后编译下蓝图。
image

攻击先判断是否在攻击。

然后攻击次数加1。
image

然后判断攻击次数是否大于招式动画的长度。
image

如果小于招式动画的长度就获取一下招式。
image

如果大于招式动画的长度就把,Attack count归零。
image
image

然后设置一下ComboReset。
image

接着找到动画Combo_01_1_Montage,然后在攻击后摇前,大概在8后,右键加一下动画通知。
image

在动画结束时也加一下动画通知。
image

动画234也一样。
image
image
image

加完通知后,接着我们使用下通知。 打开PlayerCharABP。
image

在ComoStart通知时去做Do Attack。
image

然后再动画播放结束时,把所有的状态设置为初始值。
image

然后在动画蒙太奇里设置下混出混入时间。让混出混入时间远小于本身动画的时间。
image
image
image
image

然后创建一个保存攻击的状态。
image
image

SaveAttack开始时也要保存下。
image

然后把动画蓝图里的DoAttack改成AttackSave就可以连击出连招了。
image
https://github.com/user-attachments/assets/801d8e67-cbcd-4e1b-846b-c73e4299567a

更好的打击感

上面已经把攻击连招讲完了,但是攻击的时候不能转向,他只能朝着一个方向走,手感不是很好。下面完善一下攻击。然后做出攻击时可转向,添加闪避以及伤害通知。

攻击时可转向

一个流畅的动作类游戏,他必须得是非常跟手的。随时都跟着你的操作。在你攻击的时候,他应该也能跟着转向。这样才是一个好的动作游戏的手感。

打开playerchar。

新建一个函数。
image

用这个函数计算最后一次输入。就是要用这个函数获取最后一次键盘是按的哪个方向。这个函数不能单独使用,得配合其它函数使用。

新建一个变量,用来保存我们的输入movement。
image

还要新建一个变量,用来保存我们最后一次输入的角度。
image

我们把角色移动拖进来。
image

把角色最后输入的向量存到Movement Input。
image

我们还需要加一个变量,用来检测砍一刀时,有没有输入向量。
image
image
image

输入角度也保存一下。
image

这样这个函数是算写完了。

然后我们返回事件图表,让每帧都执行一下。
image

然后我们再创建一个函数。用这个函数改变角度。就是要让攻击动画改变角度。
image

添加两个输入。
image

先判断下输入的两个值。
image

然后就可以对角度设置渐变推进。
image
image

也设置下没有速度的时候的情况。
image

然后我们做下动画通知。新建一个文件夹。
image

创建一个AnimNotifyState蓝图。
image
image

打开编辑。新建变量。
image

然后重载一下函数。
image
image

然后找个动画试试。找到攻击这个蒙太奇。
image

添加状态通知。
image
image

表于在这段区间之间都可以转向。就是攻击前摇时可以选择方向。

然后回到RotationByAnim,把InterpSpeed变量小眼睛点开。
image

编译。回到动作就可以看到这个变量了。
image

然后设置这个渐变速度为10。
image

然后把其它的动画也设置下。
image
image
image

然后接下来我们开始写这个动画通知的函数。
image

我们再重载下两个函数。
image
image
image

现在攻击时可以转向了。
https://github.com/user-attachments/assets/f2124445-7383-46ad-b3cc-a05e40cee7fb

伤害通知

直接在动画序列中加通知。
image

接着我们回到playerchar写伤害逻辑。
image
image
image
image

然后我们返回动画蓝图。
image
image

运行可以看到攻击的范围。
https://github.com/user-attachments/assets/d1f9993d-0546-469f-a9c4-45f4dbdc1316

闪避

我们先加一下按键。
image

然后我们找个动画。创建动画蒙太奇。
image
image

然后回到动画。把启动根运动勾上。
image

角色就能跟着胶囊体动了。

然后我们写一下闪避的逻辑。
image
image

在控制里也加一下。
image

编译保存运行。
https://github.com/user-attachments/assets/6e411bef-0ddc-465b-b158-d4b264e40361

但反复按会鬼畜。这里改一下。
image

然后在动画播放完后状态设置为不翻滚。
image

编译保存运行。

现在反复按不会鬼畜了。

这里可以加速动画播放让翻滚快点。
image

闪避时可转向

image
直接给这个通知拉满,只要在翻滚的过程就能改变方向。

修复攻击时闪避后不能再攻击的Bug

因为攻击中闪避而没有走ComboReset。所以IsAttack永远为真。所以在闪避后再做一下ComboReset就可以了。
image

闪避时不能攻击

如果在闪避中,就不要给角色攻击了。
image

创建敌人

按照惯例,先创建一个文件夹。
image

创建模型

然后创建一个蓝图。
image
image

然后打开它。给它加个模型。
image

调下参数。
image
image

然后改一下这个模型的颜色。
image

再原来的材质上复制多一份。
image

双击新的材质,我们改下颜色。
image
image

点应用,保存。回来看,白色的材质球就做好了。
image

然后回到AIChar,模型换个颜色。
image

敌人AI

然后我们创建一个AIController。
image
image

然后还要一个行为树。
image
image

打开AICharController。在事件开始时运行行为树。
image

然后在AIChar里关联上AICharController。
image

编译保存。然后我们打开行为树,新建一个黑板。
image

给AI也创建下动画蓝图。
image
image
image

然后打开它。
image

双击状态机添加状态。
image

因为都是小白人,所以AI也可以用之前创建的混合空间。
image

speed提升为变量。
image

编译保存。
image

然后回到AIChar。使用刚才的动画蓝图。
image

然后给敌人加下武器。加下骨骼网格体。
image
image
image
image

然后加一下盾。
image

然后我们返回动画蓝图。
image
image
image
image
image

我们动画蓝图算是写完了。AI也会根据它移动的速度来决定它动画是走是跑还是站立。这些都是和主角一样的。然后我们写下行为树。
image
image

然后新建一个装饰器。
image
image

用来检测有没有玩家。
image

然后取一下位置。
image

然后需要加一下球形检测。
image
image

Object Types提升为变量。
image

半径给1000。
image

然后Draw Debug Type改成持久。
image

最后连上。
image

输出会Out Hits打开。
image
image

然后把每个数组再break一下。
image

如果这个球体检测到玩家,那就转化为玩家。检测不到就什么都不干。
image
image

然后as player char给他设置黑板值。
image
image

然后把Key提升为变量。
image

把小眼睛点亮,这样你在行为树上才能看到这个变量。
image

然后返回节点也连上。在循环结束之后返回为真。
image

编译保存。返回行为树。添加装饰器。
image

然后点击黑板,在黑板上新建一个值。
image
image

改下基类。
image

保存。
image

把顺序换成选择。
image
image

然后再来个顺序。再加个装饰器。
image
image

再来个顺序。
image
image

设置未设置。用于没检测到玩家的操作。
image

检测到玩家就走向玩家。
image
image

保存。给场景添加一个导航网格体边界体积。
image
image

调整导航网格体边界体积,让它覆盖整个场景。保存运行。现在可以看到敌人走过来了。
https://github.com/user-attachments/assets/b852159c-7af5-4355-939e-5cbf04939564

参数调整

AI追到你后的等待时间可以自行调整。
image

敌人的速度也可以调整下。
image

添加巡逻

新建一个服务。
image
image

打开,重载下接收Tick AI。
image
image

然后先取一下位置。
image

然后得到一个随机可以到达的位置。
image

设置半径为500。
image

然后把得到的位置设置为黑板键。
image

把Key提升为变量。改一名。
image

小眼睛打开。
image

最后把线连上。
image

编译保存。

返回行为树。添加服务。
image
image

返回黑板。增加一个向量变量。
image

返回行为树,把Target Location改为目的地。
image

移动到目的点。
image

保存。运行。现在AI能随机走动了。

攻击

然后在行为树新加一个任务,让敌人攻击。
image
image

打开,重载下接收执行AI函数。
image
image

转化为AIChar,直接播放蒙大奇。
image

给AI找个攻击动画。
image

创建一个动画蒙太奇。
image
image

打开动画,启动下根运动。让他播放这个动画时有位移。
image

返回任务,指定动画资产为Attack_08_Montage。
image

最后返回执行结果。
image

然后返回行为树。添加攻击。
image

编译保存运行。现在敌人会先过来再攻击,等待两秒再攻击。
https://github.com/user-attachments/assets/7590acab-f16d-413a-9b09-176d8f08e8de

添加伤害

玩家打AI

先给AI加点变量。
image
image

接着回到主角这里,编辑攻击逻辑。
image
image
image
image
image

基础伤害给到10。
image

主角这边的攻击伤害算写完了。
image

返回AIChar,继续写敌人被打的逻辑。
image
image

保存编译运行。
image

打印了很多。需要关掉一些没必要的碰撞。
image

主角这边也改一下。
image

现在的攻击输出就正常了。
image

因为AI会档主角的摄像机,所以AI的胶囊机碰撞的自定义下。
image

死亡

先加个变量判断是否死亡。
image
image
image
image

UI

敌人血条

新建UI文件夹。
image

我们做一下血条。新建UI控件蓝图。
image
image
image

然后打开它。新加画布。
image

然后加个进度条。
image

锚点改成中间。
image

然后把位置设置回来。
image

对齐都改成0.5。
image

尺寸y改成15。
image

填充颜色改成红色。
image

然后创建绑定。
image
image

添加对象变量。
image

用现血量除以总血量得到血条的百分比。
image

编译保存。回到AIChar。

添加控件组件。
image

改名为血条。

控件类是AIHPBar。

血条放到头顶上。

给它空间设为屏幕。

编译保存。回到事件图表。

把HPBar拖进来。

这样血条就加上了。

玩家血条
接着我们做一下玩家的血条。

新建个控件蓝图。

编译保存。然后在PlayerChar里加点变量。

然后回到PlayerHPBar创建绑定。

然后我们回到PlayerChar。

编译保存运行。

让玩家受伤
直接在动画Attack08里新建一个通知。

新建通知后,需要一个球形检测。

基本和之前写的玩家攻击逻辑一样。

然后返回PlayerChar。先加个变量。

然后回到AIChar_ABP。

保存编译,运行。现在敌人打玩家,玩家会扣血了。

AI被打动画
找到这个被打动画。

然后创建动画蒙太奇。

打开AIChar。

AI死亡动画
找到这个动画。

创建动画蒙太奇。

返回AIChar编写死亡动画逻辑。

动画要设置根运动。

在动画蒙太奇中不设置启动自动混出。敌人死亡倒地就结束了。

然后找到AI攻击。

让AI攻击前加个判断 ,判断是否正在播动画。

接着回到AIChar。在死亡后删除胶囊体。

编译保存运行。

把AI的攻击动画换成原地的
现在AI攻击会向前,对于游戏来说,玩家不容易闪避。我们给AI换个原地攻击的动画。敌人呆一点比较好。选一个腿没有动的。

然后创建蒙太奇。

动作启动根运动。

在AI攻击蓝图中改用这个动画。

当然,也要加上动画通知。

增加AI攻击前摇时间
打开攻击的动画蒙太奇,再拉一个动作。

把第一段做成0.138。

把前摇速率放慢。

现在敌人的攻击前摇时间加长了,玩家容易闪避了。

玩家被攻击动画
找到玩家被打动画。

然后启用根运动。

创建动画蒙太奇。

然后回到PlayerChar。增加被攻击动画。

每次受到伤害重置下玩家的攻击,防止玩家攻击时被攻击而不能再攻击。

玩家被死亡动画

把红框去掉
image