實例甜點 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

 


免責聲明!

本站轉載的文章為個人學習借鑒使用,本站對版權不負任何法律責任。如果侵犯了您的隱私權益,請聯系本站郵箱yoyou2525@163.com刪除。



 
粵ICP備18138465號   © 2018-2025 CODEPRJ.COM