斯坦福UE4 + C++课程学习记录 17:材质-材质函数

本文介绍了如何在UE4中创建和使用材质函数,通过封装功能简化材质设计。首先,通过创建名为MF_HitFlashDemo的材质函数,实现了受击闪烁效果的重用,并详细说明了如何公开材质函数以供其他材质调用。接着,讨论了如何为材质函数添加输入参数以适应不同场景需求。此外,还展示了如何创建UI材质M_HealthBar,用于制作血量条显示,利用材质节点控制血条颜色变化,最后在PlayerHealth_Widget蓝图中更新逻辑以设置材质的ProgressAlpha参数,实现动态血量显示效果。

摘要生成于 C知道 ,由 DeepSeek-R1 满血版支持, 前往体验 >

目录

1. 创建材质函数

2. UI材质


        在第15节的内容中,我们使用了DebugScalarValue函数将数字显示在材质上,在这一节我们将尝试编写和使用材质函数(Material Function)。

1. 创建材质函数

        首先,在Material文件夹下右键 -> 材质和纹理 -> 材质函数,命名为MF_HitFlashDemo,我们将把受击闪烁的功能封装成函数以便重用。打开MF_HitFlashDemo,并将M_HitFlashDemo(第16节实现的材质)控制“自发光颜色”的部分蓝图复制粘贴到其中,连上“OutputResult”左边的引脚。

图17-1 材质函数设置

         然后,勾选材质函数的“公开到库”选项,这样才能在其他材质中使用。保存后回到M_HitFlashDemo中,右键添加MF_HitFlashDemo节点(注意项目自带了一个MF_HitFlash函数,名字很像不要混淆)。接下来就可以把节点连到“自发光颜色”,并删除之前的一大堆节点。

<think>我们正在处理用户的问题:如何在UE4中使用C++为UI控件启用并处理键盘和鼠标事件。根据用户的问题,我们需要参考之前提供的引用内容,但注意这些引用并不是直接关于键盘鼠标事件处理的,所以我们需要结合UE4的UMG和C++编程的一般知识来回答。步骤:1.创建一个自定义的UUserWidget子类,用于代表我们的UI控件。2.在这个子类中,我们可以重写一些虚函数来处理输入事件,例如:`NativeOnMouseButtonDown`,`NativeOnMouseButtonUp`,`NativeOnMouseMove`,`NativeOnKeyDown`等。3.为了能够接收输入事件,我们需要设置UI控件可以接收输入(设置bIsFocusable和获取焦点等)。4.在控件被添加到视口后,我们需要确保它能够获取焦点。参考引用:引用[2]提到了创建控件蓝图和UMG的操作,但我们这里要用C++实现。引用[3]提到了在控件蓝图中处理鼠标事件(OnMouseButtonDown),但用户要求用C++。因此,我们将重点放在C++的实现上。具体步骤:第一步:创建自定义控件类在C++中,我们创建一个继承自UUserWidget(或更具体的控件,如UButton)的子类。但为了通用性,我们使用UUserWidget。第二步:重写输入事件处理函数在头文件中声明重写的函数。例如:```cppprotected:virtualFReplyNativeOnMouseButtonDown(constFGeometry&InGeometry,constFPointerEvent&InMouseEvent)override;virtualFReplyNativeOnMouseButtonUp(constFGeometry&InGeometry,constFPointerEvent&InMouseEvent)override;virtualFReplyNativeOnMouseMove(constFGeometry&InGeometry,constFPointerEvent&InMouseEvent)override;virtualFReplyNativeOnKeyDown(constFGeometry&InGeometry,constFKeyEvent&InKeyEvent)override;//根据需要重写其他事件```第三步:在实现文件中实现这些函数例如,处理鼠标按下事件:```cppFReplyUMyUserWidget::NativeOnMouseButtonDown(constFGeometry&InGeometry,constFPointerEvent&InMouseEvent){if(InMouseEvent.GetEffectingButton()==EKeys::LeftMouseButton){//处理左键按下//返回FReply::Handled()表示事件已处理returnFReply::Handled();}//其他情况可以继续传递returnFReply::Unhandled();}```第四步:设置控件可聚焦默认情况下,UI控件可能无法接收键盘事件,因此我们需要设置控件为可聚焦。可以在构造函数中设置:```cppUMyUserWidget::UMyUserWidget(constFObjectInitializer&ObjectInitializer):Super(ObjectInitializer){bIsFocusable=true;//设置为可聚焦}```第五步:在适当的时候让控件获取焦点例如,当控件被添加到视口时,我们可以调用`SetFocus()`。我们可以重写`NativeOnInitialized`或`NativeConstruct`函数:```cppvoidUMyUserWidget::NativeConstruct(){Super::NativeConstruct();//尝试获取焦点SetFocus();}```第六步:在蓝图中使用这个C++控件类我们可以创建一个蓝图控件,其父类为我们创建C++类。然后设计UI。注意:如果用户希望直接在C++创建和添加控件,也可以,但通常我们会结合蓝图。另外,引用[3]中提到的事件调度器方法是在蓝图中处理事件的一种方式,但用户要求C++,所以我们不使用事件调度器,而是直接重写C++函数。补充:如果控件包含一些子控件,我们可能需要设置子控件也处理事件,或者通过事件冒泡来处理。但这里我们主要关注控件自身的处理。现在,我们可以按照这个步骤编写代码示例。注意:由于用户的问题集中在C++处理,我们将提供C++代码片段。示例代码:MyUserWidget.h```cpp#pragmaonce#include"CoreMinimal.h"#include"Blueprint/UserWidget.h"#include"MyUserWidget.generated.h"UCLASS()classMYPROJECT_APIUMyUserWidget:publicUUserWidget{GENERATED_BODY()public:UMyUserWidget(constFObjectInitializer&ObjectInitializer);protected:virtualvoidNativeConstruct()override;virtualFReplyNativeOnMouseButtonDown(constFGeometry&InGeometry,constFPointerEvent&InMouseEvent)override;virtualFReplyNativeOnMouseButtonUp(constFGeometry&InGeometry,constFPointerEvent&InMouseEvent)override;virtualFReplyNativeOnMouseMove(constFGeometry&InGeometry,constFPointerEvent&InMouseEvent)override;virtualFReplyNativeOnKeyDown(constFGeometry&InGeometry,constFKeyEvent&InKeyEvent)override;};```MyUserWidget.cpp```cpp#include"MyUserWidget.h"UMyUserWidget::UMyUserWidget(constFObjectInitializer&ObjectInitializer):Super(ObjectInitializer){bIsFocusable=true;}voidUMyUserWidget::NativeConstruct(){Super::NativeConstruct();SetFocus();}FReplyUMyUserWidget::NativeOnMouseButtonDown(constFGeometry&InGeometry,constFPointerEvent&InMouseEvent){if(InMouseEvent.GetEffectingButton()==EKeys::LeftMouseButton){//在这里处理左键按下事件,例如打印日志UE_LOG(LogTemp,Log,TEXT("LeftMouseButtonDownonMyUserWidget"));returnFReply::Handled();}returnFReply::Unhandled();}//其他事件函数的实现类似...//实现其他函数,例如:FReplyUMyUserWidget::NativeOnKeyDown(constFGeometry&InGeometry,constFKeyEvent&InKeyEvent){if(InKeyEvent.GetKey()==EKeys::A){UE_LOG(LogTemp,Log,TEXT("AkeypressedonMyUserWidget"));returnFReply::Handled();}returnFReply::Unhandled();}//请根据实际需要实现MouseButtonUp,MouseMove等```注意事项:1.确保在项目设置中启用了鼠标输入和键盘输入。2.如果控件被其他控件覆盖,可能无法接收到事件。确保控件在顶层或者设置了正确的层级。3.如果控件没有获取到焦点,键盘事件可能不会被触发。所以我们在NativeConstruct中调用了SetFocus()。但注意,如果有多个可聚焦控件,可能需要通过点击等方式设置焦点。以上是基本的设置。根据实际需求,可能需要更复杂的处理,比如事件冒泡、设置输入模式等。最后,用户可能需要将控件添加到视口。这通常在玩家控制器或HUD中完成。例如,在玩家控制器中:```cppUMyUserWidget*MyWidget=CreateWidget<UMyUserWidget>(this,UMyUserWidget::StaticClass());MyWidget->AddToViewport();```这样,当控件被添加到视口后,它将尝试获取焦点并处理输入事件。希望这能帮助用户解决问题。生成相关问题:1.如何处理UI控件之间的焦点切换?2.如何阻止游戏输入事件传递到UI控件?3.如何处理游戏手柄输入事件在UI控件上的响应?4.如何实现UI控件的拖拽功能(如引用[3])?5.如何在C++中动态创建子控件并处理它们的事件?</think>在虚幻引擎4UE4)中使用C++处理UI控件的键盘和鼠标事件,需通过以下步骤实现: --- ### 步骤1:创建自定义UUserWidget子类 在C++创建继承自`UUserWidget`的自定义控件类,并重写输入事件处理函数: ```cpp // MyWidget.h #pragma once #include "CoreMinimal.h" #include "Blueprint/UserWidget.h" #include "MyWidget.generated.h" UCLASS() class MYPROJECT_API UMyWidget : public UUserWidget { GENERATED_BODY() protected: // 重写鼠标事件 virtual FReply NativeOnMouseButtonDown(const FGeometry& InGeometry, const FPointerEvent& InMouseEvent) override; virtual FReply NativeOnMouseButtonUp(const FGeometry& InGeometry, const FPointerEvent& InMouseEvent) override; // 重写键盘事件 virtual FReply NativeOnKeyDown(const FGeometry& InGeometry, const FKeyEvent& InKeyEvent) override; }; ``` ```cpp // MyWidget.cpp #include "MyWidget.h" FReply UMyWidget::NativeOnMouseButtonDown(const FGeometry& InGeometry, const FPointerEvent& InMouseEvent) { if (InMouseEvent.GetEffectingButton() == EKeys::LeftMouseButton) { // 处理左键点击逻辑 UE_LOG(LogTemp, Warning, TEXT("Left Mouse Button Down")); return FReply::Handled(); // 阻止事件继续传递 } return FReply::Unhandled(); } FReply UMyWidget::NativeOnKeyDown(const FGeometry& InGeometry, const FKeyEvent& InKeyEvent) { if (InKeyEvent.GetKey() == EKeys::SpaceBar) { // 处理空格键按下 UE_LOG(LogTemp, Warning, TEXT("Space Key Pressed")); return FReply::Handled(); } return FReply::Unhandled(); } ``` --- ### 步骤2:启用控件输入 在控件初始化时启用输入并设置可聚焦: ```cpp // 在MyWidget.h中添加 protected: virtual void NativeConstruct() override; // 在MyWidget.cpp中实现 void UMyWidget::NativeConstruct() { Super::NativeConstruct(); // 启用输入并获取焦点 SetupInput(); SetFocus(); } void UMyWidget::SetupInput() { if (UWidgetBlueprintGeneratedClass* WidgetClass = Cast<UWidgetBlueprintGeneratedClass>(GetClass())) { WidgetClass->bAllowInput = true; // 允许输入 } } ``` --- ### 步骤3:关联蓝图控件 1. **创建控件蓝图** 在内容浏览器中创建基于`UMyWidget`的控件蓝图(如`BP_MyWidget`)[^2]。 2. **添加到视口** 在玩家控制器或HUD中实例化并添加控件: ```cpp // 在PlayerController中 UMyWidget* MyWidget = CreateWidget<UMyWidget>(this, UMyWidget::StaticClass()); MyWidget->AddToViewport(); ``` --- ### 步骤4:处理事件冒泡(可选) 若需子控件事件传递给父控件: ```cpp // 在子控件事件处理中返回FReply::Unhandled() FReply UChildWidget::NativeOnMouseButtonDown(...) { // 子控件处理逻辑 return FReply::Unhandled(); // 允许事件冒泡 } ``` --- ### 关键注意事项 1. **输入模式设置** 在玩家控制器中启用UI输入: ```cpp APlayerController* PC = GetWorld()->GetFirstPlayerController(); PC->SetInputMode(FInputModeUIOnly()); // 仅UI接收输入 PC->bShowMouseCursor = true; // 显示鼠标 ``` 2. **焦点控制** 使用`SetFocus()`确保控件获取焦点,否则键盘事件无效[^4]。 3. **事件调度器(跨蓝图通信)** 若需通知其他系统,可在C++中声明事件调度器: ```cpp // MyWidget.h DECLARE_DYNAMIC_MULTICAST_DELEGATE(FOnWidgetClicked); UPROPERTY(BlueprintAssignable) FOnWidgetClicked OnClicked; // 触发事件 OnClicked.Broadcast(); ``` 在蓝图中绑定此事件[^3]。 --- ### 常见问题解决 - **事件未触发**:检查`bAllowInput`是否启用,控件是否被遮挡,或输入模式是否正确。 - **焦点丢失**:调用`SetFocus()`重新获取焦点。 - **鼠标穿透**:在`NativeOnMouseButtonDown`中返回`FReply::Handled().CaptureMouse(AsShared())`捕获鼠标。 通过上述步骤,可实现C++层级的UI控件键盘/鼠标事件处理,同时结合蓝图进行灵活扩展[^1][^2][^4]。 --- ### 相关问题 1. 如何防止UI控件事件被游戏场景输入覆盖? 2. 如何在C++中实现UI控件的拖拽功能(如引用[3])? 3. 如何处理多层级UI控件的焦点切换逻辑? 4. 如何通过C++动态修改UMG控件的样式属性? 5. 如何优化UI控件的输入事件性能? [^1]: 虚幻引擎官方UMG编程指南 [^2]: 斯坦福UE4课程中的UMG实践案例 [^3]: UI拖拽生成物体的实现原理 [^4]: UE4 C++属性与输入处理机制
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包

打赏作者

Surkea

你的鼓励将是我创作的最大动力

¥1 ¥2 ¥4 ¥6 ¥10 ¥20
扫码支付:¥1
获取中
扫码支付

您的余额不足,请更换扫码支付或充值

打赏作者

实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值