zoukankan      html  css  js  c++  java
  • 实例甜点 Unreal Engine 4迷你教程(1)之如何用C++将纹理绘制在UserWidget的Image小部件上

    完成本迷你教程之前,请前往完成以下迷你教程:

    无前置教程待完成。

     

    本教程适合的人群:

    初学者,具有开发经验两周;

     

    本示例的目的:为了在代码中实现UMG中的这个功能:

     

     

    说明:这是一些列迷你教程的首篇,所以步骤比较多。

     

    1步:创建一个FPSC++)模板工程,我的工程命名为LearnWidgets

    2步:在c++文件夹中找到以下已有的两个类,LearnWidgetsGameMode派生出BPGMLearnWidgetsHUD派生出BPHUD;并在BPGM中配置HUDBPHUD

     

     

     

     

    3步:

    创建一个继承自AActor的类,称为WidgetMng,表示Widget的管理者类,它的功能将会慢慢变强大。

     

     

    4步:

    工程.build.cs 文件中改动代码:

     

    ▼代码开始
        public LearnWidgets(ReadOnlyTargetRules Target) : base(Target)
        {
            PCHUsage = PCHUsageMode.UseExplicitOrSharedPCHs;
    
            PublicDependencyModuleNames.AddRange(new string[] { "Core", "CoreUObject", "Engine", "InputCore", "HeadMountedDisplay"
    //从这一行开始是新增的——————
    , "UMG" });
    
            // Uncomment if you are using Slate UI
            PrivateDependencyModuleNames.AddRange(new string[] { "Slate", "SlateCore" });
    //新增结束——————
        }
    ▲代码结束

    【实验Tips:如果遇到了无法编译的问题,可以尝试关闭Editor,重启VS,后再build

    5步:

    WidgetMng的代码是这样的:(按照我的风格,我会在代码中写入详细的注释,边看代码边看注释就会明白)

    ▼代码开始
    // Fill out your copyright notice in the Description page of Project Settings.
    
    #pragma once
    
    #include "CoreMinimal.h"
    #include "GameFramework/Actor.h"
    
    #include "WidgetMng.generated.h"
    
    UCLASS()
    class LEARNWIDGETS_API AWidgetMng : public AActor
    {
        GENERATED_BODY()
        
    public:    
        // Sets default values for this actor's properties
        AWidgetMng();
    
    protected:
        // Called when the game starts or when spawned
        virtual void BeginPlay() override;
    
    public:    
        // Called every frame
        virtual void Tick(float DeltaTime) override;
    
        UPROPERTY(EditAnywhere, BlueprintReadWrite, Category = Ws)
            TSubclassOf<class UUserWidget> SlaveWidgetClass;
    //这是一个UUserWidget的类目(暴露给蓝图以做选择)
        
        UPROPERTY()
            class UUserWidget* SlaveWidget;
    //这是真正的UUserWidget实例的指针(当然起初是null)
    
        UFUNCTION()
            void Initialize();
    //初始化函数
    
        UPROPERTY(EditAnywhere, BlueprintReadWrite, Category = WsTexture)
            UTexture2D* T2D;
    //这是一张纹理UTexture2D,暴露给蓝图以做选择    
    
        UFUNCTION()
            void ChangeImage(UTexture2D* T2D0);
    //ChangeImage函数希望将它所管理的SlaveWidget中的Image小部件的图片设置为T2D0纹理
    
        UFUNCTION()
            void ChangeText(const FString & F);
    //ChangeText函数希望将它所管理的SlaveWidget中的TextBlock小部件的文本设置为F;
    
    };
    
    ▲代码结束
    以下是cpp文件。
    
    ▼代码开始
    // Fill out your copyright notice in the Description page of Project Settings.
    
    #include "WidgetMng.h"
    #include "Runtime/UMG/Public/Blueprint/UserWidget.h"
    #include "Runtime/UMG/Public/Components/Image.h"
    #include "Runtime/Engine/Classes/Engine/Texture2D.h"
    #include "Runtime/UMG/Public/Components/TextBlock.h"
    //这里要加一些头文件,至于头文件如何加,这里就先不解释了。
    
    // Sets default values
    AWidgetMng::AWidgetMng()
    {
         // Set this actor to call Tick() every frame.  You can turn this off to improve performance if you don't need it.
        PrimaryActorTick.bCanEverTick = true;
    
    }
    
    // Called when the game starts or when spawned
    void AWidgetMng::BeginPlay()
    {
        Super::BeginPlay();
        
    }
    
    // Called every frame
    void AWidgetMng::Tick(float DeltaTime)
    {
        Super::Tick(DeltaTime);
    
    }
    
    void AWidgetMng::Initialize()
    {
        UE_LOG(LogTemp, Warning, TEXT("%s"), *FString("31 Initialize WidgetMng"));
    //这是LOG
    
        if (SlaveWidgetClass && SlaveWidget==NULL)
        {
            SlaveWidget = CreateWidget<UUserWidget>(GWorld->GetGameInstance(), SlaveWidgetClass);//【重要】创建UUserWidget的做法
            if (SlaveWidget)
            {
                SlaveWidget->AddToViewport();//将此实例加到屏幕上
    
            }
        }
    }
    
    void AWidgetMng::ChangeImage(UTexture2D* T2D0)
    {
        UImage* MyImage = Cast<UImage>(SlaveWidget->GetWidgetFromName(TEXT("MyImage")));
    //【重要】从SlaveWidget中找到一个名为MyImage的小部件
        if (MyImage)
        {
            UE_LOG(LogTemp, Warning, TEXT("%s"), *FString("Changing Image With A T2D"));
            MyImage->SetBrushFromTexture(T2D0);//【重要】用纹理UTexture2D来设置这个Image小部件
        }
    
    }
    
    void AWidgetMng::ChangeText(const FString & F)
    {//【重要】这个函数展示了设置特定文本给一个名为MyTextBlock的小部件;
        UTextBlock* MyTextBlock = Cast<UTextBlock>(SlaveWidget->GetWidgetFromName(TEXT("MyTextBlock")));
        if (MyTextBlock)
        {
            MyTextBlock->SetText(FText::FromString(F));
        }
    
    }
    
    ▲代码结束

    5+步:在内容浏览器中新建一个UserWidget(命名为WeaponDisplayer)如下:

    注意到它有两个小部件,我们命名为MyImageMyTextBlock

    6步:找到WidgetMngCpp),然后派生一个蓝图名为BPWidgetMng1

    第7步:给BPWidgetMng1中配置白色框框部分(还记得吗,它们是前面步骤暴露出来的):

    注意到这里有一张纹理图片叫wenjiezou,你可以import其它的图像文件进来作为纹理;

    8步:

    前面写完了WidgetMngWidget管理者),现在写HUD的逻辑,希望HUD能够生成WidgetMng;然后再生成UserWidget(也就是SlaveWidget)。(分号后面这句话已经编写完逻辑了,现在要做的就是分号前的那个需求)

    LearnWidgetsHUD中,只需要稍微改改代码即可。

    LearnWidgetsHUD.h文件:

    ▼代码开始
    // Copyright 1998-2017 Epic Games, Inc. All Rights Reserved.
    
    #pragma once 
    
    #include "CoreMinimal.h"
    #include "GameFramework/HUD.h"
    #include "WidgetMng/WidgetMng.h"
    #include "LearnWidgetsHUD.generated.h"
    
    UCLASS()
    class ALearnWidgetsHUD : public AHUD
    {
        GENERATED_BODY()
    
    public:
        ALearnWidgetsHUD();
    
        /** Primary draw call for the HUD */
        virtual void DrawHUD() override;
    
    private:
        /** Crosshair asset pointer */
        class UTexture2D* CrosshairTex;
    
    public:
        UPROPERTY(EditAnywhere, BlueprintReadWrite, Category = WidgetMngs)
            TArray<TSubclassOf<AWidgetMng>> WidgetMngsClasses;//【暴露了一些Mngs的类目】
        UPROPERTY()
            TArray<AWidgetMng*> WidgetMngs;//真正的Mngs实例
    
        virtual void BeginPlay() override;
    };
    
    
    ▲代码结束
    
    LearnWidgetsHUD.cpp文件:
    ▼代码开始
    // Copyright 1998-2017 Epic Games, Inc. All Rights Reserved.
    
    #include "LearnWidgetsHUD.h"
    #include "Engine/Canvas.h"
    #include "Engine/Texture2D.h"
    #include "TextureResource.h"
    #include "CanvasItem.h"
    #include "UObject/ConstructorHelpers.h"
    
    ALearnWidgetsHUD::ALearnWidgetsHUD()
    {
        // Set the crosshair texture
        static ConstructorHelpers::FObjectFinder<UTexture2D> CrosshairTexObj(TEXT("/Game/FirstPerson/Textures/FirstPersonCrosshair"));
        CrosshairTex = CrosshairTexObj.Object;
    }
    
    
    void ALearnWidgetsHUD::DrawHUD()
    {
        Super::DrawHUD();
    
        // Draw very simple crosshair
    
        // find center of the Canvas
        const FVector2D Center(Canvas->ClipX * 0.5f, Canvas->ClipY * 0.5f);
    
        // offset by half the texture's dimensions so that the center of the texture aligns with the center of the Canvas
        const FVector2D CrosshairDrawPosition( (Center.X),
                                               (Center.Y + 20.0f));
    
        // draw the crosshair
        FCanvasTileItem TileItem( CrosshairDrawPosition, CrosshairTex->Resource, FLinearColor::White);
        TileItem.BlendMode = SE_BLEND_Translucent;
        Canvas->DrawItem( TileItem );
    }
    
    //只关注这里,这里实例化了WidgetMng
    void ALearnWidgetsHUD::BeginPlay()
    {
        for (auto index = 0; index<WidgetMngsClasses.Num(); index++)
        {
            AWidgetMng* NewWidgetMng = NewObject<AWidgetMng>(GetGameInstance(), WidgetMngsClasses[index]);
            WidgetMngs.Add(NewWidgetMng);
            NewWidgetMng->Initialize();
        }
    }
    
    ▲代码结束

    9步:现在再介绍一个点,就是从PCplayercontroller)指挥这个Mng修改文字或图片。我发现没有PC,只有现成的LearnWidgetsCharacter,所以这里就介绍从Character索引到WidgetMng,其实都差不多;

    LearnWidgetsCharacter中加入代码:

    void ALearnWidgetsCharacter::Action1()
    {
        UE_LOG(LogTemp, Warning, TEXT("%s"), *FString("Action1 ing"));
        ALearnWidgetsHUD*  HUD = Cast<ALearnWidgetsHUD>(UGameplayStatics::GetPlayerController(this, 0)->GetHUD());//【重要】这是从Character索引到HUD的方法
        if (HUD->WidgetMngs.Num())
        {
            HUD->WidgetMngs[0]->ChangeImage(HUD->WidgetMngs[0]->T2D);//【重要】从HUD索引到WidgetMng,调用显示图像函数
        }
    }

    然后再讲这个Action1绑定在Action1输入上(如果这个不懂,请学习setupinputcomponent相关的知识);

    10步:

    Gamemode是这样的。(如果你不知道什么是Gamemode,请去官网学习Gamemode内容;)

    11步:

     

    按下Action1后(这个Action1是你自己定义的按键噢):

     

    ——小江村儿的文杰 zouwj5@qq.com 20178214:56:24

  • 相关阅读:
    多表联合查询,利用 concat 模糊搜索
    order by 中利用 case when 排序
    Quartz.NET 3.0.7 + MySql 动态调度作业+动态切换版本+多作业引用同一程序集不同版本+持久化+集群(一)
    ASP.NET Core 2.2 基础知识(十八) 托管和部署 概述
    ASP.NET Core 2.2 基础知识(十七) SignalR 一个极其简陋的聊天室
    ASP.NET Core 2.2 基础知识(十六) SignalR 概述
    ASP.NET Core 2.2 基础知识(十五) Swagger
    ASP.NET Core 2.2 基础知识(十四) WebAPI Action返回类型(未完待续)
    linux磁盘管理 磁盘查看操作
    linux磁盘管理 文件挂载
  • 原文地址:https://www.cnblogs.com/JackSamuel/p/7277865.html
Copyright © 2011-2022 走看看