天天看点

combobox添加下拉内容_【UE4】C++基础【02】添加Slate至窗口

【导图】:

combobox添加下拉内容_【UE4】C++基础【02】添加Slate至窗口

【前言】:

奈何水平有限,本篇有多处扯淡的环节,谨慎参考。

【1.】:视频教程

迪迪老湿哪——UE4纯C++与Slate开发沙盒游戏​ke.qq.com

【2.】:UE4 C++基础系列

  • 【UE4】C++基础【00】——通俗易懂 用蓝图来学习 C++ 基础知识
  • 【UE4】C++基础【01】——默认代码扒拉拉(初学者向)
  • 【UE4】C++基础【02】——添加Slate至窗口

【3.】:UI实现原理:

combobox添加下拉内容_【UE4】C++基础【02】添加Slate至窗口

【4.】:常混淆关键词梳理

常混淆的关键词,Slate、UMG、UI、HUD、Widget,前言中先梳理一下。

  • Slate ——
    • 定义——Slate是完全自定义、与平台无关的用户界面框架。简而言之, Slate是跨平台的UI框架
    • 功能实现——
      • 可以用来做应用程序Application的UI(如UE4 Editor 独立exe可执行程序)
      • 工具架Toolbar的UI
      • 更可以做游戏当中的UI (Slate代码创建 VS UMG可视化创建)
  • UMG(Unreal Motion Graphics UI Designer) ——它是 工具 ,一个可视化的UI创建工具,就是WidgetBlueprint的那个Designer环境(Designer负责可视化、Graph负责控件事件定义)
    • 作用——可用来创建UI元素,如HUD、菜单等
    • 核心——Widgets控件
combobox添加下拉内容_【UE4】C++基础【02】添加Slate至窗口
  • UI(UserInterface) ——用户界面
    • 含义——菜单和其他互动元素,像Menu主菜单、Pause暂停菜单、NPC头顶的对话框等。
  • HUD(Head Up Display) ——
    • 典故——来源于飞机飞行员,指抬头就能看到仪表盘上飞机的飞行数据。
    • 含义——游戏期间(Runtime)在屏幕上覆盖的状态和信息
    • 目的——告知玩家当前游戏状态,如分数、生命值、游戏时间等。
    • 定义——HUD通常不可互动,意味着玩家不能单击HUD的元素
  • Widget ——控件
    • 含义 ——它们是一系列预先制作的函数
    • 作用 ——可用于构建界面(如Button按钮、Slider滑块、ProgressBar进度条、Vertical/Horizontal Box 水平/竖直框。
    • 大环境 ——这些Widget控件在专门的控件蓝图(UserInterface-> WidgetBlueprint )中编辑。它使用两个选项卡进行构造
      • Designer ——控件可视化布局,位置、旋转、缩放、父子等
      • Graph ——实现控件背后的功能,如细节面板中的Events事件,像Button的OnClicked、Hovered事件等。
combobox添加下拉内容_【UE4】C++基础【02】添加Slate至窗口
combobox添加下拉内容_【UE4】C++基础【02】添加Slate至窗口

【5.】:小贴士

我感觉初学者学C++就是个先不断找寻

对应英文语句和各种符号的意思

的过程,跟阅读理解差不多。

我觉得学代码应该分为这些阶段:

  • 新手
    • Happiness——知道这么写能不报错,哈哈哈哈,有一定的奖励反馈以支撑头发继续战斗下去。(What?)
    • Effect——简单知道这么写能起什么作用(How?)
  • 高手
    • Benifit——深入理解引擎为什么要这么写,有什么好处。(Why?)

在学习期间肯定有很多不会的地方,可以按以下方式查询。

  1. VS中鼠标悬浮语句出Tooltip提示框快速查看对应意思。
combobox添加下拉内容_【UE4】C++基础【02】添加Slate至窗口

2.网页端虚幻官方C++ API Reference (或像上面鼠标Hover的时候,点击SearchOnline,会自动用Bing搜索关键词,跟内容浏览器资源右键View Documentation/See Full Documentation差不多)

combobox添加下拉内容_【UE4】C++基础【02】添加Slate至窗口

3.深入了解的话,就右键PeekDefinations在当前文档内出小窗口快速浏览或 GoToDefinition到源文件查看相应代码。

combobox添加下拉内容_【UE4】C++基础【02】添加Slate至窗口
combobox添加下拉内容_【UE4】C++基础【02】添加Slate至窗口

一、 预备工作

【1.1】创建基础C++类(GameMode、PlayerController、HUD)

  1. 新建地图—— Content->Map->新建

    MenuMap

  2. 设置项目默认地图——Project Settings ->Maps & Modes 设置

    MenuMap

    为项目默认地图
  3. 新建C++ GameModeBase 为

    ShitGameMode

    1. 确保 Public—— 头文件public、源文件private
    2. Public路径后添加

      /GamePlay

      以将这个

      ShitGameMode

      放在 GamePlay文件夹下,规整一点(如果报错不能生成文件,后期VS处理)
combobox添加下拉内容_【UE4】C++基础【02】添加Slate至窗口

4. 新建 PlayerController 为

ShitController

,同样Public

5. 新建 HUD (跟UI一样放在屏幕上,但是不用手动AddToViewport)为

ShitHUD

,同样为Public。

  • GameController
  • GameMode
  • HUD

如若出现报错,请按照提示在cpp中添加文件路径前缀:UE4添加C++类失败 如何解决?

【1.2】世界设置GameMode为新创建自定义的GameMode类

  • ShitGameMode
combobox添加下拉内容_【UE4】C++基础【02】添加Slate至窗口
combobox添加下拉内容_【UE4】C++基础【02】添加Slate至窗口

二、VS代码编辑器配置GameMode

【2.1】给ProjectName.Build.cs添加Slate、SlateCore模块

当然内部原理更复杂,我等菜鸟简单了解一下具体的功能即可,后期深入再理解原理。

  • Unreal Build Tool (UBT)——负责 各个模块的编译 并处理 各模块之间的依赖关系,Build.cs和Target.cs就是服务于UBT的。Build.cs中包含了定义的模块的依赖关系、额外的库、路径等信息,这些文件被编译成dll动态链接库文件,并通过单一的exe可执行文件进行加载。
  • Unreal Header Tool (UHT)——C++代码解析工具
    • 搜集带U的,如UCLASS()、UPROPERTY() 生成反射数据并注入到 GENERATED_BODY()中。

篮子悠悠:UE4 C++基础教程 - 工程目录结构​zhuanlan.zhihu.com

combobox添加下拉内容_【UE4】C++基础【02】添加Slate至窗口

如果我们要使用Slate UI 我们只需要Uncomment取消注解就可以了。

新添加格式为字符串,名字为Slate、SlateCore,到 私有从属组块名中。

PrivateSlate语句行,

Ctrl+K,Ctrl+U(Uncomment)

(Ctrl+C(comment))

PrivateDependencyModuleNames.AddRange(new string[] {"Slate"、"SlateCore"});
           
combobox添加下拉内容_【UE4】C++基础【02】添加Slate至窗口

【2.2】使用VAssistX插件在Gamemode.h头文件中新Declare构造函数

  • VAssistX
    • 快速追踪,
      • Alt+G ——Declaration和Definition的快速跳转;
      • Alt+O ——cpp 和 h 文件快速切换
    • 快速创建,添加成员变量的Set/Get方法,如构造函数,CreateImplementation
      • Alt+C (自定义)——CreateImplementation 快速创建实现,直接在头文件函数声明(Declaration)处快捷键,然后就跳转到了源文件中,并自动写好函数实现语句(Definition)。
combobox添加下拉内容_【UE4】C++基础【02】添加Slate至窗口
combobox添加下拉内容_【UE4】C++基础【02】添加Slate至窗口

【2.3】

GENERATED_BODY()

GENERATED_UCLASS_BODY()

的区别

  • _Body()

    • 标识的类的成员默认是Private的
    • 标识的类 需要声明 无参数的构造函数 (Public:如AxxxActor)
  • _

    UCLASS_Body()

    • 可以不声明构造函数(如果要实现构造函数需要加上

      const FObjectInitializer&ObjectInitializer:Super(ObjectInitializer)

      参数 (ObjectInitializer,对象构造器/对象初始化操作)

我们之前学过Super()的作用就是调用这个函数之前会先调用父类中的函数。

默认的是

GENERATED_BODY()

,本节只是简单了解一下二者区别。
combobox添加下拉内容_【UE4】C++基础【02】添加Slate至窗口

【2.4】GameMode源文件中#include HUD和Controller的头文件

  • 我们之前说过h是领导,外面接活,就是#include一堆引擎的东西,啥框架、反射生成啦这些玩意儿。
  • cpp是员工,给领导干活,#include一堆我们自己创建的领导。

如Gamemode cpp员工要#include自身Gamemode领导,还有其他两个领导。注意路径,Gameplay或UI文件夹,否则 #include下面一堆姨妈红。

//ShitGameMode.cpp

// Fill out your copyright notice in the Description page of Project Settings.


#include "GamePlay/ShitGameMode.h"
#include "GamePlay/ShitController.h"
#include "UI/HUD/ShitHUD.h"

AShitGameMode::AShitGameMode()
{

}
           

【2.5】GameMode cpp 源文件中 补充构造函数定义,细化GameMode配置

说明:

  • ::

    作用域限定符(范围解析运算符)
    。类外实现函数定义 (如蓝图学习C++ 【8.1】中类成员函数的类内类外定义 和【8.2】中构造函数的声明与定义)
  • StaticClass() 是UE4引擎自己通过反射创建的文件下面的一个函数,运行时可以返回这个类的UClass对象。
combobox添加下拉内容_【UE4】C++基础【02】添加Slate至窗口
  • 语法:类名Class=继承类名::StaticClass();
  • 如 HUDClass=AShitHUD::StaticClass();

代码中的

=

等号其实就跟在编辑器ComboBox中选枚举一样,像完善GameMode详细参数,如HUD、Controller这些。我们在代码中直接写死,不让在编辑器中枚举选了。

combobox添加下拉内容_【UE4】C++基础【02】添加Slate至窗口
// ShitGameMode.cpp

#include "GamePlay/ShitGameMode.h"
#include "GamePlay/ShitController.h"
#include "UI/HUD/ShitHUD.h"

AShitGameMode::AShitGameMode()
{
	PlayerControllerClass = AShitController::StaticClass();
	HUDClass = AShitHUD::StaticClass();
}


           

【2.6】Build检验

编辑器中看到在VS中定义的GameMode的属性都传过来了,且不可改动

combobox添加下拉内容_【UE4】C++基础【02】添加Slate至窗口
combobox添加下拉内容_【UE4】C++基础【02】添加Slate至窗口

三、VS代码编辑器配置PlayerController

【3.1】ShitController 构造函数定义声明

  1. 来到ShitController 头文件。
  2. 跟GameMode一样头文件中public声明构造函数
  3. 再鼠标悬浮构造函数处 Alt+C通过VAssistX插件在cpp中快速定义构造函数基本语法,即CreateImplementation创建声明的实现。
// ShitController.h

#pragma once

#include "CoreMinimal.h"
#include "GameFramework/PlayerController.h"
#include "ShitController.generated.h"

/**
 * 
 */
UCLASS()
class TESTGAME_API AShitController : public APlayerController
{
    GENERATED_BODY()

public:AShitController(); //在此Alt+C
};
           
//ShitController.cpp

#include "GamePlay/ShitController.h"

AShitController::AShitController() //Alt+C 结果
{

}
           

【3.2】ShitController中详细定义函数

【1】

bShowMouseCursor=true;

显示鼠标

  • 蓝图一般是关卡蓝图中getcontroller、ShowMouse变量、打勾不打勾 或PlayerController蓝图中勾选显示鼠标。( 构造函数中写的这个就跟Controller蓝图中Class Settings勾选是一样的)
  • C++直接b布尔类型变量、ShowMouse变量、=True/False 是否启用
combobox添加下拉内容_【UE4】C++基础【02】添加Slate至窗口
combobox添加下拉内容_【UE4】C++基础【02】添加Slate至窗口

【2】设置只接受鼠标输入并将鼠标锁在窗口内

  1. 头文件中跟默认代码一样声明 BeginPlay初始函数 虚函数——

    virtual void BeginPlay() override;

  2. 一样Alt+C CreateImplementation创建函数声明。
  3. 源文件中定义锁定鼠标在窗口内
  • FInputModeUIOnly—— 用于设置仅允许UI响应用户输入的输入模式的数据结构
// Fill out your copyright notice in the Description page of Project Settings.


#include "GamePlay/ShitController.h"

AShitController::AShitController()
{
	bShowMouseCursor = true;
}

void AShitController::BeginPlay()
{
	FInputModeUIOnly InputMode;
	InputMode.SetLockMouseToViewportBehavior(EMouseLockMode::LockAlways);
	SetInputMode(InputMode);
}
           
combobox添加下拉内容_【UE4】C++基础【02】添加Slate至窗口

【3.3】Build检验

  1. VS Game Build
  2. Hot 热更新过来可以看到定义的Class都过来了

然后Standalone Game独立游戏模式 Alt+P 运行检验结果:

看到鼠标是显示出来的且卡在窗口内。
combobox添加下拉内容_【UE4】C++基础【02】添加Slate至窗口
combobox添加下拉内容_【UE4】C++基础【02】添加Slate至窗口

四、VS代码编辑器配置SlateWidget

【4.1】新建两个SlateWidget

【操作】:
combobox添加下拉内容_【UE4】C++基础【02】添加Slate至窗口
【注意事项】:
  • 需要注意的是SlateWidget并不会在ContentBrowser中出现,包括文件夹,它只会在VS中出现。(我还各种Build、Rebuild、重启测试,结果是真的没有, 大家别费那个劲儿在Content Browser中找了
  • UE4 C++基础 篇中我们讲到过UE4采用Pascal命名法,S前缀代表SlateWidget。比如我们蓝图创建了一个名为ShitWidget的SlateWidget,VS中会变成SSlateWidget.h/.cpp。
  • HUD是不带S前缀的,SlateWidget才带S前缀,注意一下。

【4.2】HUD基础代码配置

  • 跟上面GameMode和Controller一样,在HUD 头文件中同样public声明,Alt+C源文件定义构造函数。
  • ShitHUD cpp源文件中#include 引用
    • SShitMenuHUDWidget.h头文件。
    • SlateBasics.h头文件。(否则会报错)
// ShitHUD.h
#pragma once

#include "CoreMinimal.h"
#include "GameFramework/HUD.h"
#include "ShitHUD.generated.h"

/**
 * 
 */
UCLASS()
class TESTGAME_API AShitHUD : public AHUD
{
	GENERATED_BODY()

public:
		AShitHUD(); //声明构造函数
}
           
//ShitHUD.cpp
#include "UI/HUD/ShitHUD.h"
#include "UI/Widget/SShitMenuHUDWidget.h"
#include "SlateBasics.h"

AShitHUD::AShitHUD()
{ };
           

【4.3】绑定Widget至HUD并添加到GameViewport游戏窗口中。

参考官方文档——在游戏中使用Slate

【1.】:

头文件声明指针

// ShitHUD.h
#pragma once

#include "CoreMinimal.h"
#include "GameFramework/HUD.h"
#include "ShitHUD.generated.h"

/**
 * 
 */
UCLASS()
class TESTGAME_API AShitHUD : public AHUD
{
	GENERATED_BODY()

public:
		AShitHUD();

		TSharedPtr<class SShitMenuHUDWidget>MenuHUDWidget;
	
};
           

上面的

TSharedPtr<class SShitMenuHUDWidget>MenuHUDWidget;

跟下面的蓝图差不多。

  • TSharedPtr 声明共享指针。
  • 指针类为

    ShitMenuHUDWidget

    (用UMG创建的自定义UI,继承自UserWidget)
  • 指针名为

    MenuHUDWidget

combobox添加下拉内容_【UE4】C++基础【02】添加Slate至窗口
  • TSharedPtr——等同于在蓝图细节面板中的变量栏创建一个变量(指针变量)
  • ToSharedRef()——将指针指的Class类调用过来。
【2.】:

源文件定义指针

// ShitHUD.cpp


#include "UI/HUD/ShitHUD.h"
#include "UI/Widget/SShitMenuHUDWidget.h"
#include "SlateBasics.h"

AShitHUD::AShitHUD()
{
	if (GEngine && GEngine->GameViewport)
  {
		SAssignNew(MenuHUDWidget, SShitMenuHUDWidget);

		GEngine->GameViewport->AddViewportWidgetContent(
SNew(SWeakWidget).PossiblyNullContent(MenuHUDWidget.ToSharedRef())
);
   }
}
           
【解释说明】:
  • 【1】if语句
    • && 逻辑与运算符,两个表达式必须都为true,整个表达式才为true
    • 判断GEngine和GameViewport是否存在,存在则执行括号中的语句
  • 【2】创建SlateWidget语句
    • SAssignNew为SlateWidget的一种创建方式,要 搭配头文件中声明的指针 一起才管用。
TSharedPtr<class SShitMenuHUDWidget>MenuHUDWidget;
SAssignNew(MenuHUDWidget, SShitMenuHUDWidget);
           

两种创建方式的区别是:

  • SNew(xxx)
  • SAssign(指针,SlateWidget类名)
combobox添加下拉内容_【UE4】C++基础【02】添加Slate至窗口

SNew和SAssignNew

  • 3】添加到游戏窗口语句
GEngine->GameViewport->AddViewportWidgetContent(
SNew(SWeakWidget).PossiblyNullContent(MenuHUDWidget.ToSharedRef())
);
           
  1. GEngine->GameViewport->AddViewportWidgetContent();

    添加到游戏窗口(默认代码 中我们还学过GEngine也是可以在屏幕上Print String打印信息)
combobox添加下拉内容_【UE4】C++基础【02】添加Slate至窗口
  • 为了在游戏中显示一个Slate控件,就必须把这个控件添加到游戏视口(Viewport)中。
    • 重叠的控件会按照Z-Order索引进行排序,大的数置顶在上面,小的数在下面,跟PS的图层一样。
  • 游戏视口GameViewport是GameViewportClient的一个实例,可通过使用到游戏当前 U Engine实例的“ G Engine”(Game Engine?)指针访问——

    GEngine->GameViewport

  • GameViewport的AddViewportWidgetContent函数可以将控件添加到视口中。
2.

SNew(SWeakWidget).PossiblyNullContent(MenuHUDWidget.ToSharedRef());

将上面通过SAssignNew创建的SlateWidget添加到视口中
【实现流程】:
  1. PossiblyNullContent(MenuHUDWidget.ToSharedRef()——如果这个指针指向的widget类存在,那就
  2. SNew(SWeakWidget)——把它传到这个新创建的SWeakWidget SlateWidget中
  3. GEngine->GameViewport->AddViewportWidgetContent(....),将SWeakWidget添加到屏幕上。
【SWeakWidget是什么】:
  • SWeakWidget 是什么鬼?——实现一个小部件,该小部件持有指向一个子小部件的弱指针(Weak Pointer)。它封装一段内容而不拥有它。 可以理解为一种绿绿的暧昧的关系。
    • Tooltip=A,女一号
    • Hovered Widget =B,男一号。
    • Floating Window=C,男二号。
B代码里有A,但是A通过C显示,然而C代码里面没有A。

(哈哈,就好比男一号心里有女一号,然而女一号要通过跟男二号潜规则才能上位亮相,但是男二号心里并没有女一号。那是因为男二号还有很多可潜规则的对象。)

combobox添加下拉内容_【UE4】C++基础【02】添加Slate至窗口
【3.】SlateWidget分辨
  • 项目编辑器中 ——
    • 我们在项目编辑器中创建的是 两个特定SlateWidget类 ,这里SlateWidgets就代表添加到屏幕上面的那些UserWidget(蓝图)。
combobox添加下拉内容_【UE4】C++基础【02】添加Slate至窗口
HUD中引入SlateWidget,以添加到GameViewport。
  • VS中 ——
    • 而我们在HUD中通过

      SNew()或SAssignNew()

      创建SlateWidgets,指定我们创建的SlateWidgets以填充至屏幕中。
    • 两个特定SlateWidgets类 中我们同样也可以通过

      SNew()或SAssignNew()

      来创建

      SButton

      组件,以在Widgets中添加Button按钮。
combobox添加下拉内容_【UE4】C++基础【02】添加Slate至窗口
SlateWidget中新创建Button、Box等像UMG中的那些Widget控件。
combobox添加下拉内容_【UE4】C++基础【02】添加Slate至窗口

【4.4】: 解决小Bug

虚幻的Bug真神奇:

  1. 有这种白色棱形问号的,不用思考,肯定是中文的问题,系统语言更改真的有时候能够解决很多问题的,比如微信定位地址,电脑系统英文会默认用Google打开,中文会默认用腾讯地图打开。 系统语言改为英文后,就到了第二个编号了,明显少了一个bug。
  2. 第二个它提示不能够删除dll动态链接库,直接关闭VS,然后在ContentBrowser中随便打开一个Class,然后再Build,就好了,编译成功!虚幻就是这么地神奇!
combobox添加下拉内容_【UE4】C++基础【02】添加Slate至窗口

【4.5】SlateWidget中引入SButton组件

ShitMenuHUDWidget 源文件中新引入

SButton.h"

,添加SButton组件。

  • [ ]中括号是重载运算符
  • ChildSlot就是槽,可以放子控件。
// Fill out your copyright notice in the Description page of Project Settings.


#include "UI/Widget/SShitMenuHUDWidget.h"
#include "SButton.h"
#include "SlateOptMacros.h"

BEGIN_SLATE_FUNCTION_BUILD_OPTIMIZATION
void SShitMenuHUDWidget::Construct(const FArguments& InArgs)
{
	
	ChildSlot
		[
			SNew(SButton)// 创建一个Button Slate
	];
	
}
END_SLATE_FUNCTION_BUILD_OPTIMIZATION
           

注意一下这个路径的问题,开头我是直接 在HUD cpp源文件中

#include"SButton.h"

,后来一直报错,结果检查到还是路径的问题呢。个人觉得Build.cs中引入模块名其实就跟文件夹定位的意思差不多,Build.cs定一次,一劳永逸,省得在自定义类的源文件中再多次#include这个文件夹了。

  • 然后VS中右键SButton.h找到它的定义,然后再文件资源管理器中打开,查看路径。

所以最终

#include"Widgets/Input/SButton.h"

就解决问题了,因为路径对了嘛,UE可以找到SButton啦。

combobox添加下拉内容_【UE4】C++基础【02】添加Slate至窗口

最终效果:可以看到Button充满了整个屏幕。不过我们还没有定义事件,我们下节再定义。

combobox添加下拉内容_【UE4】C++基础【02】添加Slate至窗口

待续。添加样式啥的。