学んだこと、試したこと、調べたことをまとめています。
Widget切り替え
C++での切り替え方法が良く分からなかったので、ここはBlueprintを使った。
・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
👇参考動画
👇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));
}
👇参考動画
Twitterしてます
ブログの更新をお知らせ
コメント