这里演示在UE4中UMG使用和C++代码操作Widget对象的示例。实现的功能有:
- 如何在widget蓝图中制作UI模版;
- 如何用C++动态加载资源(UTexture2D);
- 当触发widget组件的事件时如何调用C++函数;
例子的完整工程(包括所有代码)在文章末尾下载。
这个例子的部分代码参考自UE4官方项目的源码,有兴趣深入研究可以去看那些UI比较丰富的官方项目。
注:当前使用的是最新版本v4.10。下面的代码涉及的API可能在后续版本中变动,注意下。
具体步骤:
1,先新建一个空的C++工程
2,然后我们新建一个自己的PlayerController:工程编辑器中的点击File -》 new C++ class -》 选择Player Controller -》 下一步 -》 起一个类名:MyPlayerController
自定义PlayerController是为了添加角色控制的逻辑,每个游戏都有特定的角色(可以是3d人身角色,也可以是一个2d面板),所以一个正常的游戏都会需要添加自己的PlayerController,当前例子没有角色,这里添加PlayerController是为了将后面的UMG widget实例加入到PlayerController中。
我们先在PlayerController构造函数中添加一些配置代码,来实现鼠标显示,默认是不显示:
AMyPlayerController::AMyPlayerController() { //显示鼠标 bShowMouseCursor = true; DefaultMouseCursor = EMouseCursor::Crosshairs; //启用鼠标事件 bEnableClickEvents = true; bEnableMouseOverEvents = true; }
3,再GameMode类的构造函数中,设置默认的PlayerController为刚刚我们新建的PlayerController:
UMGDemoGameMode.h
// Fill out your copyright notice in the Description page of Project Settings. #include "UMGDemo.h" #include "UMGDemoGameMode.h" #include "MyPlayerController.h" AUMGDemoGameMode::AUMGDemoGameMode() { //使用自定义PlayerController类 PlayerControllerClass = AMyPlayerController::StaticClass(); }
4,再新建一个自定义的UBlueprintFunctionLibrary,这个类是一个提供各种通用的静态函数的管理类,我们将在这个类中实现一个获取自定义PlayerController的静态函数。工程编辑器中的点击File -》 new C++ class -》 勾选Show All Classes -》 找到BlueprintFunctionLibrary并选中 -》 下一步 -》 类名我们起为:MyBlueprintFunctionLibrary
添加完毕后会自动编译,这里会提示需要在编辑器中重新Compile编译一次,否则编辑器的内容视图中看不到这个文件,这个窗口我们先关掉,后面会统一编译
5,在“工程名.h”头文件加入我们刚刚新建的BlueprintFunctionLibrary:
// Fill out your copyright notice in the Description page of Project Settings. #pragma once #include "Engine.h" #include "MyBlueprintFunctionLibrary.h"
并实现一个静态的函数用于获取自定义PlayerController:
MyBlueprintFunctionLibrary.h
public: /** 获取所有PlayerController列表,然后再找到本地客户端的第一个PlayerController并返回 */ UFUNCTION(BlueprintCallable, Category = "TD_Test Gameplay") static APlayerController* GetLocalPlayerController(UObject* WorldContextObject);
MyBlueprintFunctionLibrary.cpp
APlayerController* UMyBlueprintFunctionLibrary::GetLocalPlayerController(UObject* WorldContextObject) { if (UWorld* World = GEngine->GetWorldFromContextObject(WorldContextObject)) { for (FConstPlayerControllerIterator Iterator = World->GetPlayerControllerIterator(); Iterator; ++Iterator) { APlayerController* PlayerController = *Iterator; if (PlayerController->IsLocalController()) { // For this project, we will only ever have one local player. return PlayerController; } } } return nullptr; }
6,新建一个自定义UserWidget类,添加的目的是:将widget组件需要调用的C++逻辑都放到这个类中,且只能放到自定义UserWidger类中,如果你想在UMG蓝图中让widget组件调用UserWidget类之外的函数是行不通的。工程编辑器中的点击File -》 new C++ class -》 勾选Show All Classes -》 找到UserWidget并选中 -》 下一步 -》 类名我们起为:MyUserWidget
添加完以后还无法编译,需求在“工程名.Build.cs”中加入配置,加入红色部分即可:
PublicDependencyModuleNames.AddRange(new string[] { "Core", "CoreUObject", "Engine", "InputCore", "UMG", "Slate", "SlateCore" });
7,添加Widget蓝图,并将此蓝图的父类指定为刚刚新建的MyUserWidget class。右击内容视图-》用户界面-》Widget蓝图,名字起为:MyWidgetBlueprint
然后双击打开蓝图,点击Graph(图形)界面 -》 点击 Class settings -》 找到Parent Class -》 选择我们刚刚新建的自定义UserWidget类。(如果找不到自定义UserWidget,在编辑器中重新编译下代码,实在不行重启下编辑器)
8,再回到Designer界面,从左侧的组件列表中,我们拖拽几个组件进来,分别是:Button,Overlay,Image。层级关系是:Button 《 Overlay 《 Image
后面会实现这样的一个功能:给定两张图片(Texture2d),每点击一次,button的图片变一次。这个功能其实也可以用存蓝图脚本实现,这里为了演示蓝图调用C++函数,我们把替换图片的逻辑放在C++代码中。官方文档说,对于调用非常频繁的逻辑,若要提高性能,建议用C++实现而不要在蓝图中实现。
先修改widget组件的一些参数:
设置设置button的大小,因为我们使用的图片大小是205X115,所以button的大小也这样设置
属性Style中Normal、Hovered、Pressed中的Draw As都修改为None,因为按钮的图片我们准备设置在Image组件当中。之所以不直接在button中设置背景图片,是因为仅仅依靠一个button组件,无法只用一张图片就实现按钮下压的效果,这里我们想只用一张图片来实现按钮下压的效果,所以除了button,还用了Overlay和Image两种组件
然后再设置下Image组建的size,设置为图片一样大小:205x115。
控制button按下后图片浮动的上下左右距离,在Style下的Pressed Padding中设置,如果想要浮动的效果明显一点,根据需要设置大一下:
到此我们把UMG widget蓝图模版绘制完成,接下来我们用C++代码操作这些widget组件。
9,首先我们在GameMode类中重载父类的BeginPlay()函数
/** Called when the game starts. */ virtual void BeginPlay() override;
同时在GameMode内定义了几个函数:
//创建widget对象并添加到Viewport
void CreateWidgetInstance();
//获取需要操作数据的widget对象
void FindImageComponents();
//动态加载icon所需Texture2D
void LoadAssetsDynamic();
其中CreateWidgetInstance()函数用来创建Widget实例对象(以之前的MyUserWidgetBlueprint为模版),并添加到游戏的Viewport中;
FindImageComponents()用来获取创建的widget实例中的Image组件的引用,因为我们后面要用代码操作这个Image组件,所以先把这个组件的指针存起来,不用每次操作时再查找;
LoadAssetsDynamic()用来加载Texture资源。我们对Image组件更换图片时,实际是对Texture的更换,所以,进入游戏时我们就先加载到内存中,等后面点击button的时候,直接修改Image组件中对这些Texture内存的引用,来实现图片切换。
具体代码如下:
UMGDemoGameMode.h
// Fill out your copyright notice in the Description page of Project Settings. #pragma once #include "GameFramework/GameMode.h" #include "Blueprint/UserWidget.h" #include "Runtime/UMG/Public/Components/Image.h" #include "UMGDemoGameMode.generated.h" /** * */ UCLASS() class UMGDEMO_API AUMGDemoGameMode : public AGameMode { GENERATED_BODY() public: AUMGDemoGameMode(); /** Called when the game starts. */ virtual void BeginPlay() override; private: UImage* imageHero; UTexture2D* texHero1; UTexture2D* texHero2; UTexture2D* defaultTexHero; protected: /** The widget class we will use as our game over screen when the player wins. */ UPROPERTY(EditAnywhere, BlueprintReadOnly, Category = "Game") TSubclassOf<UUserWidget> MyWidgetClass; /** The widget instance that we are using as our menu. */ UPROPERTY() UUserWidget* MyWidgetInstance; //创建widget对象并添加到Viewport void CreateWidgetInstance(); //获取需要操作数据的widget对象 void FindImageComponents(); //动态加载icon所需Texture2D void LoadAssetsDynamic(); public: //修改icon图片:切换英雄时调用 void ChangeHeroIcon(); };
UMGDemoGameMode.cpp
下面代码中的实现思路有点不科学,因为把很多UI相关的操作放在GameMode内部。建议参考新文章中的方法:http://aigo.iteye.com/blog/2296218
// Fill out your copyright notice in the Description page of Project Settings. #include "UMGDemo.h" #include "UMGDemoGameMode.h" #include "MyPlayerController.h" AUMGDemoGameMode::AUMGDemoGameMode() { //使用自定义PlayerController类 PlayerControllerClass = AMyPlayerController::StaticClass(); imageHero = NULL; texHero1 = NULL; texHero2 = NULL; defaultTexHero = NULL; } void AUMGDemoGameMode::BeginPlay() { Super::BeginPlay(); UMyBlueprintFunctionLibrary::SetGameModeInstance(this); CreateWidgetInstance(); FindImageComponents(); LoadAssetsDynamic(); ChangeHeroIcon(); } //创建widget对象并添加到Viewport void AUMGDemoGameMode::CreateWidgetInstance() { if (MyWidgetInstance) { MyWidgetInstance->RemoveFromViewport(); MyWidgetInstance = nullptr; } if (MyWidgetClass) { if (AMyPlayerController* PC = Cast<AMyPlayerController>(UMyBlueprintFunctionLibrary::GetLocalPlayerController(this))) { MyWidgetInstance = CreateWidget<UUserWidget>(PC, MyWidgetClass); if (MyWidgetInstance) { MyWidgetInstance->AddToViewport(); } } } } //获取需要操作数据的widget对象 void AUMGDemoGameMode::FindImageComponents() { if (UCanvasPanel* CanvasPanelWidget = Cast<UCanvasPanel>(MyWidgetInstance->GetRootWidget())) { //获取英雄头像的UImage指针 if (UButton* btn = Cast<UButton>(CanvasPanelWidget->GetChildAt(0))) { if (UOverlay* overlay = Cast<UOverlay>(btn->GetChildAt(0))) { if (UImage* image = Cast<UImage>(overlay->GetChildAt(0))) { imageHero = image; } } } } } //动态加载icon所需Texture2D void AUMGDemoGameMode::LoadAssetsDynamic() { //加载英雄头像的Texture if (texHero1) { //如果已经加载过,则先销毁掉 texHero1->ConditionalBeginDestroy(); texHero1 = NULL; GetWorld()->ForceGarbageCollection(true); } texHero1 = Cast<UTexture2D>(StaticLoadObject(UTexture2D::StaticClass(), NULL, TEXT("Texture2D'/Game/Textures/hero1.hero1'"))); if (texHero2) { texHero2->ConditionalBeginDestroy(); texHero2 = NULL; GetWorld()->ForceGarbageCollection(true); } texHero2 = Cast<UTexture2D>(StaticLoadObject(UTexture2D::StaticClass(), NULL, TEXT("Texture2D'/Game/Textures/hero2.hero2'"))); defaultTexHero = texHero2; } void AUMGDemoGameMode::ChangeHeroIcon() { if (!defaultTexHero || !texHero1 || !texHero1 || !imageHero) { return; } defaultTexHero = defaultTexHero == texHero1 ? texHero2 : texHero1; imageHero->SetBrushFromTexture(defaultTexHero); }
相关推荐
在UE4(Unreal Engine 4)中,UI系统基于UMG(Unreal Motion Graphics),它提供了一种可视化的方式去创建用户界面,并且可以与C++代码深度集成。本示例"UE4 UI简单例子 C++"展示了如何利用C++编程语言在UE4中创建一...
这款插件的特点在于它完全基于UMG(User Interface Meta Language)实现,意味着无需借助WebBrowser或者WebUI嵌套,而是通过纯C++编程语言以及蓝图系统来构建。这使得图表的集成更为流畅,性能更佳,同时也便于开发者...
在UE4中,CanvasUI基于UMG(Unreal Motion Graphics),这是一个强大的2D UI设计工具,允许通过直观的可视化编辑器创建复杂的用户界面。Canvas是UMG中的一个基本元素,它是一个二维画布,可以添加各种UI组件,如文本...
通过C++的高效性和对UMG及蓝图系统的全面支持,它提升了UE4项目的色彩管理体验,使得游戏的视觉效果和用户交互得以进一步优化。对于那些致力于创造丰富多彩游戏世界的UE4开发者来说,这是一个不可多得的工具。
UE5 蓝图 UMG实现日历系统.
UE4 UMG 跑马灯字幕效果 大概的思路就是将Text 放置到ScrollBox 中 通过tick 不断移动scroll 的Offset 达到Text文本自动滚动的效果 唯一有点难度的就是判断scroll 是否滚动到末尾 然后从头播放 蓝图就是
UE5 UMG滚动框可从前从后添加新UI思路
本项目“UE4-InventorySystem”提供了一个基于C++实现的基础库存系统,它充分利用了UE4.6版本中的用户界面(UI)框架——UMG(Unreal Motion Graphics)。下面将详细介绍这个库存系统的实现原理和关键知识点。 1. *...
《UE4插件VictoryPlugin-master深度解析:通过路径加载图片技术详解》 在Unreal Engine 4(简称UE4)的开发过程中,插件扮演着至关重要的角色,它们能够扩展游戏引擎的功能,提高开发效率。VictoryPlugin是UE4的一...
在UE4(Unreal Engine 4)中,文件拖拽窗口插件是一种增强用户交互功能的工具,允许用户通过简单的拖放操作将外部文件导入到游戏引擎中。这种功能对于内容创作者、开发者以及测试者来说非常实用,因为它提高了工作...
UE4后处理材质资源,描边高亮效果。UE4后处理材质资源,描边高亮效果。
UE4的UMG(Unreal Motion Graphics)系统允许创建自定义的2D和3D界面组件。 6. **音效与音乐**:合适的音效和背景音乐可以极大地提升游戏氛围。UE4支持导入音频文件,并通过事件驱动的方式在特定时刻播放。 7. **...
UE4局域网多人联机,其中包含背包系统,动画系统,角色生成系统,计时器,敌人生成系统,UI系统,救人系统(模仿吃鸡救人),子弹后坐力系统,十字准心位置,掉血系统,伤害系统,UMG界面布局系统,一套完整的局域网...
而RenderTarget是UE4中的一种特殊纹理,可以捕获场景的渲染结果,也可以作为其他渲染操作的目标。 该插件的核心功能是将UMG小部件的渲染输出导向一个特定的RenderTarget。这通常涉及到以下几个关键步骤: 1. 创建和...
《KantanCharts:UE4插件轻松实现UMG Slate图表绘制》 KantanCharts是一款针对Unreal Engine 4(简称UE4)开发的...然而,为了充分利用其功能,开发者需要对UE4的UMG系统有一定了解,并且熟悉C++或蓝图的基本操作。
《UE-GJAPI-UMG:游戏开发中的GameJolt API交互工具》 在Unreal Engine的游戏开发过程中...在实际应用中,开发者需要结合UE4、UMG、C++以及GameJolt API的知识,才能充分发挥其潜力,打造出更加生动和互动的游戏世界。
Learning C++ by Building Games with Unreal Engine 4: A beginner’s guide to learning 3D game development with C++ and UE4, 2nd Edition by Sharan Volin--July 1, 2019 English | 2018 | ISBN: 1788476249 |...
UE4使用蓝prints和C++来创建UI元素,如按钮、文本框等,并通过UMG(User Made Graphics)系统进行布局管理。UMG允许开发者以可视化的方式创建和组织UI组件,但其灵活性和扩展性在面对大型项目时可能会显得不足。这就...
UE4赛车游戏源码,使用虚幻4引擎C++、蓝图、UMG等开发...
本文将详细介绍如何在UE4中实现多关卡之间的流畅切换,以及如何与UMG(Unreal Motion Graphics)结合以创建丰富的用户界面。 首先,我们要了解在UE4中,流关卡(Streaming Level)的概念。流关卡允许游戏在运行时...