【C++】Structure(構造体)
C++でBlueprintを再現すること
BlueprintのStructure(構造体)を使用した処理をC++で再現します。
Structure(構造体)は異なるVariableTypeの変数を1つにまとめられます。
Array(配列)との違いは、Array(配列)は1つのVariableTypeしか持てませんが、Structure(構造体)は異なるVariableTypeの変数を持つことができます。
C++の構造体の作り方について知ることができます。
PrintCalcResultのInputをStructer(構造体)に変更することでより処理が見やすくなります。
C++では参照渡しをConst宣言できるので安全に処理が軽くなります。
編集するActorクラスを作成する
プロジェクトを閉じていたら、プロジェクトを開き、「Chapter_2_Structure」を開きます。
[Tools]メニューから[New C++ Class]を開きます。
親クラスに[Actor]を選択します。
ClassTypeとClass名を設定します。
Property | Value |
---|---|
Class Type | Public |
Name | CPPStructure |
Solution Explorerから今回編集する2つのファイルを開きます。
- CPPStructure.h
- CPPStructure.cpp
開いたファイルを学習する初期状態に修正します。
// Fill out your copyright notice in the Description page of Project Settings.
#pragma once
#include "CoreMinimal.h"
#include "GameFramework/Actor.h"
#include "CPPCalcType.h"
#include "CPPStructure.generated.h"
UCLASS()
class CPP_BP_API ACPPStructure : public AActor
{
GENERATED_BODY()
public:
ACPPStructure();
// Event Dispatcher[OnPrintHello]
DECLARE_DYNAMIC_MULTICAST_DELEGATE(FPrintHelloDelegate);
UPROPERTY(BlueprintAssignable, Category = "CPP_BP")
FPrintHelloDelegate OnPrintHello;
// Custom Event[PrintHello]
UFUNCTION()
void PrintHello();
int32 Sum(int32 A, int32 B);
// Action Mappingsに設定したActionを処理する関数
void PressedActionPrintCalcResult();
protected:
// Called when the game starts or when spawned
virtual void BeginPlay() override;
private:
TArray<FString> Messages = { TEXT("C++ Hello World!"), TEXT("你好 世界!"), TEXT("Bonjour le monde!"), TEXT("Hallo Welt!"), TEXT("こんにちは世界!") };
// 計算結果を出力する関数
void PrintCalcResult(const ECPPCalcType Type, const int32 A, const int32 B, const float PrintDuration);
// PrintString関数のDurationに設定する変数
const float Duration = 10.0f;
// PrintString関数のTextColorに設定する変数
const FLinearColor TextColor = FColor(255, 255, 255);
// 計算用の変数
int32 CalcVarA = 7;
int32 CalcVarB = 3;
// Flow Control用の変数
bool IsPrintHello = false;
int32 TypeIndex = 0;
TArray<ECPPCalcType> CalcTypes = { ECPPCalcType::Add, ECPPCalcType::Subtract, ECPPCalcType::Multiply, ECPPCalcType::Divide };
// Input設定
void SetupInput();
// Input Eventを処理する関数
void PressedH();
};
// Fill out your copyright notice in the Description page of Project Settings.
#include "CPPStructure.h"
#include "Kismet/KismetSystemLibrary.h"
#include "Kismet/GameplayStatics.h"
ACPPStructure::ACPPStructure()
{
// Event Dispathcer[OnPrintHello]にCustom Event[PrintHello]をバインドする
OnPrintHello.AddDynamic(this, &ACPPStructure::PrintHello);
}
int32 ACPPStructure::Sum(int32 A, int32 B)
{
return A + B;
}
// Called when the game starts or when spawned
void ACPPStructure::BeginPlay()
{
SetupInput();
if (IsPrintHello)
{
// Hello World!を出力する処理
PrintHello();
}
else
{
// 計算結果を出力する処理
PressedActionPrintCalcResult();
}
}
void ACPPStructure::PrintCalcResult(const ECPPCalcType Type, const int32 A, const int32 B, const float PrintDuration)
{
switch (Type)
{
case ECPPCalcType::Add:
{
// Add(足し算)の処理
int32 ResultAdd = Sum(CalcVarA, CalcVarB);
FString StrResultAdd = FString::Printf(TEXT("%d"), ResultAdd);
UKismetSystemLibrary::PrintString(
this
, StrResultAdd
, true
, true
, FColor::Red
, Duration
, TEXT("None"));
break;
}
case ECPPCalcType::Subtract:
{
// Subtract(引き算)の処理
int32 ResultSubtract = CalcVarA - CalcVarB;
FString StrResultSubtract = FString::Printf(TEXT("%d"), ResultSubtract);
UKismetSystemLibrary::PrintString(
this
, StrResultSubtract
, true
, true
, FColor::Yellow
, Duration
, TEXT("None"));
break;
}
case ECPPCalcType::Multiply:
{
// Multiply(掛け算)の処理
int32 ResultMultiply = CalcVarA * CalcVarB;
FString StrResultMultiply = FString::Printf(TEXT("%d"), ResultMultiply);
UKismetSystemLibrary::PrintString(
this
, StrResultMultiply
, true
, true
, FColor::Green
, Duration
, TEXT("None"));
break;
}
case ECPPCalcType::Divide:
{
// Divide(割り算)の処理
float ResultDivide = (float)CalcVarA / (float)CalcVarB;
FString StrResultDivide = FString::Printf(TEXT("%f"), ResultDivide);
UKismetSystemLibrary::PrintString(
this
, StrResultDivide
, true
, true
, FColor::Blue
, Duration
, TEXT("None"));
break;
}
}
}
void ACPPStructure::SetupInput()
{
// 入力を有効にする
EnableInput(UGameplayStatics::GetPlayerController(GetWorld(), 0));
// HキーのPressedとReleasedをバインドする
InputComponent->BindKey(EKeys::H, IE_Pressed, this, &ACPPStructure::PressedH);
// ActionMappingsに設定したActionをバインドする
InputComponent->BindAction("ActionPrintCalcResult", IE_Pressed, this, &ACPPStructure::PressedActionPrintCalcResult);
}
void ACPPStructure::PressedH()
{
// Event Dispathcer[OnPrintHello]をコールする
OnPrintHello.Broadcast();
}
void ACPPStructure::PressedActionPrintCalcResult()
{
// 計算結果を出力する処理
PrintCalcResult(CalcTypes[TypeIndex], CalcVarA, CalcVarB, Duration);
TypeIndex++;
TypeIndex = TypeIndex % CalcTypes.Num();
}
void ACPPStructure::PrintHello()
{
bool NotBonjour = true;
int32 HelloIndex = 0;
while (NotBonjour)
{
// 文字列に"Bonjour"が含まれているか
if (Messages[HelloIndex].Contains(TEXT("Bonjour")))
{
// While Loopの条件をfalseに設定する
NotBonjour = false;
}
else
{
// Messagesの値を出力する
UKismetSystemLibrary::PrintString(this, Messages[HelloIndex], true, true, TextColor, Duration, TEXT("None"));
}
// HelloIndexをインクリメント
HelloIndex++;
}
// CompletedをPrintStringで出力する
UKismetSystemLibrary::PrintString(this, TEXT("Completed"), true, true, FColor::Cyan, Duration, TEXT("None"));
}
Structure(構造体)「FCPPCalcInfo」を作成する
Structure(構造体)「FCPPCalcInfo」を作成します。
[Tools]メニューから[New C++ Class]を開きます。
親クラスに[None]を選択します。
ClassTypeとClass名を設定します。
Property | Value |
---|---|
Class Type | Public |
Name | CPPCalcInfo |
「CPPCalcInfo.h」のみ使用するので、「CPPCalcInfo.cpp」は削除します。
「CPPCalcInfo.h」を開きます。
Unreal Engineのc++でStructure(構造体)を宣言する時は以下のように書きます。
// Fill out your copyright notice in the Description page of Project Settings.
#pragma once
#include "CoreMinimal.h"
#include "(構造体名).generated.h"
USTRUCT(BlueprintType)
struct F(構造体名)
{
GENERATED_BODY()
変数宣言
};
BlueprintのStructure(構造体)「FBPCalcInfo」をC++で再現します。
C++で再現すると以下のような書き方になります。
// Fill out your copyright notice in the Description page of Project Settings.
#pragma once
#include "CoreMinimal.h"
#include "CPPCalcType.h"
#include "CPPCalcInfo.generated.h"
USTRUCT(BlueprintType)
struct FCPPCalcInfo
{
GENERATED_BODY()
ECPPCalcType Type = ECPPCalcType::Add;
int32 NumA = 7;
int32 NumB = 3;
};
Function「PrintCalcResultArgStructure」を作成する
引数にStructure(構造体)「FBPCalcInfo」を渡すFunction[PrintCalcResultArgStructure]を作成します。
C++でFunction[PrintCalcResultArgStructure]を宣言します。
Input/Output | VariableName | VariableType |
---|---|---|
Input | CalcInfo | FCPPCalcInfo |
Input | Duration | float |
引数にStructure(構造体)「FCPPCalcInfo」を使用するので、CPPCalcInfo.hをincludeに追加します。
#include "CPPCalcInfo.h" // 追加
private:
// 引数に構造体を使用した計算結果を出力する関数
void PrintCalcResultArgStructure(const FCPPCalcInfo& CalcInfo, const float PrintDuration);
Function[PrintCalcResultArgStructure]のBlueprintの処理です。
Structure(構造体)「FCPPCalcInfo」のメンバー変数にアクセスするには[構造体変数.メンバー変数名]と書きます。
void ACPPStructure::PrintCalcResultArgStructure(const FCPPCalcInfo& CalcInfo, const float PrintDuration)
{
// 構造体変数名.メンバー変数名
CalcInfo.Type
CalcInfo.NumA
CalcInfo.NumB
}
Function[PrintCalcResultArgStructure]の処理を以下のように書きます。
void ACPPStructure::PrintCalcResultArgStructure(const FCPPCalcInfo& CalcInfo, const float PrintDuration)
{
switch (CalcInfo.Type)
{
case ECPPCalcType::Add:
{
// Add(足し算)の処理
// 値渡し
int32 ResultAdd = Sum(CalcInfo.NumA, CalcInfo.NumB);
FString StrResultAdd = FString::Printf(TEXT("%d"), ResultAdd);
UKismetSystemLibrary::PrintString(
this
, StrResultAdd
, true
, true
, FColor::Red
, Duration
, TEXT("None"));
break;
}
case ECPPCalcType::Subtract:
{
// Subtract(引き算)の処理
int32 ResultSubtract = CalcInfo.NumA - CalcInfo.NumB;
FString StrResultSubtract = FString::Printf(TEXT("%d"), ResultSubtract);
UKismetSystemLibrary::PrintString(
this
, StrResultSubtract
, true
, true
, FColor::Yellow
, Duration
, TEXT("None"));
break;
}
case ECPPCalcType::Multiply:
{
// Multiply(掛け算)の処理
int32 ResultMultiply = CalcInfo.NumA * CalcInfo.NumB;
FString StrResultMultiply = FString::Printf(TEXT("%d"), ResultMultiply);
UKismetSystemLibrary::PrintString(
this
, StrResultMultiply
, true
, true
, FColor::Green
, Duration
, TEXT("None"));
break;
}
case ECPPCalcType::Divide:
{
// Divide(割り算)の処理(int > float)
float ResultDivide = (float)CalcInfo.NumA / (float)CalcInfo.NumB;
FString StrResultDivide = FString::Printf(TEXT("%f"), ResultDivide);
UKismetSystemLibrary::PrintString(
this
, StrResultDivide
, true
, true
, FColor::Blue
, Duration
, TEXT("None"));
break;
}
}
}
Function[PrintCalcResultArgStructure]を使用した処理に編集する
Structure(構造体)の配列をBlueprintと同じになるように、C++でStructure(構造体)の配列を宣言します。
C++で構造体を初期化するには以下のように書きます。
// 構造体の初期化
FCPPCalcInfo CalcInfo = {ECPPCalcType::Add, 7, 3};
// 構造体の配列の初期化
TArray<FCPPCalcInfo> CalcInfos = {{ECPPCalcType::Add, 7, 3}, {ECPPCalcType::Subtract, 7, 3}}
「CPPStructure.h」に構造体の配列[CalcInfos]を宣言します。
private:
TArray<FCPPCalcInfo> CalcInfos = { {ECPPCalcType::Add, 7, 3}
, {ECPPCalcType::Subtract, 7, 3}
, {ECPPCalcType::Multiply, 7, 3}
, {ECPPCalcType::Divide, 7, 3}
};
Blueprintの構造体の配列を取得する処理をC++で再現します。
C++で処理を再現するには以下のように書きます。
void ACPPStructure::PressedActionPrintCalcResult()
{
// 構造体を引数に持った計算結果を出力する処理
PrintCalcResultArgStructure(CalcInfos[TypeIndex], Duration);
TypeIndex++;
TypeIndex = TypeIndex % CalcTypes.Num();
}
ソースコードを保存して、Compileを実行します。
「CPPStructure」をViewportにDrag&Dropします。
PrintStringの出力結果が分かりづらくなるので、「BP_Structure」を削除します。
Level Editorの[Play]ボタンをクリックします。
[C]キーをPressするとStructure(構造体)の配列を順番に処理します。
すべて保存
C++側の説明は以上になります。
プロジェクトをすべて保存しましょう。
Visual StudioのSolutionもすべて保存しましょう。
Visual StudioでBuild
LiveCodingを有効にした状態では、Visual StudioでプロジェクトをBuildできないです。
以下のどちらかの対応後にVisual StudioからBuildを実行します。
- LiveCodingを無効にする
- プロジェクトを閉じる
[LiveCodingを無効にする]か[プロジェクトを閉じる]
Visual Studioで Build > Build Solution
参照URL
ソースコードとプロジェクト
ここまでのソースコードとプロジェクトファイルをGitHubからダウンロードできます。
CPPCalcInfo.h
CPPStructure.h
CPPStructure.cpp