96SEO 2026-02-19 19:18 8
Widget然后手动地逐层添加到主界面设定其位置变换容易造成结构混乱和逻辑混乱在蓝图内创建蓝图

面板的位置变换获取添加到的父级控件的对象实例进行界面的添加父级控件的对象实例又有自己的父级对象层层获取实例需要引入大量头文件和实例耦合性非常高。
面板的生成、销毁、显示、隐藏、冻结、激活等生命周期功能往往在复杂的
“模态显示不允许操作父窗体”普通开发模式下需要手动维护弹窗类型
面板设定显示类型包括无影响DoNothing隐藏其他HideO***r反向反转Reverse等几种不同的类型在
管理器下实现不同的生命周期函数提供遮罩管理器定义不同透明度与可否穿透遮罩的类型。
开发需要加载数量众多的图片等资源用普通的方式进行加载十分麻烦。
管理器进行消息的传递一般是使用委托或者回调函数等但是这种方式有其局限性面对大量不同类型的方法调用时需要定义很多不同类型的委托。
使用框架的反射事件系统以及注册事件系统爱怎么调就怎么调随心所欲。
Widgets/Layout/Anchors.h#pragma
布局类型UPROPERTY(EditAnywhere)ELayoutType
类型的面板使用指定影响的范围UPROPERTY(EditAnywhere)ELayoutLevel
面板类型UPROPERTY(EditAnywhere)EPanelShowType
弹窗遮罩透明度UPROPERTY(EditAnywhere)EPanelLucencyType
锚点UPROPERTY(EditAnywhere)FAnchors
paddingUPROPERTY(EditAnywhere)FMargin
的水平布局UPROPERTY(EditAnywhere)TEnumAsByteEHorizontalAlignment
的垂直布局UPROPERTY(EditAnywhere)TEnumAsByteEVerticalAlignment
面板属性初始化工作留到蓝图内手动配置UPROPERTY(EditAnywhere)FUINature
{SetVisibility(ESlateVisibility::Visible);
{SetVisibility(ESlateVisibility::Visible);
{SetVisibility(ESlateVisibility::Hidden);
{GENERATED_BODY()public:virtual
ActiveOverlay;UPROPERTY()TArrayUOverlay*
ActiveCanvas;TArrayUCanvasPanel*
TranslucenceLucency;FLinearColor
CastUCanvasPanel(GetRootWidget());//
使自身忽略鼠标事件检测但子控件可以接受检测RootCanvas-SetVisibility(ESlateVisibility::SelfHitTestInvisible);//
WidgetTree-ConstructWidgetUImage(UImage::StaticClass());//
EnterPanelDoNothing(UCanvasPanel*
EnterPanelHideO***r(UCanvasPanel*
EnterPanelReverse(UCanvasPanel*
UDDFrameWidget::AdvanceLoadPanel(FName
(AllPanelGroup.Contains(PanelName)
LoadedPanelName.Contains(PanelName))return;//
进行异步加载BuildSingleClassWealth(EWealthType::Widget,
添加面板名到已加载面板名组LoadedPanelName.Push(PanelName);
UDDFrameWidget::ShowUIPanel(FName
(ShowPanelGroup.Contains(PanelName)
PopPanelStack.Contains(PanelName))return;//
(!AllPanelGroup.Contains(PanelName)
!LoadedPanelName.Contains(PanelName))
{BuildSingleClassWealth(EWealthType::Widget,
AcceptPanelWidget);LoadedPanelName.Push(PanelName);return;}//
(AllPanelGroup.Contains(PanelName))
*AllPanelGroup.Find(PanelName);//
UDDFrameWidget::AcceptAdvancePanel(FName
CastUDDPanelWidget(BackWidget);//
ObjectNamePanelWidget-RegisterToModule(ModuleIndex,
添加到全部组AllPanelGroup.Add(BackName,
UDDFrameWidget::AcceptPanelWidget(FName
CastUDDPanelWidget(BackWidget);//
ObjectNamePanelWidget-RegisterToModule(ModuleIndex,
添加到全部组AllPanelGroup.Add(BackName,
进行第一次显示执行进入界面方法DoEnterUIPanel(BackName);
UDDFrameWidget::DoEnterUIPanel(FName
*AllPanelGroup.Find(PanelName);//
(PanelWidget-UINature.LayoutType
CastUCanvasPanel(RootCanvas-GetChildAt(RootCanvas-GetChildrenCount()
WidgetTree-ConstructWidgetUCanvasPanel(UCanvasPanel::StaticClass());WorkLayout-SetVisibility(ESlateVisibility::SelfHitTestInvisible);UCanvasPanelSlot*
RootCanvas-AddChildToCanvas(WorkLayout);FrameCanvasSlot-SetAnchors(FAnchors(0.f,
1.f));FrameCanvasSlot-SetOffsets(FMargin(0.f,
添加到激活组ActiveCanvas.Push(WorkLayout);}}//
WidgetTree-ConstructWidgetUCanvasPanel(UCanvasPanel::StaticClass());WorkLayout-SetVisibility(ESlateVisibility::SelfHitTestInvisible);UCanvasPanelSlot*
RootCanvas-AddChildToCanvas(WorkLayout);FrameCanvasSlot-SetAnchors(FAnchors(0.f,
1.f));FrameCanvasSlot-SetOffsets(FMargin(0.f,
添加到激活画布组ActiveCanvas.Push(WorkLayout);}//
(PanelWidget-UINature.PanelShowType)
EPanelShowType::DoNothing:EnterPanelDoNothing(WorkLayout,
EPanelShowType::HideO***r:EnterPanelHideO***r(WorkLayout,
EPanelShowType::Reverse:EnterPanelReverse(WorkLayout,
UDDFrameWidget::DoShowUIPanel(FName
UDDFrameWidget::EnterPanelDoNothing(UCanvasPanel*
UDDFrameWidget::EnterPanelDoNothing(UOverlay*
UDDFrameWidget::EnterPanelHideO***r(UCanvasPanel*
UDDFrameWidget::EnterPanelHideO***r(UOverlay*
UDDFrameWidget::EnterPanelReverse(UCanvasPanel*
UDDFrameWidget::EnterPanelReverse(UOverlay*
提前加载面板资源就立刻显示面板这会导致面板没加载出来就被使用。
正在预加载但是收到显示到界面命令时进行循环检测是否加载完毕加载完毕则进行显示void
正在提前加载但是已经收到显示命令的界面名简称预显示组TArrayFName
WaitShowTaskName;DDFrameWidget.cpp
UDDFrameWidget::ShowUIPanel(FName
(ShowPanelGroup.Contains(PanelName)
PopPanelStack.Contains(PanelName))return;if
(!AllPanelGroup.Contains(PanelName)
!LoadedPanelName.Contains(PanelName))
{BuildSingleClassWealth(EWealthType::Widget,
AcceptPanelWidget);LoadedPanelName.Push(PanelName);return;}//
如果预加载未完成就调用显示命令启动循环检测函数检测到预加载完成的时候显示
(!AllPanelGroup.Contains(PanelName)
LoadedPanelName.Contains(PanelName)
!WaitShowPanelName.Contains(PanelName))
添加名字到预显示名字组WaitShowPanelName.Push(PanelName);//
秒检测一次InvokeRepeat(WaitShowTaskName,
UDDFrameWidget::WaitShowPanel);return;}//
UDDFrameWidget::WaitShowPanel()
(AllPanelGroup.Contains(WaitShowPanelName[i]))
执行进入界面方法DoEnterUIPanel(WaitShowPanelName[i]);//
添加到完成组CompleteName.Push(WaitShowPanelName[i]);}}//
i)WaitShowPanelName.Remove(CompleteName[i]);//
0)StopInvoke(WaitShowTaskName);
UDDFrameWidget::EnterPanelDoNothing(UCanvasPanel*
WorkLayout-AddChildToCanvas(PanelWidget);PanelSlot-SetAnchors(PanelWidget-UINature.Anchors);PanelSlot-SetOffsets(PanelWidget-UINature.Offsets);//
必须一致ShowPanelGroup.Add(PanelWidget-GetObjectName(),
面板的进入界面生命周期PanelWidget-PanelEnter();
UDDFrameWidget::EnterPanelDoNothing(UOverlay*
WorkLayout-AddChildToOverlay(PanelWidget);PanelSlot-SetPadding(PanelWidget-UINature.Offsets);PanelSlot-SetHorizontalAlignment(PanelWidget-UINature.HAlign);PanelSlot-SetVerticalAlignment(PanelWidget-UINature.VAlign);//
必须一致ShowPanelGroup.Add(PanelWidget-GetObjectName(),
面板的进入界面生命周期PanelWidget-PanelEnter();
RCStatePanel、RCShortCutPanel、RCMiniMapPanel、RCBigMapPanel、RCMenuPanel
MiniMapPanel作为状态栏面板和小地图面板。
然后分别将它们的父类指定为
在游戏主界面类里重写初始化函数添加界面到窗口并显示状态栏和小地图面板。
{AddToViewport();ShowUIPanel(StatePanel);ShowUIPanel(MiniMapPanel);
UDDFrameWidget::DoEnterUIPanel(FName
*AllPanelGroup.Find(PanelName);if
(PanelWidget-UINature.LayoutType
CastUCanvasPanel(RootCanvas-GetChildAt(RootCanvas-GetChildrenCount()
WidgetTree-ConstructWidgetUCanvasPanel(UCanvasPanel::StaticClass());WorkLayout-SetVisibility(ESlateVisibility::SelfHitTestInvisible);UCanvasPanelSlot*
RootCanvas-AddChildToCanvas(WorkLayout);FrameCanvasSlot-SetAnchors(FAnchors(0.f,
1.f));FrameCanvasSlot-SetOffsets(FMargin(0.f,
UnActiveCanvas.Pop();ActiveCanvas.Push(WorkLayout);}switch
(PanelWidget-UINature.PanelShowType)
EPanelShowType::DoNothing:EnterPanelDoNothing(WorkLayout,
EPanelShowType::HideO***r:EnterPanelHideO***r(WorkLayout,
EPanelShowType::Reverse:EnterPanelReverse(WorkLayout,
CastUOverlay(RootCanvas-GetChildAt(RootCanvas-GetChildrenCount()
WidgetTree-ConstructWidgetUOverlay(UOverlay::StaticClass());WorkLayout-SetVisibility(ESlateVisibility::SelfHitTestInvisible);UCanvasPanelSlot*
RootCanvas-AddChildToCanvas(WorkLayout);FrameCanvasSlot-SetAnchors(FAnchors(0.f,
1.f));FrameCanvasSlot-SetOffsets(FMargin(0.f,
UnActiveOverlay.Pop();ActiveOverlay.Push(WorkLayout);}switch
(PanelWidget-UINature.PanelShowType)
EPanelShowType::DoNothing:EnterPanelDoNothing(WorkLayout,
EPanelShowType::HideO***r:EnterPanelHideO***r(WorkLayout,
EPanelShowType::Reverse:EnterPanelReverse(WorkLayout,
}编译后运行游戏可以看到状态栏和小地图面板都出现在界面上。
说明我们的
作为专业的SEO优化服务提供商,我们致力于通过科学、系统的搜索引擎优化策略,帮助企业在百度、Google等搜索引擎中获得更高的排名和流量。我们的服务涵盖网站结构优化、内容优化、技术SEO和链接建设等多个维度。
| 服务项目 | 基础套餐 | 标准套餐 | 高级定制 |
|---|---|---|---|
| 关键词优化数量 | 10-20个核心词 | 30-50个核心词+长尾词 | 80-150个全方位覆盖 |
| 内容优化 | 基础页面优化 | 全站内容优化+每月5篇原创 | 个性化内容策略+每月15篇原创 |
| 技术SEO | 基本技术检查 | 全面技术优化+移动适配 | 深度技术重构+性能优化 |
| 外链建设 | 每月5-10条 | 每月20-30条高质量外链 | 每月50+条多渠道外链 |
| 数据报告 | 月度基础报告 | 双周详细报告+分析 | 每周深度报告+策略调整 |
| 效果保障 | 3-6个月见效 | 2-4个月见效 | 1-3个月快速见效 |
我们的SEO优化服务遵循科学严谨的流程,确保每一步都基于数据分析和行业最佳实践:
全面检测网站技术问题、内容质量、竞争对手情况,制定个性化优化方案。
基于用户搜索意图和商业目标,制定全面的关键词矩阵和布局策略。
解决网站技术问题,优化网站结构,提升页面速度和移动端体验。
创作高质量原创内容,优化现有页面,建立内容更新机制。
获取高质量外部链接,建立品牌在线影响力,提升网站权威度。
持续监控排名、流量和转化数据,根据效果调整优化策略。
基于我们服务的客户数据统计,平均优化效果如下:
我们坚信,真正的SEO优化不仅仅是追求排名,而是通过提供优质内容、优化用户体验、建立网站权威,最终实现可持续的业务增长。我们的目标是与客户建立长期合作关系,共同成长。
Demand feedback