Unreal Engine开发:Unreal Engine基础入门_(13).用户界面(UI)设计

用户界面(UI)设计

在虚拟现实游戏中,用户界面(UI)设计是至关重要的部分。一个设计良好、用户友好的UI可以极大地提升游戏的体验感,帮助玩家更好地理解游戏规则、操作游戏,并获得更多的沉浸感。Unreal Engine 提供了强大的工具和系统来创建和管理UI元素,本节将详细介绍如何在Unreal Engine 中设计和实现用户界面。

1. 蓝图中的UI设计

1.1 创建UI元素

在Unreal Engine 中,UI元素主要通过**UMG(Unreal Motion Graphics)**来创建和管理。UMG 是一个视觉脚本系统,允许开发者通过拖放和属性设置来设计UI。

步骤:

  1. 打开UMG编辑器:

    • 在内容浏览器中,右键点击空白区域,选择UI -> Widget Blueprint

    • 为新的Widget Blueprint命名,例如HUDWidget

    • 双击HUDWidget打开UMG编辑器。

  2. 添加UI元素:

    • 在UMG编辑器中,从Palette面板中选择你需要的UI元素,例如TextBlockButtonImage等。

    • 将这些元素拖放到Design面板中的画布上。

    • 通过Details面板调整UI元素的属性,例如位置、大小、颜色等。

  3. 布局管理:

    • 使用Anchor来固定UI元素的相对位置。

    • 使用Canvas PanelHorizontal BoxVertical Box等容器来管理多个UI元素的布局。

示例:

假设我们想要创建一个简单的HUD,显示玩家的生命值和分数。


// HUDWidget 示例

// 创建一个TextBlock来显示生命值

TextBlock* HealthText = NewObject<TextBlock>(this, TEXT("HealthText"));

HealthText->SetText(FText::FromString("Health: 100"));

HealthText->SetVisibility(ESlateVisibility::Visible);



// 创建一个TextBlock来显示分数

TextBlock* ScoreText = NewObject<TextBlock>(this, TEXT("ScoreText"));

ScoreText->SetText(FText::FromString("Score: 0"));

ScoreText->SetVisibility(ESlateVisibility::Visible);



// 使用Canvas Panel来管理布局

CanvasPanel* CanvasPanel = NewObject<CanvasPanel>(this, TEXT("CanvasPanel"));

CanvasPanel->AddChild(HealthText);

CanvasPanel->AddChild(ScoreText);



// 设置Canvas Panel的尺寸

CanvasPanel->SetWidthOverride(200);

CanvasPanel->SetHeightOverride(100);



// 设置HealthText的位置

CanvasPanelSlot* HealthSlot = Cast<CanvasPanelSlot>(HealthText->Slot);

HealthSlot->SetPosition(FVector2D(10, 10));



// 设置ScoreText的位置

CanvasPanelSlot* ScoreSlot = Cast<CanvasPanelSlot>(ScoreText->Slot);

ScoreSlot->SetPosition(FVector2D(10, 50));

1.2 动态更新UI

在游戏运行过程中,UI元素需要动态更新以反映游戏状态的变化。这可以通过蓝图脚本或C++代码来实现。

蓝图脚本:

  1. 绑定事件:

    • 在UMG编辑器中,选择需要动态更新的UI元素。

    • Details面板中,找到Events部分,点击+号添加事件。

    • 例如,为TextBlock添加OnTextChanged事件。

  2. 编写事件处理逻辑:

    • 在事件处理节点中,编写更新UI的逻辑。

    • 例如,通过Set Text节点来更新TextBlock的内容。

C++代码:

  1. 创建UI类:

    • 在项目中创建一个新的C++类,继承自UUserWidget

    • 例如,创建一个AHUDWidget类。

  2. 获取UI元素:

    • 在类的构造函数中,通过BindToWidget方法获取UI元素的引用。
  3. 更新UI元素:

    • 通过SetText方法更新TextBlock的内容。

// AHUDWidget.h

#pragma once



#include "CoreMinimal.h"

#include "UUserWidget.h"

#include "Components/TextBlock.h"

#include "AHUDWidget.generated.h"



UCLASS()

class YOURGAME_API AHUDWidget : public UUserWidget

{

    GENERATED_BODY()

    

public:

    virtual bool Initialize() override;



    UFUNCTION(BlueprintCallable, Category = "UI")

    void SetHealth(int32 Health);



    UFUNCTION(BlueprintCallable, Category = "UI")

    void SetScore(int32 Score);



protected:

    UPROPERTY(meta = (BindWidget))

    UTextBlock* HealthText;



    UPROPERTY(meta = (BindWidget))

    UTextBlock* ScoreText;

};



// AHUDWidget.cpp

#include "AHUDWidget.h"



bool AHUDWidget::Initialize()

{

    bool Success = Super::Initialize();

    if (!Success) return false;



    if (HealthText == nullptr)

    {

        UE_LOG(LogTemp, Error, TEXT("HealthText is not assigned"));

        return false;

    }



    if (ScoreText == nullptr)

    {

        UE_LOG(LogTemp, Error, TEXT("ScoreText is not assigned"));

        return false;

    }



    return true;

}



void AHUDWidget::SetHealth(int32 Health)

{

    if (HealthText)

    {

        HealthText->SetText(FText::FromString(FString::Printf(TEXT("Health: %d"), Health)));

    }

}



void AHUDWidget::SetScore(int32 Score)

{

    if (ScoreText)

    {

        ScoreText->SetText(FText::FromString(FString::Printf(TEXT("Score: %d"), Score)));

    }

}

1.3 UI动画

Unreal Engine 中的UI动画可以通过TimelineAnimation Blueprint来实现。Timeline 适用于简单的动画,而Animation Blueprint 则适用于更复杂的动画效果。

Timeline 动画:

  1. 创建Timeline:

    • 在UMG编辑器中,选择需要动画的UI元素。

    • Details面板中,找到Timeline部分,点击Add Timeline按钮。

    • 为Timeline命名,例如FadeInTimeline

  2. 设置关键帧:

    • 在Timeline编辑器中,设置关键帧来定义动画的起始和结束状态。

    • 例如,设置Alpha属性从0到1。

  3. 绑定动画事件:

    • 在Timeline编辑器中,添加事件节点,例如On Finished

    • 在蓝图中,连接这些事件节点到相应的处理逻辑。

示例:

假设我们想要实现一个淡入淡出的动画效果。


// 淡入淡出动画示例

// 创建一个Timeline

Timeline* FadeInTimeline = NewObject<Timeline>(this, TEXT("FadeInTimeline"));



// 设置关键帧

FadeInTimeline->AddFloatTrack("Alpha", 0.0f, 1.0f, 2.0f);



// 绑定动画事件

FadeInTimeline->OnFinished.AddDynamic(this, &AHUDWidget::OnFadeInFinished);



// 播放动画

FadeInTimeline->Play();

C++代码:


// AHUDWidget.h

#pragma once



#include "CoreMinimal.h"

#include "UUserWidget.h"

#include "Components/TextBlock.h"

#include "UMG/TimelineComponent.h"

#include "AHUDWidget.generated.h"



UCLASS()

class YOURGAME_API AHUDWidget : public UUserWidget

{

    GENERATED_BODY()

    

public:

    virtual bool Initialize() override;



    UFUNCTION(BlueprintCallable, Category = "UI")

    void PlayFadeInAnimation();



    UFUNCTION()

    void OnFadeInFinished();



protected:

    UPROPERTY(meta = (BindWidget))

    UTextBlock* HealthText;



    UPROPERTY(meta = (BindWidget))

    UTextBlock* ScoreText;



    UPROPERTY()

    UTimelineComponent* FadeInTimeline;



    UPROPERTY()

    FOnTimelineFloat FadeInAlpha;



    UPROPERTY()

    FOnTimelineEvent FadeInFinished;

};



// AHUDWidget.cpp

#include "AHUDWidget.h"

#include "Kismet/KismetMathLibrary.h"



bool AHUDWidget::Initialize()

{

    bool Success = Super::Initialize();

    if (!Success) return false;



    if (HealthText == nullptr)

    {

        UE_LOG(LogTemp, Error, TEXT("HealthText is not assigned"));

        return false;

    }



    if (ScoreText == nullptr)

    {

        UE_LOG(LogTemp, Error, TEXT("ScoreText is not assigned"));

        return false;

    }



    if (FadeInTimeline == nullptr)

    {

        UE_LOG(LogTemp, Error, TEXT("FadeInTimeline is not assigned"));

        return false;

    }



    // 绑定Alpha值

    FadeInAlpha.BindUFunction(this, "SetHealthTextAlpha");

    FadeInTimeline->AddInterpFloat(FadeInAlpha, FName("FadeInAlpha"));



    // 绑定动画结束事件

    FadeInFinished.BindUFunction(this, "OnFadeInFinished");

    FadeInTimeline->SetTimelineFinishedFunc(FadeInFinished);



    return true;

}



void AHUDWidget::PlayFadeInAnimation()

{

    if (FadeInTimeline)

    {

        FadeInTimeline->Play();

    }

}



void AHUDWidget::SetHealthTextAlpha(float Alpha)

{

    if (HealthText)

    {

        HealthText->SetRenderOpacity(Alpha);

    }

}



void AHUDWidget::OnFadeInFinished()

{

    UE_LOG(LogTemp, Log, TEXT("Fade In Animation Finished"));

}

1.4 响应用户输入

在虚拟现实游戏中,UI需要能够响应用户的输入,例如点击按钮、滑动进度条等。

蓝图脚本:

  1. 绑定事件:

    • 在UMG编辑器中,选择需要响应输入的UI元素。

    • Details面板中,找到Events部分,点击Add Event按钮。

    • 例如,为Button添加OnClicked事件。

  2. 编写处理逻辑:

    • 在事件处理节点中,编写响应用户输入的逻辑。

    • 例如,点击按钮时播放音效或执行某个游戏逻辑。

示例:

假设我们有一个按钮,点击后会增加玩家的分数。


// 响应用户输入示例

// 绑定Button的OnClicked事件

Button* ScoreButton = NewObject<Button>(this, TEXT("ScoreButton"));

ScoreButton->OnClicked.AddDynamic(this, &AHUDWidget::OnScoreButtonClicked);



// 编写处理逻辑

void AHUDWidget::OnScoreButtonClicked()

{

    // 增加分数

    int32 NewScore = 100;

    SetScore(NewScore);



    // 播放音效

    PlaySound();

}

C++代码:


// AHUDWidget.h

#pragma once



#include "CoreMinimal.h"

#include "UUserWidget.h"

#include "Components/TextBlock.h"

#include "Components/Button.h"

#include "AHUDWidget.generated.h"



UCLASS()

class YOURGAME_API AHUDWidget : public UUserWidget

{

    GENERATED_BODY()

    

public:

    virtual bool Initialize() override;



    UFUNCTION(BlueprintCallable, Category = "UI")

    void SetHealth(int32 Health);



    UFUNCTION(BlueprintCallable, Category = "UI")

    void SetScore(int32 Score);



    UFUNCTION()

    void OnScoreButtonClicked();



protected:

    UPROPERTY(meta = (BindWidget))

    UTextBlock* HealthText;



    UPROPERTY(meta = (BindWidget))

    UTextBlock* ScoreText;



    UPROPERTY(meta = (BindWidget))

    UButton* ScoreButton;

};



// AHUDWidget.cpp

#include "AHUDWidget.h"

#include "Kismet/GameplayStatics.h"



bool AHUDWidget::Initialize()

{

    bool Success = Super::Initialize();

    if (!Success) return false;



    if (HealthText == nullptr)

    {

        UE_LOG(LogTemp, Error, TEXT("HealthText is not assigned"));

        return false;

    }



    if (ScoreText == nullptr)

    {

        UE_LOG(LogTemp, Error, TEXT("ScoreText is not assigned"));

        return false;

    }



    if (ScoreButton == nullptr)

    {

        UE_LOG(LogTemp, Error, TEXT("ScoreButton is not assigned"));

        return false;

    }



    // 绑定Button的OnClicked事件

    ScoreButton->OnClicked.AddDynamic(this, &AHUDWidget::OnScoreButtonClicked);



    return true;

}



void AHUDWidget::SetHealth(int32 Health)

{

    if (HealthText)

    {

        HealthText->SetText(FText::FromString(FString::Printf(TEXT("Health: %d"), Health)));

    }

}



void AHUDWidget::SetScore(int32 Score)

{

    if (ScoreText)

    {

        ScoreText->SetText(FText::FromString(FString::Printf(TEXT("Score: %d"), Score)));

    }

}



void AHUDWidget::OnScoreButtonClicked()

{

    // 增加分数

    int32 NewScore = 100;

    SetScore(NewScore);



    // 播放音效

    UGameplayStatics::PlaySound2D(this, YourSoundEffect);

}

1.5 适配不同分辨率

在虚拟现实游戏中,玩家的设备可能具有不同的分辨率。因此,UI需要能够适配不同的屏幕尺寸和分辨率。

方法:

  1. 使用相对布局:

    • 使用Anchor来固定UI元素的相对位置。

    • 使用Canvas PanelPercentage模式来设置UI元素的尺寸和位置。

  2. 使用缩放:

    • 在UMG编辑器中,设置UI元素的Scale属性。

    • 使用ViewportScale属性来调整整个UI的缩放比例。

  3. 使用自适应布局:

    • 在蓝图中,编写逻辑来检测屏幕尺寸,并根据尺寸调整UI元素的位置和大小。

示例:

假设我们想要实现一个自适应的UI,根据屏幕尺寸调整UI元素的位置和大小。


// 适配不同分辨率示例

// 获取屏幕尺寸

FVector2D ScreenSize = GetPlayerScreenSize();



// 根据屏幕尺寸调整UI元素的位置和大小

if (ScreenSize.X > 1920)

{

    HealthText->SetPosition(FVector2D(50, 50));

    HealthText->SetSize(FVector2D(200, 50));

}

else

{

    HealthText->SetPosition(FVector2D(10, 10));

    HealthText->SetSize(FVector2D(100, 25));

}

C++代码:


// AHUDWidget.h

#pragma once



#include "CoreMinimal.h"

#include "UUserWidget.h"

#include "Components/TextBlock.h"

#include "AHUDWidget.generated.h"



UCLASS()

class YOURGAME_API AHUDWidget : public UUserWidget

{

    GENERATED_BODY()

    

public:

    virtual bool Initialize() override;

    virtual void NativeConstruct() override;



    UFUNCTION(BlueprintCallable, Category = "UI")

    void SetHealth(int32 Health);



    UFUNCTION(BlueprintCallable, Category = "UI")

    void SetScore(int32 Score);



protected:

    UPROPERTY(meta = (BindWidget))

    UTextBlock* HealthText;



    UPROPERTY(meta = (BindWidget))

    UTextBlock* ScoreText;

};



// AHUDWidget.cpp

#include "AHUDWidget.h"

#include "Kismet/KismetSystemLibrary.h"



bool AHUDWidget::Initialize()

{

    bool Success = Super::Initialize();

    if (!Success) return false;



    if (HealthText == nullptr)

    {

        UE_LOG(LogTemp, Error, TEXT("HealthText is not assigned"));

        return false;

    }



    if (ScoreText == nullptr)

    {

        UE_LOG(LogTemp, Error, TEXT("ScoreText is not assigned"));

        return false;

    }



    return true;

}



void AHUDWidget::NativeConstruct()

{

    Super::NativeConstruct();



    // 获取屏幕尺寸

    FVector2D ScreenSize;

    UGameViewportClient* ViewportClient = GetWorld()->GetGameViewport();

    ViewportClient->GetViewportSize(ScreenSize);



    // 根据屏幕尺寸调整UI元素的位置和大小

    if (ScreenSize.X > 1920)

    {

        HealthText->SetPosition(FVector2D(50, 50));

        HealthText->SetSize(FVector2D(200, 50));



        ScoreText->SetPosition(FVector2D(50, 100));

        ScoreText->SetSize(FVector2D(200, 50));

    }

    else

    {

        HealthText->SetPosition(FVector2D(10, 10));

        HealthText->SetSize(FVector2D(100, 25));



        ScoreText->SetPosition(FVector2D(10, 40));

        ScoreText->SetSize(FVector2D(100, 25));

    }

}



void AHUDWidget::SetHealth(int32 Health)

{

    if (HealthText)

    {

        HealthText->SetText(FText::FromString(FString::Printf(TEXT("Health: %d"), Health)));

    }

}



void AHUDWidget::SetScore(int32 Score)

{

    if (ScoreText)

    {

        ScoreText->SetText(FText::FromString(FString::Printf(TEXT("Score: %d"), Score)));

    }

}

1.6 UI的性能优化

在虚拟现实游戏中,UI的性能优化非常重要,以确保游戏的流畅运行和良好的用户体验。优化UI可以显著提高游戏的帧率和响应速度,从而提升玩家的整体体验。

方法:

  1. 减少UI元素数量:

    • 尽量减少不必要的UI元素,只保留必要的部分。

    • 使用Lazy Load来延迟加载UI元素。

  2. 使用缓存:

    • 缓存频繁更新的UI元素的内容,避免每次更新都重新渲染。

    • 使用Texture Cache来缓存频繁使用的纹理。

  3. 优化绘制:

    • 使用Draw Call合并来减少绘制调用次数。

    • 确保UI元素的材质和纹理都是优化过的。

  4. 使用GPU Instancing:

    • 对于大量相似的UI元素,使用GPU Instancing来提高性能。

示例:

假设我们有一个UI元素,需要频繁更新其内容。为了优化性能,我们可以缓存TextBlock的内容,只有在内容发生变化时才进行更新。


// AHUDWidget.h

#pragma once



#include "CoreMinimal.h"

#include "UUserWidget.h"

#include "Components/TextBlock.h"

#include "AHUDWidget.generated.h"



UCLASS()

class YOURGAME_API AHUDWidget : public UUserWidget

{

    GENERATED_BODY()

    

public:

    virtual bool Initialize() override;

    virtual void NativeConstruct() override;



    UFUNCTION(BlueprintCallable, Category = "UI")

    void SetHealth(int32 Health);



    UFUNCTION(BlueprintCallable, Category = "UI")

    void SetScore(int32 Score);



protected:

    UPROPERTY(meta = (BindWidget))

    UTextBlock* HealthText;



    UPROPERTY(meta = (BindWidget))

    UTextBlock* ScoreText;



    // 缓存TextBlock的内容

    FString CachedHealthText;

    FString CachedScoreText;

};



// AHUDWidget.cpp

#include "AHUDWidget.h"



bool AHUDWidget::Initialize()

{

    bool Success = Super::Initialize();

    if (!Success) return false;



    if (HealthText == nullptr)

    {

        UE_LOG(LogTemp, Error, TEXT("HealthText is not assigned"));

        return false;

    }



    if (ScoreText == nullptr)

    {

        UE_LOG(LogTemp, Error, TEXT("ScoreText is not assigned"));

        return false;

    }



    return true;

}



void AHUDWidget::SetHealth(int32 Health)

{

    FString NewHealthText = FString::Printf(TEXT("Health: %d"), Health);

    if (NewHealthText != CachedHealthText)

    {

        HealthText->SetText(FText::FromString(NewHealthText));

        CachedHealthText = NewHealthText;

    }

}



void AHUDWidget::SetScore(int32 Score)

{

    FString NewScoreText = FString::Printf(TEXT("Score: %d"), Score);

    if (NewScoreText != CachedScoreText)

    {

        ScoreText->SetText(FText::FromString(NewScoreText));

        CachedScoreText = NewScoreText;

    }

}

1.7 国际化和本地化

在虚拟现实游戏中,支持多语言和本地化是提升全球玩家体验的重要手段。Unreal Engine 提供了强大的国际化和本地化工具,可以帮助开发者轻松实现这一目标。

方法:

  1. 使用FText:

    • FText是Unreal Engine 中用于处理多语言文本的类。

    • 使用FText::FromString方法来设置UI元素的文本内容。

  2. 创建本地化资源:

    • 在项目设置中,启用Localization

    • 使用Localization Dashboard来创建和管理本地化资源文件。

  3. 加载本地化资源:

    • 在运行时,根据当前的语言设置加载相应的本地化资源。

示例:

假设我们想要支持英语和中文的UI文本。

  1. 启用国际化:

    • 在项目设置中,导航到Project Settings -> Localization

    • 启用Enable Localization选项。

    • 添加支持的语言,例如EnglishSimplified Chinese

  2. 创建本地化资源文件:

    • 使用Localization Dashboard创建本地化资源文件。

    • 为每种语言添加相应的文本内容。

  3. 加载本地化资源:

    • 在C++代码中,使用NSLOCTEXT宏来定义本地化的文本。

    • 在运行时,使用FInternationalization::GetString方法来获取当前语言的文本内容。


// AHUDWidget.h

#pragma once



#include "CoreMinimal.h"

#include "UUserWidget.h"

#include "Components/TextBlock.h"

#include "AHUDWidget.generated.h"



UCLASS()

class YOURGAME_API AHUDWidget : public UUserWidget

{

    GENERATED_BODY()

    

public:

    virtual bool Initialize() override;

    virtual void NativeConstruct() override;



    UFUNCTION(BlueprintCallable, Category = "UI")

    void SetHealth(int32 Health);



    UFUNCTION(BlueprintCallable, Category = "UI")

    void SetScore(int32 Score);



protected:

    UPROPERTY(meta = (BindWidget))

    UTextBlock* HealthText;



    UPROPERTY(meta = (BindWidget))

    UTextBlock* ScoreText;

};



// AHUDWidget.cpp

#include "AHUDWidget.h"

#include "Internationalization/Internationalization.h"



bool AHUDWidget::Initialize()

{

    bool Success = Super::Initialize();

    if (!Success) return false;



    if (HealthText == nullptr)

    {

        UE_LOG(LogTemp, Error, TEXT("HealthText is not assigned"));

        return false;

    }



    if (ScoreText == nullptr)

    {

        UE_LOG(LogTemp, Error, TEXT("ScoreText is not assigned"));

        return false;

    }



    return true;

}



void AHUDWidget::NativeConstruct()

{

    Super::NativeConstruct();



    // 初始化文本内容

    HealthText->SetText(NSLOCTEXT("HUD", "HealthLabel", "Health: 100"));

    ScoreText->SetText(NSLOCTEXT("HUD", "ScoreLabel", "Score: 0"));

}



void AHUDWidget::SetHealth(int32 Health)

{

    if (HealthText)

    {

        FString HealthString = FString::Printf(TEXT("%d"), Health);

        HealthText->SetText(FText::Format(NSLOCTEXT("HUD", "HealthFormat", "Health: {0}"), FText::FromString(HealthString)));

    }

}



void AHUDWidget::SetScore(int32 Score)

{

    if (ScoreText)

    {

        FString ScoreString = FString::Printf(TEXT("%d"), Score);

        ScoreText->SetText(FText::Format(NSLOCTEXT("HUD", "ScoreFormat", "Score: {0}"), FText::FromString(ScoreString)));

    }

}

1.8 无障碍设计

无障碍设计是确保所有玩家,包括残障玩家,都能享受游戏的重要方面。Unreal Engine 提供了多种工具和方法来实现无障碍设计。

方法:

  1. 文字大小和颜色:

    • 确保文字大小足够大,颜色对比度高,以便视力受限的玩家能够轻松阅读。

    • 提供文字缩放选项,允许玩家根据需要调整文字大小。

  2. 语音提示:

    • 为重要的UI元素添加语音提示,帮助听力受限的玩家理解游戏状态。

    • 使用AudioComponent来播放语音提示。

  3. 键盘导航:

    • 为UI元素添加键盘导航支持,帮助无法使用手柄的玩家进行操作。

    • 使用Widget SwitcherInput Action来实现键盘导航。

  4. 触觉反馈:

    • 为UI元素添加触觉反馈,帮助触觉受限的玩家感知游戏状态。

    • 使用Haptic Feedback组件来实现触觉反馈。

示例:

假设我们想要为UI添加键盘导航支持。

  1. 设置键盘导航:

    • 在UMG编辑器中,选择需要支持键盘导航的UI元素。

    • Details面板中,找到Navigation部分,设置Focus属性。

  2. 编写导航逻辑:

    • 在蓝图中,编写逻辑来处理键盘导航事件。

    • 例如,使用Set Focus节点来切换焦点。


// 键盘导航示例

// 为Button设置Focus属性

ScoreButton->SetFocusable(true);



// 编写导航逻辑

void AHUDWidget::OnKeyPressed(FKey Key)

{

    if (Key == EKeys::Tab)

    {

        // 切换焦点

        if (HealthText->HasFocus())

        {

            ScoreText->SetFocus();

        }

        else

        {

            HealthText->SetFocus();

        }

    }

}

C++代码:


// AHUDWidget.h

#pragma once



#include "CoreMinimal.h"

#include "UUserWidget.h"

#include "Components/TextBlock.h"

#include "Components/Button.h"

#include "AHUDWidget.generated.h"



UCLASS()

class YOURGAME_API AHUDWidget : public UUserWidget

{

    GENERATED_BODY()

    

public:

    virtual bool Initialize() override;

    virtual void NativeConstruct() override;

    virtual void NativeTick(const FGeometry& MyGeometry, float InDeltaTime) override;



    UFUNCTION(BlueprintCallable, Category = "UI")

    void SetHealth(int32 Health);



    UFUNCTION(BlueprintCallable, Category = "UI")

    void SetScore(int32 Score);



    UFUNCTION()

    void OnScoreButtonClicked();



protected:

    UPROPERTY(meta = (BindWidget))

    UTextBlock* HealthText;



    UPROPERTY(meta = (BindWidget))

    UTextBlock* ScoreText;



    UPROPERTY(meta = (BindWidget))

    UButton* ScoreButton;

};



// AHUDWidget.cpp

#include "AHUDWidget.h"

#include "Kismet/GameplayStatics.h"

#include "Engine/InputSettings.h"



bool AHUDWidget::Initialize()

{

    bool Success = Super::Initialize();

    if (!Success) return false;



    if (HealthText == nullptr)

    {

        UE_LOG(LogTemp, Error, TEXT("HealthText is not assigned"));

        return false;

    }



    if (ScoreText == nullptr)

    {

        UE_LOG(LogTemp, Error, TEXT("ScoreText is not assigned"));

        return false;

    }



    if (ScoreButton == nullptr)

    {

        UE_LOG(LogTemp, Error, TEXT("ScoreButton is not assigned"));

        return false;

    }



    // 绑定Button的OnClicked事件

    ScoreButton->OnClicked.AddDynamic(this, &AHUDWidget::OnScoreButtonClicked);



    // 设置Button的Focus属性

    ScoreButton->SetFocusable(true);



    return true;

}



void AHUDWidget::NativeConstruct()

{

    Super::NativeConstruct();



    // 获取屏幕尺寸

    FVector2D ScreenSize;

    UGameViewportClient* ViewportClient = GetWorld()->GetGameViewport();

    ViewportClient->GetViewportSize(ScreenSize);



    // 根据屏幕尺寸调整UI元素的位置和大小

    if (ScreenSize.X > 1920)

    {

        HealthText->SetPosition(FVector2D(50, 50));

        HealthText->SetSize(FVector2D(200, 50));



        ScoreText->SetPosition(FVector2D(50, 100));

        ScoreText->SetSize(FVector2D(200, 50));

    }

    else

    {

        HealthText->SetPosition(FVector2D(10, 10));

        HealthText->SetSize(FVector2D(100, 25));



        ScoreText->SetPosition(FVector2D(10, 40));

        ScoreText->SetSize(FVector2D(100, 25));

    }

}



void AHUDWidget::NativeTick(const FGeometry& MyGeometry, float InDeltaTime)

{

    Super::NativeTick(MyGeometry, InDeltaTime);



    // 检测键盘输入

    if (FInputSystem::Get().IsKeyPressed(EKeys::Tab))

    {

        // 切换焦点

        if (HealthText->HasFocusedDescendants())

        {

            ScoreText->SetFocus();

        }

        else

        {

            HealthText->SetFocus();

        }

    }

}



void AHUDWidget::SetHealth(int32 Health)

{

    if (HealthText)

    {

        FString HealthString = FString::Printf(TEXT("%d"), Health);

        HealthText->SetText(FText::Format(NSLOCTEXT("HUD", "HealthFormat", "Health: {0}"), FText::FromString(HealthString)));

    }

}



void AHUDWidget::SetScore(int32 Score)

{

    if (ScoreText)

    {

        FString ScoreString = FString::Printf(TEXT("%d"), Score);

        ScoreText->SetText(FText::Format(NSLOCTEXT("HUD", "ScoreFormat", "Score: {0}"), FText::FromString(ScoreString)));

    }

}



void AHUDWidget::OnScoreButtonClicked()

{

    // 增加分数

    int32 NewScore = 100;

    SetScore(NewScore);



    // 播放音效

    UGameplayStatics::PlaySound2D(this, YourSoundEffect);

}

1.9 总结

在虚拟现实游戏中,用户界面(UI)设计是提升游戏体验的关键因素之一。通过使用Unreal Engine 提供的UMG工具,开发者可以轻松创建和管理各种UI元素。动态更新UI、实现UI动画、响应用户输入、适配不同分辨率、优化UI性能、支持国际化和本地化,以及实现无障碍设计,都是设计高质量UI的重要步骤。希望本节的内容能够帮助你在虚拟现实游戏中设计出更加友好和高效的用户界面。

评论
成就一亿技术人!
拼手气红包6.0元
还能输入1000个字符
 
红包 添加红包
表情包 插入表情
 条评论被折叠 查看
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

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

余额充值