说明
学习一下如何将Widget蓝图与C++连接起来,将处理逻辑写在C++中
基础
在蓝图中,我们显示Widget是通过一个Actor或者PlayerController,甚至关卡蓝图,利用Create Widget以及 AddToViewPort使得Widget显示在屏幕上的
所以在C++中也是一样,一般来说由于Actor的销毁比如角色死亡,会导致其所有处理逻辑从内存中清除掉。所以将这个功能写在PlayerController类里。
现在为了演示,直接创建了一个Actor类和一个UserWidget类。
Actor类
其主要作用就是显示这个UMG界面,在.h文件中需要一个UserWidget类的指针,用来存储Create出来的对象。相当于上图中的那个变量
然后还需要接受一个类,一般通过TSubClassOf声明,然后在引擎中选择由UserWidget类创建好的蓝图类。相当于上图中CreateWidget模块的Class
//.h
public:
UPROPERTY()
class UXDebugMenuWidget* XDebugMenu;
UPROPERTY(EditAnywhere, Category = "Debug")
TSubclassOf<class UUserWidget> DebugMenuWdgClass;
在.cpp文件中就主要来实现上图中的逻辑
//.cpp
//Create Widget
XDebugMenu = CreateWidget<UXDebugMenuWidget>(GetWorld(), DebugMenuWdgClass);
if (XDebugMenu)
{
XDebugMenu->AddToViewport();
}
CreateWidget函数
在源码中其为一个函数模板,
template <typename WidgetT = UUserWidget, typename OwnerT = UObject>
WidgetT* CreateWidget(OwnerT* OwningObject, TSubclassOf<UUserWidget> UserWidgetClass = WidgetT::StaticClass(), FName WidgetName = NAME_None)
{
static_assert(TIsDerivedFrom<WidgetT, UUserWidget>::IsDerived, "CreateWidget can only be used to create UserWidget instances. If creating a UWidget, use WidgetTree::ConstructWidget.");
static_assert(TIsDerivedFrom<OwnerT, UWidget>::IsDerived
|| TIsDerivedFrom<OwnerT, UWidgetTree>::IsDerived
|| TIsDerivedFrom<OwnerT, APlayerController>::IsDerived
|| TIsDerivedFrom<OwnerT, UGameInstance>::IsDerived
|| TIsDerivedFrom<OwnerT, UWorld>::IsDerived, "The given OwningObject is not of a supported type for use with CreateWidget.");
SCOPE_CYCLE_COUNTER(STAT_CreateWidget);
if (OwningObject)
{
return Cast<WidgetT>(UUserWidget::CreateWidgetInstance(*OwningObject, UserWidgetClass, WidgetName));
}
return nullptr;
}
可以看到有两个信息
- 该函数只能创建UserWidget 对于UWidget需要其他函数
- OwingObject的类型只能是UWidget UWidgetTree APlayerController UGameInstance UWorld其中的一种,其他的类型无法调用该函数
所以当在Actor调用该函数生成Widget的时候,可以利用GetWorld()来得到UWorld类的参数,如果在PlayerController类中直接使用this指针即可
UserWidget类
参考
该类主要是处理UMG在蓝图中的逻辑。需要注意到点就是每个控件的声明是有严格的要求的,以Button控件为例
UPROPERTY(meta = (BindWidget))
class UButton* Button_Tab1;
- UPROPERTY(meta = (BindWidget))
BindWidget是一组专门用来绑定Button这些控件的枚举值中的一个UE官方文档 - 变量名称:C++中控件的名称必须和蓝图中一样
- 用BindWidget标记过的 widget 在 C++ 构造函数中为空,它们稍后在生命周期中被初始化。如果您需要进行类似构造函数的设置,请使用该NativeConstruct()函数。
- 对于按钮响应,可以调用官方设置好的委托函数广播即可OnClicked.AddDynamic(this,&Func);
使用HUD
使用HUD可以对一个GameMode设置使用一种UMG显示
GameMode是控制整个游戏的规则,相当于一种最高权限,可以设置玩家的控制器类型,默认角色类型,HUD类型等等。
当我们将将Widget放在HUD里面是,我们就可以通过GameMode来控制一些数值的显示,实际上是通过PlayerController来更改HUD的
可以将HUD理解为多个Widget的集合,我们将在HUD类里实现在Actor类中的创建Widget的操作。代码都是一样的,只不过OwingObject的类型我们需要修改为PlayerController,因为对于HUD类来说没有GetWorld对象,但其受到每个玩家控制器的控制,具有GetOwningPlayerController()函数来获取PlayerController。
然后就可以在PlayerController类里面使用HUD类对象调用HUD中的方法实现UMG的显示了。