UE4运用C++和框架开发坦克大战教程笔记(十八)(第55~57集)
55. UI 进入退出动画
HideOther 面板出现时隐藏其他面板
我们先前写的 “根据面板类型 PanelShowType
采用不同的首次进入界面方法”,只写了对于 DoNothing
面板类型的首次进入界面逻辑,接下来我们来补全 HideOther
面板类型的相关逻辑,Reverse
的留到后面再写。
HideOther
面板类型的进入界面后会隐藏同 Level 下的其他面板(不包括弹窗),如果进入的是 Level_All 层级,则隐藏所有层级的其他面板(不包括弹窗)。
DDFrameWidget.cpp
void UDDFrameWidget::EnterPanelHideOther(UCanvasPanel* WorkLayout, UDDPanelWidget* PanelWidget)
{
// 将显示组的同一层级的其他对象都隐藏,如果是 Level_All 就全部隐藏,Level_All 优先级高
for (TMap<FName, UDDPanelWidget*>::TIterator It(ShowPanelGroup); It; ++It) {
if (PanelWidget->UINature.LayoutLevel == ELayoutLevel::Level_All || PanelWidget->UINature.LayoutLevel == It.Value()->UINature.LayoutLevel) {
It.Value()->PanelHidden();
}
}
// 添加 UI 面板到 Layout
UCanvasPanelSlot* PanelSlot = WorkLayout->AddChildToCanvas(PanelWidget);
PanelSlot->SetAnchors(PanelWidget->UINature.Anchors);
PanelSlot->SetOffsets(PanelWidget->UINature.Offsets);
// 将 UI 面板添加到显示组
ShowPanelGroup.Add(PanelWidget->GetObjectName(), PanelWidget);
// 调用进入界面生命周期函数
PanelWidget->PanelEnter();
}
void UDDFrameWidget::EnterPanelHideOther(UOverlay* WorkLayout, UDDPanelWidget* PanelWidget)
{
// 将显示组的同一层级的其他对象都隐藏,如果是 Level_All 就全部隐藏,Level_All 优先级高
for (TMap<FName, UDDPanelWidget*>::TIterator It(ShowPanelGroup); It; ++It) {
if (PanelWidget->UINature.LayoutLevel == ELayoutLevel::Level_All || PanelWidget->UINature.LayoutLevel == It.Value()->UINature.LayoutLevel) {
It.Value()->PanelHidden();
}
}
// 添加到 UOverlay
UOverlaySlot* PanelSlot = WorkLayout->AddChildToOverlay(PanelWidget);
PanelSlot->SetHorizontalAlignment(PanelWidget->UINature.HAlign);
PanelSlot->SetVerticalAlignment(PanelWidget->UINature.VAlign);
// 将 UI 面板添加到显示组
ShowPanelGroup.Add(PanelWidget->GetObjectName(), PanelWidget);
// 调用进入界面生命周期函数
PanelWidget->PanelEnter();
}
为了测试 HideOther
面板类型的面板首次进入界面,我们使用协程方法来安排各面板的出场顺序。等下会新建一个蓝图界面 BigMapPanel,并且将其设置为 HideOther
面板类型。
RCGameUIFrame.h
public:
// 协程方法,用于安排面板出现顺序
DDCoroTask* UIProcess();
RCGameUIFrame.cpp
void URCGameUIFrame::DDInit()
{
AddToViewport();
// 将显示面板代码放到协程方法里,此处替换为启动协程
StartCoroutine("UIProcess", UIProcess());
}
DDCoroTask* URCGameUIFrame::UIProcess()
{
DDCORO_PARAM(URCGameUIFrame);
#include DDCORO_BEGIN()
D->ShowUIPanel("StatePanel");
D->ShowUIPanel("MiniMapPanel");
#include DDYIELD_READY()
DDYIELD_RETURN_SECOND(10.f); // 挂起 10 秒
D->ShowUIPanel("BigMapPanel");
#include DDCORO_END()
}
编译后,在 Blueprint/UIFrame 下创建一个 Widget Blueprint,命名为 BigMapPanel。打开界面并将其父类改成 RCBigMapPanel。随后将界面修改如下:
来到 HUDData,给 Class Wealth Data 添加一个元素如下:
运行游戏,10 秒后大地图面板会显示,原本界面上的状态栏和小地图面板会隐藏。(这里笔者为了方便读者查看效果,换了一张比较明显的图,后面课程也会要求替换)
(注:UI 框架的动图,笔者都会缩短挂起时间或稍作剪辑,所以从动图里看到会觉得变化比较快)
添加面板出现和收起的动画效果
接下来我们实现一下面板的出现和收起的动画效果。由于动画是在 UMG 里面做的,所以我们在面板类声明两个蓝图实现的方法,供 C++ 代码调用蓝图动画节点。
DDPanelWidget.h
public:
// 动画回调函数,返回的 float 是动画时长
UFUNCTION(BlueprintImplementableEvent)
float DisplayEnterMovie();
UFUNCTION(BlueprintImplementableEvent)
float DisplayLeaveMovie();
protected:
// 隐藏 UI 面板
void SetSelfHidden();
protected:
// 隐藏动画任务名
static FName PanelHiddenName;
在面板显示和收起的方法里加入调用动画的语句;并且让面板收起动画播放完毕后再隐藏面板(通过延时方法实现)。
DDPanelWidget.cpp
FName UDDPanelWidget::PanelHiddenName(TEXT("PanelHiddenTask"));
void UDDPanelWidget::PanelEnter()
{
SetVisibility(ESlateVisibility::Visible);
// 调用进入界面动画
DisplayEnterMovie();
}
void UDDPanelWidget::PanelDisplay()
{
SetVisibility(ESlateVisibility::Visible);
// 调用进入界面动画
DisplayEnterMovie();
}
void UDDPanelWidget::PanelHidden()
{
// 修改原本代码如下
// 运行完移出界面动画后调用隐藏函数
InvokeDelay(PanelHiddenName