文章目录
![在这里插入图片描述](https://img-blog.csdnimg.cn/direct/8015ff6dc94143dea200a48d8e409946.gif)
BP_Character 组合攻击
首先我们获取攻击动画,在这里使用的是 Easy Combo Buffering
的攻击动画
![](https://img-blog.csdnimg.cn/direct/9c4855ce066e4bd49d6912c94cfbea64.png)
将动画导出为文件,然后导入动画文件,得到动画序列如下
![](https://img-blog.csdnimg.cn/direct/2ae93cae091343c993977c48a24ff54b.png)
动画重定向到 Quinn 模型上,得到动画序列,然后创建攻击动画的 Montage
![](https://img-blog.csdnimg.cn/direct/e6809702e090417eb6185b64ca3248af.png)
首先要明白的是,一般人物在攻击过程中,其是不会发生移动的,所以我们需要开启 EnableRootMotion
和 Force Root Lock
通过下面操作可以进行批量操作
![](https://img-blog.csdnimg.cn/direct/be0624af75394063938b1cd8d677bc10.png)
开启 EnableRootMotion
和 Force Root Lock
![](https://img-blog.csdnimg.cn/direct/6258878cbb1443f38f1d632f32ac1185.png)
目前攻击动画准备完毕,现在为动画添加 Input 输入,Input 的添加方式有两种,一种是使用 Input Mapping Context,这种较为简单,创建一个 Input Action 然后 map 一个输入就可以
![](https://img-blog.csdnimg.cn/direct/9672e9004fa74866acb89b7cfcc2425d.png)
第二种是通过 Project Settings 添加 Input,首先在 window 下面找到 Project Setting
![](https://img-blog.csdnimg.cn/direct/37de2d69efcf4da4bfac1f2a35d27482.png)
然后找到 Input 中的 Action Mapping 添加动作,这里使用鼠标左键作为攻击输入
![](https://img-blog.csdnimg.cn/direct/4592cd828c284fe18c8983645112cc05.png)
现在有了动画和输入,现在进入 BP_Character 蓝图,该蓝图位置存储在 Game Mode 的 Default Pawn Class 中
![](https://img-blog.csdnimg.cn/direct/c4700cbca1ea4e4492afe413a6fd4ad7.png)
打开 BP_Character 蓝图,使用 Play_Montage 连接 Input 和 动画
![](https://img-blog.csdnimg.cn/direct/55adc6fb0e6e417d879aebbfc3ea6f48.png)
这里的 Retriggerable Delay 教程中说要设置为最长的动画时间长一点点,在这里好像除了放慢了一下速度好像并没有什么效果
光这样还不行,我们需要在动画与动画之间的衔接处使用 Montage 的 AnimNotify 方法设置 IsAttacking 为 Fasle 表示动画可以衔接,这里设置通知事件为 AttackingAgain
![](https://img-blog.csdnimg.cn/direct/72fc91fbdbbb43ea905a35e4707f3329.png)
在所有 Montage 中都设置完毕后,我们回到 ABP_Quinn,去调用通知事件 AttackingAgain
![](https://img-blog.csdnimg.cn/direct/518a0594851d46faa210c16f644c56c2.png)
这样组合攻击处理完毕!
![](https://img-blog.csdnimg.cn/direct/871b79f812cc486085bd02066dcfdf85.gif)
Notify State 检测攻击
由于攻击是一个过程,如果我们使用上一步的 Montage notify 只有一帧的时间进行检测,这里使用 notify state 进行攻击检测
在 Blueprint 文件夹下面创建一个 AnimNotifyState,命名为 ANS_HitDetection
![](https://img-blog.csdnimg.cn/direct/60d1d79c6c1f45958021ea3542039e86.png)
然后进入 Montage 动画里面,使用 Add Notify State 添加 ANS_HitDetection
![](https://img-blog.csdnimg.cn/direct/4c2f4434dedc450aa6dd9085623c4e14.png)
将所有的 Montage 都处理完毕后,我们回到 ANS_HitDetection
中添加 Received Notify Tick
![](https://img-blog.csdnimg.cn/direct/06c1de4eb53e48bc9161123caf940fd5.png)
在函数蓝图中实现如下功能
![](https://img-blog.csdnimg.cn/direct/7f746a2c2f26444a95a7e108f59c42cc.png)
其中蓝色框中的 Hit Detect 是定义在 BP_Character 中的一个函数,接下来我们实现这个函数,这里 Radius 一般设置为25就好,这里要注意的是 Select 的 Count Attack 比默认的多 1
![](https://img-blog.csdnimg.cn/direct/fa52f195112346a09816038025a98718.png)
实现完毕后得到效果如下
![](https://img-blog.csdnimg.cn/direct/5bf67e77704641659f136241132ec0c2.gif)
BP_Character 攻击反馈
在上一步中我们的攻击反馈是直接消失,我们想让人物播放攻击动画代替直接消失,这里的动画我们从 mixamo 中导入
![](https://img-blog.csdnimg.cn/direct/a4e2736830fa4f1cba7fca1960e574c9.png)
从 mixamo 中分别导入两个 前方受击动画和后方受击动画,将其导入到 UE5 中然后重定向
![](https://img-blog.csdnimg.cn/direct/a3c287c8a0f14857a56d52906dcc5595.png)
在攻击检测 HitDetect
函数中,我们直接使用 Apply Damage
和 Event AnyDamage
来对受击人物执行攻击反馈
![](https://img-blog.csdnimg.cn/direct/5e4789e699df40b1be4be5c94650c827.png)
首先我们通过两个 Character 的前向向量的点积的正负值来判断受击方向是 Front 还是 Back 赋值给 IsForward
![](https://img-blog.csdnimg.cn/direct/0e7f01783a5b40c39f997a4735f29efa.png)
然后根据 IsForward 来选取前向动画列表还是后向动画列表,然后随机播放 Montage
![](https://img-blog.csdnimg.cn/direct/b496abe63c8343d58602758efd19cbfe.gif)
BP_Character 生命系统
首先在 BP_Character 中添加两个变量,Health 和 MaxHealth,都设置为100
然后在 Blueprint 文件夹中创建 Widget Blueprint
![](https://img-blog.csdnimg.cn/direct/297f7071683a4ac7b71f9ffa8ac6bbe8.png)
Widget Blueprint Designer 设置如下,记得 Anchors要设置为居中
![](https://img-blog.csdnimg.cn/direct/e974f6167b0a4ec4be1855b89036232b.png)
然后对 Progress Percent 进行绑定,由于这里我们不能够导入变量,所以我们最好设置两个变量
![](https://img-blog.csdnimg.cn/direct/bccc33c2ddd74e2da98aeed4ee0b62a2.png)
这样 Widget Blueprint 设置完毕,接下来我们回到 BP_Character 中进行设置,首先添加一个 Widget Blueprint
![](https://img-blog.csdnimg.cn/direct/6084c971fc864dacb505c7004af91f83.png)
然后给 Widget 绑定 Widget Class,调整 Widget 的 Location 位置
![](https://img-blog.csdnimg.cn/direct/b297ae37367048c5874351bdad491dcc.png)
然后这里要注意将 Space 转化为 Screen,如果是 World 的情况,血条会像纸片绑在人物身上
![](https://img-blog.csdnimg.cn/direct/d457f172fb1e4a07921dd04bbc457fe0.png)
回到 EventGraph 中,在 Event BeginPlay 事件后面添加
![](https://img-blog.csdnimg.cn/direct/bab12aa828334d7da91a84088a11590c.png)
这一步还只是让 Character 有了血条,我们在 Character 中设置一个 UpdateHealth 函数,在每次收到伤害时更新 Health
![](https://img-blog.csdnimg.cn/direct/9589a065b9f14ef9ba89252ccbdf15ff.png)
这样 Character 就有了血条了
![](https://img-blog.csdnimg.cn/direct/008ac022ea4a4fb589710cbf1ad54c85.png)
但是这里的血条并不会根据人物的大小变化而变化,同时发现前面的 Character 血条并没有满血,其原因是因为在 Character 中失败了,没有获取到控制权导致初始化失败
![](https://img-blog.csdnimg.cn/direct/cd7b96ad40a145a5982c90ccf2c2ee1f.png)
在 Cast Failed 处连接 Widget 初始化
![](https://img-blog.csdnimg.cn/direct/0884f1982e104c70ba01249ef72b9ee9.png)
得到如下效果
![](https://img-blog.csdnimg.cn/direct/a9f106c55b2d4d21b54d9d497d1ce414.gif)
这里可以发现攻击了多次,是 Notify State 导致的,每检测到一次就会收到一次伤害,所以在 Event AnyDamage 中 我们设置一个变量 IsBeAttacking 来判断是否正在被攻击
![](https://img-blog.csdnimg.cn/direct/bf991abbb10a426a9f9d8d7eb3534609.png)
得到效果如下
![](https://img-blog.csdnimg.cn/direct/d0e303138a96471486b9ff602fd32b7d.gif)
BP_Character 死亡效果
同样的这里从 mixamo 中下载死亡动画,这里下载了两个,一个是向前倒地一个是向后倒地,重定向创建 Montage 之后,我们可以通过 Montage 中的 Montage Sections 来循环倒地动画避免动画又突然站起来
![](https://img-blog.csdnimg.cn/direct/fdfc96ccaf1f4739a5ad45d99d000518.png)
然后在BP_Character 中修改两处地方
![](https://img-blog.csdnimg.cn/direct/a411bd900df842f6a7371ce0aa44613c.png)
得到的效果如下,这里要注意不要开启 RootMotion,不然到不了地就飞起来了
![](https://img-blog.csdnimg.cn/direct/65a44ff2fad145fbb958b6ab3d76e5f9.gif)
BP_Character 武器系统
这里我们从 OpenGameArt 中下载一个剑的模型,网站:Lowpoly Sword | OpenGameArt.org
![](https://img-blog.csdnimg.cn/direct/2fb42f93063048acab90d680b2ab20c1.png)
首先创建一个材质来处理贴图,控制一下 Metallic 和 Roughness
![](https://img-blog.csdnimg.cn/direct/fa1b31f5fc5041d3a81ebb8c7817fb10.png)
处理完毕后,我们回到 Sword 的 Static Mesh 中创建两个 Sockets
![](https://img-blog.csdnimg.cn/direct/3aa27280be5d4ca0abbdee740100cecc.png)
创建完毕之后我们将这个网格体移动到 Character 中去处理
![](https://img-blog.csdnimg.cn/direct/9120f42f9d48485fad0e0605e535f808.png)
处理完毕后,我们需要修改 Hit Detect 中的检测距离,修改攻击范围
![](https://img-blog.csdnimg.cn/direct/3b3962c0446a4fd28a57435b28e5f184.png)
得到效果如下
![](https://img-blog.csdnimg.cn/direct/81e929b2307d4ce39f0750454b91f8ac.gif)
BP_Enemy 初始化和行为树
首先利用 BP_Character 创建一个子类作为敌人 BP_Enemy
![](https://img-blog.csdnimg.cn/direct/d447f9f776bf4d938a240e9807700247.png)
这里为了让敌人和我们自身有不同之处,我们可以修改 BP_Enemy 的 Materials 的颜色
这里先复制一下原来的 Meterials
![](https://img-blog.csdnimg.cn/direct/89bcb7803d664c9fb45cbb4bb84b4d9e.png)
勾选 tint 给他设置为红色
![](https://img-blog.csdnimg.cn/direct/92f42d9e544c44d18c43f05b21aba147.png)
然后我们就可以得到一个红色的人
![](https://img-blog.csdnimg.cn/direct/1c052c1ec3394b5ab02debb07a92bfdf.png)
做了一些变异之后,我们可以开始我们的行为树的创建,首先右键创建两个AI Asset:分别是Behavior Tree 和 Blackboard,分别命名为 BT_Enemy 和 BB_Enemy
![](https://img-blog.csdnimg.cn/direct/14f73ef28a824f01b7ef5039ff7b7498.png)
然后在 Behavior Tree 中 配置 Blackboard
![](https://img-blog.csdnimg.cn/direct/c44a1c9108f24bf98ae6621eef6d553c.png)
在这里创建三个 Task,其中 Move To 是 自带的 Task,其他两个是 BTTask_GetPlayerLocation 和 BTTask_Attack
首先配置 BTTask_GetPlayerLocation,这个任务是需要获得玩家的位置,要注意使用 Set Blackboard Value as Object 将 Character 丢出去,并设置一个 key 命名为 Player
![](https://img-blog.csdnimg.cn/direct/d1d36bd57e604389a8feb99617b8015e.png)
在外面的 Blackboard 中我们需要设置一个 actor 对象来接受这个 Character
![](https://img-blog.csdnimg.cn/direct/af6ea315767340a49cfad5bb0de3960d.png)
然后在 Behavior Tree 中设置 Player 为 Player
![](https://img-blog.csdnimg.cn/direct/732e280b68d54fee9e01e2b8063af30d.png)
同时我们也把 Move To 也设置为 Player
在设置 BTTask_Attack 事件之前,我们需要在 BP_Character 中创建两个时间,一个是 Attack 一个是 Death
Attack的蓝图如下
![](https://img-blog.csdnimg.cn/direct/3ab599a7cd3c48f4a8565bd3782e6117.png)
Death的蓝图如下
![](https://img-blog.csdnimg.cn/direct/7b522e6c2cda42769c213a4af8b0b22e.png)
然后配置 BTTask_Attack 事件
![](https://img-blog.csdnimg.cn/direct/cf0f032d4610498ba8bc92c6474e17a3.png)
得到效果如下
![](https://img-blog.csdnimg.cn/direct/c6524476fd994d0590fa6a83f575c236.gif)