让我们继续《塞尔达传说》中林克技能的制作!!!
UE版本:5.6.0
VS版本:2022
本章节的核心目标:技能面板
先让我们看一下完成后的效果:
第14章效果
本章节项目链接:
通过网盘分享的文件:14_技能面板
链接: https://pan.baidu.com/s/1BcNuIlxd2elJZd70RfJgug 提取码: rd7w
–来自百度网盘超级会员v3的分享
已经完成的功能:
动作 | 按键 | 是否完成 |
---|---|---|
移动 | W、S、A、D | 完成 |
疲劳 | 无 | 完成 |
冲刺 | Left Shift | 完成 |
滑行与跳跃 | Space | 完成 |
下落 | 无 | 完成 |
预计制作的技能:
技能(符文) | 按键 | 是否完成 |
---|---|---|
RBB(方向遥控炸弹) | 未设定 | 未开始 |
RBS(圆形遥控炸弹) | 未设定 | 未开始 |
Mag(磁铁) | 未设定 | 未开始 |
Stasis(时间静止) | 未设定 | 未开始 |
Ice(冻结) | 未设定 | 未开始 |
UI交互
UI面板 | 按键 | 是否完成 |
---|---|---|
打开(关闭)技能面板 | Tab | 进行中 |
本章节的项目文件:
技能的图标:
说明:每种技能共有4个图标,用来表示4个不同的状态。
Disable_Hover_Pressed:表示的是鼠标在未选中的图标上悬停和按下的效果。
Disable_Normal:表示的是未选中的图标(正常状态下的显示)。
Enable_Hover_Pressed:表示的是鼠标在选中的图标上悬停和按下的效果。
Enable_Normal:表示的是选中的图标显示的效果。
0.导入素材
将文件夹内的图片全部拖拽进UE中。
为了防止模糊,我们将这些图片的压缩方式设置为UserInterface2D
具体操作为:全选图片=》右键【资产操作】=》【编辑属性矩阵中的选择】
选择【压缩】=》压缩设置【UserInterface2D】
1.ZSCharBase.h中新建符文的枚举类
UENUM(BlueprintType)
enum class ERunes : uint8
{
R_EMAX UMETA(DisplayName = "EMAX"),
R_RBB UMETA(DisplayName = "方形遥控炸弹"),
R_RBS UMETA(DisplayName = "圆形遥控炸弹"),
R_Mag UMETA(DisplayName = "磁铁"),
R_Stasis UMETA(DisplayName = "时间静止"),
R_Ice UMETA(DisplayName = "冻结")
};
UCLASS()
class ZELDARSKILLS_API AZSCharBase : public ACharacter
{
GENERATED_BODY()
public:
};
2.制作 - 显示技能图标用的格子
目的1: 方便添加和管理图标的显示。
目的2: 用于选中技能事件的逻辑交互(我们得获知玩家点击到了哪一个技能,然后才能执行后续的逻辑)。
2.1 新建用户控件蓝图(命名为:UI_RuneSlot)
命名为UI_RuneSlot,用于显示技能图标。
2.2 为UI_RuneSlot添加尺寸框
尺寸框(Size Box)作用:控制子控件尺寸的核心布局容器。在这里我们用到了它的子布局:宽度重载和高度重置。
具体而言:添加尺寸框到UI_RuneSlot下后,勾选:宽度重载和高度重载,并将其值设置为250,而后选择屏幕上所需。
2.3 为UI_RuneSlot添加勾选框
勾选框(Check Box)作用:在本次项目而言,主要作用为与鼠标进行交互,能够根据鼠标当前的一个操作情况显示图片。它的尺寸大小由尺寸框控制。
重命名为CB,并勾选其为变量。后续在蓝图中有用。
2.3.1(测试)为勾选框添加一张任意图片
目的:根据这张技能图标显示情况,获取到图片在勾选框应该显示的大小。如下图所示,明显图片填入后偏大(因为这个图片是512x512的)。
将图片的大小(Image Size)设置为250和250,就刚好合适(记下这个值,后面我们在蓝图中用得到)。
2.3.2(可选)禁用键盘选中技能图标
如果你不希望玩家通过键盘来选择符文,你可以取消勾选框内的该属性。
2.3.3(可选)调整勾选框内显示的图片
不调整的话,勾选框内显示的图片与你导入的图片相比会偏暗。这是由勾选框的前景颜色所引起的,取消继承,并将前景颜色改为全白既可以解决这个问题。
2.4 自定义添加图片功能(UI_RuneSlot蓝图)
2.4.1(蓝图)触发事件和设置的目标属性
是编辑器内部的功能:Event Pre Construct 触发。设置的目标属性是勾选框的样式:Make Check Box Style。
2.4.2(蓝图)设置Unchcked Image
Unchecked Image的值通过Make Slate Brush赋值。这个笔刷绘制用的“颜料”,就是我们的素材。接下来为我们的笔刷准备“颜料”
(1)Make Slate Brush的Image_Size设置为:(250,250)。
(2)新建变量(Texture 2D【纹理2D】),并命名为:IMG_D_N:用于接收名字带有Disabled_Normal的图片。Make Slate Brush的Image设置为:IMG_D_N。
2.4.3(蓝图)设置Unchecked Hovered Image和Unchecked Pressed Image
与2.4.2的操作完全一致。
2.4.4(蓝图)设置剩下的情况
2.4.5(蓝图)变量细节设置
为了让这些变量可以由我们手动进行赋值(添加图片),因此我们要勾选可编辑实例和生成时公开。
2.4.6(蓝图,可选)Foreground Color 设置
2.4.7(完成)功能完成示意图
2.5 选中符文的逻辑交互(UI_RuneSlot蓝图)
2.5.1(蓝图)添加事件-勾选状态变化时
当玩家点击UI_RuneSlot后触发的事件。
2.5.2(蓝图)新建事件分发器
事件分发器的作用:用于管理和调度事件的传递与响应。它允许广播事件,其他对象可根据需要订阅这些事件,从而实现对象间的消息传递。
新建一个事件分发器,命名为OnClicked,我们让它传递如下两个参数:
(1)新建变量(文本)Name:用于传递点击的符文名字
(2)新建变量(ERunes)RuneType:用于传递点击的符文类型。
PS:记得勾选 (1)可编辑实例和(2)生成时公开
2.5.3(蓝图)新建函数获取设置格子选中状态
目的:方便设置当前格子的选中状态。
(1)新建一个函数:命名为CheckStatus
(2)内部逻辑:设置勾选框的Checked即可。
2.5.4(完成)功能完成示意图
编译执行后,回到UI_RuneSlot设计器界面,显示如下内容,为该部分功能完成。
3.制作 - 技能面板
目的1:显示所有的技能(UI_RuneSlot)
目的2:管理技能选中逻辑
3.1 新建C++脚本(命名为:ZSRuneSelections)
3.2 创建基于ZSRuneSelections的蓝图类
右键ZSRuneSelections,选择创建基于ZSRuneSelections的蓝图类,并命名为UI_RuneSelections,放到UI文件夹下。
3.3 搭建技能面板
3.3.1(UI设计)添加画布面板
(1)添加画布面板;
(2)为画布面板,添加一个背景模糊(Background Blur),调整其参数:全覆盖,将偏移量置为0,模糊强度设置为1。【添加背景模糊的目的:让打开技能面板的时候,背景显示模糊。】
3.3.2(UI设计)添加水平框
目的:管理技能。
参数设置:
(1)锚点:中心
(2)位置X:0;位置Y:0;
(3)对齐:(0.5,0.5)【说明:中心位置】;
(4)尺寸X:1250【说明:有5个技能,每个技能长250,因此 为5x250=1250】。
(5)尺寸Y:250【说明:高度就是250】
(6)重命名:HB_RuneContainer,并勾选其为变量
3.4 添加格子到技能面板中
拖拽5个UI_RuneSlot到水平框下。
3.5 设置UI_RuneSlot的参数
以RBS为例。
3.6 交互文本
创建一个文本,该文本的作用是显示当前选中的技能名字。设置成如下图所示,并记得勾选其为变量。
4. 代码 - 选择技能
4.1 技能面板与角色的交互
4.1.1 角色获知当前选中的技能
简单来说:ZSRuneSelections:告知ZSCharBase,当前选中的技能是谁。
具体而言:
ZSCharBase.h:
// 当前选中的符文
UPROPERTY(EditAnywhere, Category = "Runes")
ERunes ActiveRune{ ERunes::R_EMAX };
ZSRuneSelections.h:
// Fill out your copyright notice in the Description page of Project Settings.
#pragma once
#include "CoreMinimal.h"
#include "Blueprint/UserWidget.h"
#include "ZSCharBase.h"
#include "ZSRuneSelections.generated.h"
/**
*
*/
UCLASS()
class ZELDARSKILLS_API UZSRuneSelections : public UUserWidget
{
GENERATED_BODY()
public:
UPROPERTY(EditAnywhere, BlueprintReadWrite)
AZSCharBase* playerRef;
UFUNCTION(BlueprintCallable)
// 设置:角色当前选中的技能
void SelectedRuneType(ERunes RuneType);
};
ZSRuneSelections.cpp:
// Fill out your copyright notice in the Description page of Project Settings.
#include "UI/ZSRuneSelections.h"
void UZSRuneSelections::SelectedRuneType(ERunes RuneType)
{
// 玩家选择技能
if (playerRef)
{
playerRef->ActiveRune = RuneType; // 更新玩家选中的技能
}
}
4.2 UI_RuneSelections管理UI_RuneSlot
我们希望通过UI_RuneSelections去管理所有的技能格子(UI_RuneSlot)。
4.2.1(蓝图)注册UI_RuneSlot的OnClicked事件的响应函数
通过UI_RuneSelections注册UI_RuneSlot的OnClicked事件的响应函数。
绑定的响应函数为(自定义的:SelectedRune),该函数的功能如下:
(1)告知角色当前选中的技能(SelectRuneType方法)。
(2)UIRuneSlot根据自身是否被选中设置其选中状态(Check Status)。
(3)UI_RuneSelections的TXT_Hint显示的内容设置为当前选中的符文名字。
整体一览:
5.通过Tab键 - 玩家与技能面板交互
5.1 为UI_ZSLayout的画布面板创建控件切换器
5.1.1 UI_ZSLayout介绍
UI_ZSLayout是本人文章UE5 - 制作《塞尔达传说》中林克的技能 - 9 - 耐力条制作(涉及蓝图)中,创建的。
内部构造很简单,就一个耐力条,如下图
涉及的蓝图逻辑与耐力条的值有关,如下图所示。
蓝图中的Update Stamina函数的内容如下图:
5.1.2 创建控件切换器
选中UI_ZSLayout的画布面板,右键,选择包裹->控件切换器。
重命名为WS,并勾选为变量
5.1.3 创建新的画布面板
存放PB_ST的画布面板重命名为StatusPanel,将新建的画布面板重命名为RunesPanel。
5.1.4 添加UI_RuneSelections
将UI_RunesSelections拖拽到RunesPanel下面,调整大小,全覆盖,偏移值设置为0,并将其勾选为变量。
5.2 输入操作与交互逻辑
5.2.1 UE创建输入操作资产
命名为:IA_ToogleUI
设置其为暂停时触发。
老规矩,到IMC_ZS_Settings添加,并设置为tab键
5.2.2 (cpp)交互逻辑
ZSCharBase.h:
// 声明 唤出技能面板动作
UPROPERTY(EditAnywhere, Category = "Inputs")
UInputAction* ToggleUIAction;
// 指向UZSLayout类型的UObject实例,用于管理UI布局的生命周期
// 该指针由UE5垃圾回收系统自动管理,无需手动释放
UPROPERTY(EditAnywhere, BlueprintReadOnly, Category = "UI")
TObjectPtr<UZSLayout> LayoutRef;
#pragma region ToggleUI
UFUNCTION()
// Tab - 按下 - 触发的函数
void ToggleUI_Started(const FInputActionValue& val);
#pragma endregion
UFUNCTION(BlueprintImplementableEvent)
// 获取角色当前切换的【画布面板】编号
// 如当前的Status Panel 编号为:0
int32 GetWSIndexInfo();
UFUNCTION(BlueprintImplementableEvent)
// 设置角色当前切换的【画布面板】编号,用于与UI交互
// 如我设置为 0:则关闭技能面板显示
void SetWSIndex(int32 index);
ZSCharBase.cpp:
void AZSCharBase::SetupPlayerInputComponent(UInputComponent* PlayerInputComponent)
{
Super::SetupPlayerInputComponent(PlayerInputComponent);
// UI
EIComp->BindAction(ToggleUIAction, ETriggerEvent::Started, this, &AZSCharBase::ToggleUI_Started);
}
void AZSCharBase::ToggleUI_Started(const FInputActionValue& val)
{
AZSPlayerController* PC = Cast<AZSPlayerController>(Controller);
// 判断当前显示的面板是否为 技能面板
if (GetWSIndexInfo() == 1)
{
// ----- 隐藏技能面板 ------
// 关闭鼠标显示
PC->bShowMouseCursor = false;
// 将玩家控制器的输入模式设置为仅游戏模式
PC->SetInputMode(FInputModeGameOnly());
// 继续游戏
PC->SetPause(false);
// 隐藏技能面板 - 将控件切换器的索引设置为0(状态面板)
SetWSIndex(0);
}
else
{
// ----- 显示技能面板 ------
// 显示鼠标 - 我们要用来选技能
PC->bShowMouseCursor = true;
// 设置玩家控制器为游戏与UI混合输入模式,并聚焦到指定UI组件
// 让玩家能够通过鼠标与UI元素进行交互
FInputModeGameAndUI InputHandle;
InputHandle.SetWidgetToFocus(LayoutRef->TakeWidget());
PC->SetInputMode(InputHandle);
// 暂停游戏
PC->SetPause(true);
// 显示技能面板 - 将控件切换器的索引设置为1
SetWSIndex(1);
}
}
5.2.3(蓝图)交互逻辑
先添加IA_ToogleUI到BP_Player中。
实现GetWSIndexInfo:
(1)获取到Layout Ref(也就是咱们的ZSLayoutUI)。
(2)拿到其下的WS,返回激活的Index。
(3)若是LayoutRef的值无效,返回-1(即:什么都不会做)
实现SetWSIndex:
(1)获取到Layout Ref(也就是咱们的ZSLayoutUI)。
(2)(2)拿到其下的WS,设置其Index(为传入的Index)。
第14部分完成啦!!
十分感谢大家的阅读、点赞、收藏!!
如果有不足之处,有疑问之处,有错误地方,欢迎大家在评论区讨论、批评、指正!!!