【UE5】構造体の利用【C++】

学んだこと、試したこと、調べたことをまとめています。

Widget切り替え

C++での切り替え方法が良く分からなかったので、ここはBlueprintを使った。

Widget Classはインスタンス編集可能にしている。

・Widget Classのアクセス指定子をpublicにしておくことで、他のBPでWidgetを切り替えられるようにした。
KihiroGMB.h

#pragma once

#include "CoreMinimal.h"
#include "GameFramework/GameModeBase.h"
#include "DoOnceUW.h"
#include "UW_DoN.h"
#include "KishiroGMB.generated.h"

/**
 * 
 */
UCLASS()
class SAMPLEPROJECT_API AKishiroGMB : public AGameModeBase
{
	GENERATED_BODY()

public:		

	UPROPERTY(EditAnywhere, BlueprintReadWrite, Category="Class Types")
	TSubclassOf<UUserWidget> WidgetClass;

protected:

	UPROPERTY(VisibleInstanceOnly, Category="Runtime")
	class UKishiroUW* KishiroUW;

	UPROPERTY(VisibleInstanceOnly, Category = "Runtime")
	class UDoOnceUW* DoOnceUW;

	UPROPERTY(VisibleInstanceOnly, Category = "Runtime")
	class UUW_DoN* DoNUW;

	void BeginPlay() override;

	void SetupInput();

	void PressedB();
	
	APlayerController* ControllerRef;

	ACharacter* PlayerRef;

	bool bisPressedB = false;
};

KishiroGMB.cpp

#include "KishiroGMB.h"
#include "KishiroUW.h"
#include <UObject/UObjectGlobals.h>
#include <Kismet/GameplayStatics.h>
#include <GameFramework/Character.h>
#include <Kismet/KismetSystemLibrary.h>

void AKishiroGMB::BeginPlay()
{

	ControllerRef = UGameplayStatics::GetPlayerController(GetWorld(), 0);
	
	PlayerRef = UGameplayStatics::GetPlayerCharacter(GetWorld(), 0);

	SetupInput();
}

void AKishiroGMB::SetupInput()
{
	EnableInput(ControllerRef);

	InputComponent->BindKey(EKeys::B, IE_Pressed, this, &AKishiroGMB::PressedB);
}

void AKishiroGMB::PressedB()
{
	if (!bisPressedB)
	{
		if (IsValid(WidgetClass))
		{
			FString ClassName = WidgetClass->GetName();
			UKismetSystemLibrary::PrintString(this, ClassName, true, true, FColor::Cyan, 10.0f);


			if (ClassName == TEXT("WB_KishiroUW_C"))
			{
				KishiroUW = Cast<UKishiroUW>(CreateWidget(GetWorld(), WidgetClass));
				KishiroUW->AddToViewport();
			}
			
			if (ClassName == TEXT("WB_DoOnce_C"))
			{
				DoOnceUW = Cast<UDoOnceUW>(CreateWidget(GetWorld(), WidgetClass));
				DoOnceUW->AddToViewport();
			}

			if (ClassName == TEXT("WB_DoN_C"))
			{
				DoNUW = Cast<UUW_DoN>(CreateWidget(GetWorld(), WidgetClass));
				DoNUW->AddToViewport();
			}

			ControllerRef->SetShowMouseCursor(true);
			PlayerRef->DisableInput(ControllerRef);
			bisPressedB = true;
		}
	}
	else
	{
		if (IsValid(WidgetClass))
		{
			if (KishiroUW != nullptr) { KishiroUW->RemoveFromParent(); }
			if (DoOnceUW != nullptr) { DoOnceUW->RemoveFromParent(); }
			if (DoNUW != nullptr) { DoNUW->RemoveFromParent(); }

			ControllerRef->SetShowMouseCursor(false);
			PlayerRef->EnableInput(ControllerRef);
			bisPressedB = false;
		}
	}

}

マクロ

BPにおけるマクロの特徴
・実行ピンを複数持てる
・ローカル変数がリセットされない
・アクセス指定子はprivate
👇参考動画

【UE4/UE5ゲーム制作講座】超基礎編・これを見れば変数がわかる!

👇StandardMacros

今回は構造体を使ってマクロと同じような働きをつくる。
BPとの比較
・複数の実行ピン
複数もつことはできる。ピンじゃないけど。
・ローカル変数
リセットしなければ、リセットされない。
・アクセス指定子
構造体自体はprivateではないが、マクロの働きをする関数自体はprivateにすることは可能。
感想
汎用性が高く複雑な処理があれば、手間を減らせるし見通しも立てやすくなりそう。

Gate

Gate.h

// Fill out your copyright notice in the Description page of Project Settings.

#pragma once

#include "Gate.generated.h"

USTRUCT(BlueprintType)
struct FGate
{
	GENERATED_BODY()

public:
	FORCEINLINE FGate();
	explicit FORCEINLINE FGate(bool StartClosed);

	FORCEINLINE void Open() { bGateOpen = true; }

	FORCEINLINE void Close() { bGateOpen = false; }

	FORCEINLINE void Toggle() { bGateOpen = !bGateOpen; }

	FORCEINLINE bool IsOpen() const { return bGateOpen; }

private:
	UPROPERTY(VisibleAnywhere)
	bool bGateOpen;
};

FORCEINLINE FGate::FGate() : bGateOpen(false)
{}

FORCEINLINE FGate::FGate(const bool bStartClosed) : bGateOpen(!bStartClosed)
{}

実装内容
・クリックしたら1ずつ数が増える。
・Closeにすると、クリックしても反応しない。
・Openで、Close状態を解除。
KishiroUW.h(関連箇所のみ)

#include "Gate.h"
protected:
        UPROPERTY(BlueprintReadWrite, meta = (BindWidget))
	class UTextBlock* CountTxt;

	UPROPERTY(BlueprintReadWrite, meta = (BindWidget))
	class UButton* ExecuteBtn;

	UPROPERTY(BlueprintReadWrite, meta = (BindWidget))
	class UButton* OpenBtn;

	UPROPERTY(BlueprintReadWrite, meta = (BindWidget))
	class UButton* CloseBtn;

        void NativeConstruct() override;


	UFUNCTION()
	void OnExecuteClick();

	UFUNCTION()
	void OnOpenClick();

	UFUNCTION()
	void OnCloseClick();

private:
	FGate Gate;

	int32 Count;

KishiroUW.cpp(関連箇所のみ)

// Fill out your copyright notice in the Description page of Project Settings.


#include "KishiroUW.h"
#include <Components/Button.h>
#include <Components/TextBlock.h>

#include <Kismet/GameplayStatics.h>

void UKishiroUW::NativeConstruct()
{
	

	if (Btn1)
	{

		ExecuteBtn->OnClicked.AddDynamic(this, &UKishiroUW::OnExecuteClick);
		OpenBtn->OnClicked.AddDynamic(this, &UKishiroUW::OnOpenClick);
		CloseBtn->OnClicked.AddDynamic(this, &UKishiroUW::OnCloseClick);

	}
	Count = 0;
	Gate.Open();
	CountTxt->SetText(FText::AsNumber(Count));
}

void UKishiroUW::OnExecuteClick()
{
	if (Gate.IsOpen())
	{
		Count += 1;
		CountTxt->SetText(FText::AsNumber(Count));
	}
	
}

void UKishiroUW::OnOpenClick()
{
	Gate.Open();
}

void UKishiroUW::OnCloseClick()
{
	Gate.Close();
}

DoOnce

DoOnce.h


#pragma once

#include "DoOnce.generated.h"

USTRUCT(BlueprintType)
struct FDoOnce
{
	GENERATED_BODY()

	UPROPERTY(BlueprintReadWrite)
	bool bDoOnce;

	FORCEINLINE FDoOnce();
	explicit FORCEINLINE FDoOnce(bool bStartClosed);

	FORCEINLINE void Reset() { bDoOnce = true; }

	FORCEINLINE bool Execute()
	{
		if (bDoOnce)
		{
			bDoOnce = false;
			return true;
		}
		return false;
	}
};

FORCEINLINE FDoOnce::FDoOnce() : bDoOnce(false)
{}

FORCEINLINE FDoOnce::FDoOnce(const bool bStartClosed) : bDoOnce(!bStartClosed)
{}

実装内容

・Executeボタンを1回おすと、Executedと表示される。
・2回目以降はAlready Executedになる。
・Resetで初期状態に戻せる。

DoOnceUW.h

#pragma once

#include "CoreMinimal.h"
#include "Blueprint/UserWidget.h"
#include "DoOnce.h"
#include "DoOnceUW.generated.h"

/**
 * 
 */
UCLASS()
class SAMPLEPROJECT_API UDoOnceUW : public UUserWidget
{
	GENERATED_BODY()

protected:
	UPROPERTY(BlueprintReadWrite, meta = (BindWidget))
	class UTextBlock* StateTxt;

	UPROPERTY(BlueprintReadWrite, meta = (BindWidget))
	class UButton* ExecuteBtn;

	UPROPERTY(BlueprintReadWrite, meta = (BindWidget))
	class UButton* ResetBtn;

	void NativeConstruct() override;

	UFUNCTION()
	void OnExecuteClick();

	UFUNCTION()
	void OnResetClick();

	UPROPERTY(VisibleAnywhere)
	FDoOnce DoOnce;

};

DoOnceUW.cpp

#include "DoOnceUW.h"
#include <Components/Button.h>
#include <Components/TextBlock.h>

void UDoOnceUW::NativeConstruct()
{
	Super::NativeConstruct();

	DoOnce.Reset();

	if (ExecuteBtn && ResetBtn)
	{
		ExecuteBtn->OnClicked.AddDynamic(this, &UDoOnceUW::OnExecuteClick);
		ResetBtn->OnClicked.AddDynamic(this, &UDoOnceUW::OnResetClick);
	}
	StateTxt->SetText(FText::AsCultureInvariant(TEXT("Not Executed")));
}

void UDoOnceUW::OnExecuteClick()
{
	if (DoOnce.Execute())
	{
		StateTxt->SetText(FText::AsCultureInvariant(TEXT("Executed")));
	}
	else
	{
		StateTxt->SetText(FText::AsCultureInvariant(TEXT("Already Executed")));
	}
}

void UDoOnceUW::OnResetClick()
{
	StateTxt->SetText(FText::AsCultureInvariant(TEXT("Not Executed")));
	DoOnce.Reset();
}

DoN

DoN.h

#pragma once

#include "DoN.generated.h"

USTRUCT(BlueprintType)
struct FDoN
{
	GENERATED_BODY()

	UPROPERTY(BlueprintReadWrite)
	int32 N = 1;

	UPROPERTY(BlueprintReadWrite)
	int32 Count = 0;

	FORCEINLINE void Reset()
	{
		Count = 0;
	}

	FORCEINLINE void Reset(int32 InN)
	{
		N = InN;
		Count = 0;
	}

	FORCEINLINE bool Execute()
	{
		if (Count < N)
		{
			Count += 1;
			return true;
		}
		return false;
	}

	FORCEINLINE bool Execute(int32 InN)
	{
		if (Count < InN)
		{
			Count += 1;
			return true;
		}
		return false;
	}
};

実装内容

・Executeボタンを押すとCounterの値が増える。
・Counterの値がNと同じになると増えなくなる。
・ResetボタンでCounterの値を0に戻せる。
UW_DoN.h


#pragma once

#include "CoreMinimal.h"
#include "Blueprint/UserWidget.h"
#include "DoN.h"
#include "UW_DoN.generated.h"

/**
 * 
 */
UCLASS()
class SAMPLEPROJECT_API UUW_DoN : public UUserWidget
{
	GENERATED_BODY()

protected:
	UPROPERTY(BlueprintReadWrite, meta = (BindWidget))
	class UTextBlock* NTxt;

	UPROPERTY(BlueprintReadWrite, meta = (BindWidget))
	class UTextBlock* CounterTxt;

	UPROPERTY(BlueprintReadWrite, meta = (BindWidget))
	class UButton* ExecuteBtn;

	UPROPERTY(BlueprintReadWrite, meta = (BindWidget))
	class UButton* ResetBtn;

	void NativeConstruct() override;

	UFUNCTION()
	void OnExecuteClick();

	UFUNCTION()
	void OnResetClick();

	UPROPERTY(VisibleAnywhere)
	FDoN DoN;

};

UW_DoN.cpp

#include "UW_DoN.h"
#include <Components/Button.h>
#include <Components/TextBlock.h>

void UUW_DoN::NativeConstruct()
{
	Super::NativeConstruct();

	if (ExecuteBtn && ResetBtn)
	{
		ExecuteBtn->OnClicked.AddDynamic(this, &UUW_DoN::OnExecuteClick);
		ResetBtn->OnClicked.AddDynamic(this, &UUW_DoN::OnResetClick);
	}

	DoN.Reset(7);
	NTxt->SetText(FText::AsNumber(DoN.N));
	CounterTxt->SetText(FText::AsNumber(DoN.Count));	
}

void UUW_DoN::OnExecuteClick()
{
	if (DoN.Execute())
	{
		CounterTxt->SetText(FText::AsNumber(DoN.Count));
	}
}

void UUW_DoN::OnResetClick()
{
	DoN.Reset();
	CounterTxt->SetText(FText::AsNumber(DoN.Count));
}


👇参考動画

UE5 – Blueprints to C++ – The DoOnce Node

Twitterしてます

ブログの更新をお知らせ

コメント

タイトルとURLをコピーしました