見出し画像

UE5 C++&BP 03 【C++版】変数を作成して取得・設定する

この記事は「UE5から始めるC++&Blueprint」の原稿としてnoteで書いています。
UnrealEngineの技術書を書く人に取って、どういう行動をしていたか見れるように進捗を書いていくことにしました。
後でまとめて反省しても覚えていないと思いますので、進んだところからどんどん書いていきます。

最終的なC++とBlueprintの比較画像です。
両方とも同じ動作をします。

Blueprint側の記事になります。この記事ではBlueprintの処理をC++で再現します。

それではC++でBlueprintで書いた処理を再現していきましょう。

【C++】変数を作成して取得・設定する

VisualStudioを開いて、CPPSampleActor.cppを表示する

プロジェクトを閉じていたら、プロジェクトを開き、「Chapter_2_4_Variable」を開きます。

ToolsメニューからVisual Studioを開きます。

Solution Explorerから「CPPSampleActor.cpp」をダブルクリックして開きます。

前回書いたPrintString関数の引数をBlueprintと同じように変数化します。
C++では関数の引数がBlueprintのInputピンになります。
関数の引数については、関数の項目で詳しく説明します。

PrintString関数で文字列を出力するための変数を作成する

変数「Message」を作成して、Print StringのIn Stringに接続する内容をC++で実装します。
Event BeginePlayノードに該当するBeginPlay関数を編集します。

void ACPPSampleActor::BeginPlay()
{
	Super::BeginPlay();

	FString Message= "C++ Hello World!";

	// PrintStringノードと同じ処理
	// UKismetSystemLibraryクラスのPrintString関数を呼び出す
	UKismetSystemLibrary::PrintString(this, Message, true, true, FColor::Cyan, 2.f);
}

C++の変数の作成は図のようになります。
プログラミング言語では「変数を作成する」ではなく、「変数を宣言する」と言い方が適切です。

変数の宣言
https://wa3.i-3-i.info/word18069.html

Blueprintプリントでは変数の設定をDetailパネルで編集できます。
Variable Name、Variable Type、Default Valueというラベルが書かれているので親切です。
C++は「文法を理解している」という暗黙の了解で記述することになります。文法を理解すれば大丈夫です。一緒に頑張りましょう。

作成した変数名[Message]をPrint String関数のIn Stringにあたる、左から二番目の引数に変数名[Message]を記入します。
引数は,(カンマ)区切りです。

Blueprintは変数[Message]のGetノードからPrintStringノードの[In String]ピンに接続しました。

ソースコードを編集したので、Compileを行います。
編集したファイルを保存します。
File > Save (編集したファイル)  

Build > Build Solutionか、Level Editorの右下のアイコンでComileを行います。

BlueprintではCompile > 保存でした。
C++は保存されたファイルに対してCompileを行います。

編集したC++のActorクラスをLevelEditorのViewportにDrag&Dropします。
World Outlinerに追加したActorクラス名が表示されることを確認します。

Level Editorの[Play]ボタンをクリックします。

変数「Message」に設定した文字列が表示されました。

【Column】 String型ではなくUnrealEngine独自のFStringクラス

int(整数)型やfloat(浮動小数点)型のVariable TypeにはFが付かないのに、String型にはVariable TypeをFStringとFを最初に付けて宣言します。

int,floatはPrimitive(プリミティブ)型といってUnrealEngine以外のC++でも共通の変数の型です。

https://wa3.i-3-i.info/word15876.html

UnrealEngineのString型
Engine\Source\Runtime\Core\Public\Misc\CString.hで定義されている「FString」クラスを使用します。

F(型名)のVariable TypeはUnrealEngine独自の変数の型です。
UnrealEngine以外でC++を書く際には、FStringが存在しないので気を付けてください。

FStringクラスでは文字列を操作するための便利な関数が用意されています。

変数Durationをヘッダファイルに定義してSetter/Getterを作成してPrintString関数で使用する

次のBlueprintを再現します。
・PrintString関数のDurationピンに変数[Duration]のGetノードを設定します。
・PrintString関数の実行前にSetノードで変数の値を変更します。

ヘッダファイルに変数を宣言する。

変数[Message]はBeginPlay関数内に変数を宣言しました。
今回の変数[Duration]はヘッダファイル[CPPSampleActor.h]に変数を宣言します
SolutionExplorerの「CPPSampleActor.h」を開きます。

CPPSampleActor.h

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

#pragma once

#include "CoreMinimal.h"
#include "GameFramework/Actor.h"
#include "CPPSampleActor.generated.h"

UCLASS()
class CPP_BP_API ACPPSampleActor : public AActor
{
	GENERATED_BODY()
	
public:	
	// Sets default values for this actor's properties
	ACPPSampleActor();

	// PrintString関数のDurationに設定する変数
	float Duration = 10.0f;

protected:
	// Called when the game starts or when spawned
	virtual void BeginPlay() override;

public:	
	// Called every frame
	virtual void Tick(float DeltaTime) override;

};

変数[Duration]を宣言した箇所だけ抽出しました。

Variable Name:Durationa
Variable Type:float
Default Value:10.0f

	// PrintString関数のDurationに設定する変数
	float Duration = 10.0f;

【Column】数値の最後に文字は接尾語
10.0fのfはfloatの接尾語です。[10.0]と書いてもCompileは成功します。

値の終わりに接尾語を付けることで、その値の型を指定できます。
浮動小数点用の接尾語としてFとLがあります。Fはfloat、Lはlong double、省略した場合はdoubleと解釈されます

Cの基本:いま、使っている型を意識しよう

次は処理を書きます。
処理を書く前にBlueprintの処理を確認します。

Solution Explorerから「CPPSampleActor.cpp」をダブルクリックして開き、BeginPlay関数に処理を実装します。

void ACPPSampleActor::BeginPlay()
{
	Super::BeginPlay();

	FString Message = "C++ Hello World!";

	Duration = 3.0f;

	// PrintStringノードと同じ処理
	// UKismetSystemLibraryクラスのPrintString関数を呼び出す
	UKismetSystemLibrary::PrintString(this, Message, true, true, FColor::Cyan, Duration);
}

C++とBlueprintの処理を対応させた図です。

Setノード
Duration = 3.0f;
Getノード
DurationをPrintString関数の引数に記述する

Ctrl + Sでファイルを保存し、Compileを行います。

Level Editorの[Play]ボタンをクリックします。

文字が変数[Duration]に設定した[3.0f](3秒間)表示されます。

変数を定数化(const)して値を変更できなくする(ReadOnly:読み取り専用を再現)

Blueprintで変数の[Blueprint Read Only]を有効にして、読み取り専用にした際にCompileでSetノードがErrorになりました。
C++で読み取り専用の変数を再現します。

CPPSampleActor.h」に宣言したDurationの先頭に「const」を追加します。

private:
	// PrintString関数のDurationに設定する変数
	const float Duration = 10.0f;

const修飾子は変数の型の前に宣言します。

const VariableType VariableName = DefaultValue; 

const 修飾子を変数に設定すると、一度設定したDefault Valueから変更することが出来なくなります。

C++ 言語には、定数を表現するための const 修飾子が用意されています。ここでは const 修飾子のさまざまな使い方について説明します。
const 修飾子を使う目的は、コンパイラによる最適化を促進するためと、プログラムの意味をより明確にすることです。
変数の宣言に const をつけることで、その変数の値が書き換えられないようにできます。

C++の基礎 : const 修飾子

Ctrl+Sでファイルを保存し、[Build]メニューから[Build Solution]を選択してCompileします。

Blueprintの時と同じようにCompileがエラーになります。
[Output]ウィンドウのErrorメッセージをダブルクリックします。
エラー箇所に移動すると、変数[Duration]の値を変更している箇所がエラーと判定されています。

変数[Duration]に値を設定している行を削除します。

Ctrl+Sでファイルを保存し、[Build]メニューから[Build Solution]を選択してCompileします。

今度はCompileが成功しました。

Level Editorの[Play]ボタンをクリックします。

const修飾子を一緒に宣言したことで、変数に設定したDefault Valueが約束されます。値を変更したくない変数にはconst修飾子を宣言することで、読み取り専用の変数として使用することが出来ます。
const修飾子は関数で大活躍します。

VariableTypeを別の型(floatからFString)に変換する

BlueprintでVariable TypeをFloatからStringに変換するノードを使いました。
C++でVariable TypeをFloatからStringに変換するノードを再現します。

Solution Explorerから「CPPSampleActor.cpp」をダブルクリックして開き、BeginPlay関数に処理を実装します。
確認しやすいようにPrintString関数を複数行にしました。

#include "CPPSampleActor.h"
#include "Kismet/KismetSystemLibrary.h"
#include "Kismet/KismetStringLibrary.h" // 追加


void ACPPSampleActor::BeginPlay()
{
	Super::BeginPlay();

	FString Message = "C++ Hello World!";

	// PrintStringノードと同じ処理
	// UKismetSystemLibraryクラスのPrintString関数を呼び出す
	UKismetSystemLibrary::PrintString(
		this
		, UKismetStringLibrary::Conv_FloatToString(Duration) // DurationをfloatからFStringに変換する
		, true
		, true
		, FColor::Cyan
		, Duration);
}

Variable TypeをFloatからStringに変換するノードは、UKismetStringLibraryクラスのConv_FloatToString関数を使用します。

UKismetStringLibrary::Conv_FloatToString(Duration) // DurationをfloatからFStringに変換する

UKismetStringLibraryクラスのConv_FloatToString関数はKismetStringLibrary.hで宣言されているので、KismetStringLibrary.hを使用するために#include文を追加します。

#include "Kismet/KismetStringLibrary.h" // 追加

Ctrl + Sでファイルを保存し、Compileを行います。

Level Editorの[Play]ボタンをクリックします。

変数[Duration]の値が文字列として画面に表示されます。

PrintStringのTextColorを変数化

最後にPrint StringのTextColorを変数化して、PrintString関数のTextColorにGetノードを接続処理をC++で再現します。

PrintStringのTextColorに使用されるVariable TypeはLinearColorです。
C++でVariable Typeを宣言する時は[FLinearColor]になります。
CPPSampleActor.h」に変数[TextColor]を宣言します。

	// PrintString関数のDurationに設定する変数
	const float Duration = 10.0f;

	// PrintString関数のTextColorに設定する変数
	const FLinearColor TextColor = FLinearColor(0.0, 0.66, 1.0);

CPPSampleActor.cpp」のPrintString関数に変数[TextColor]を使用するように記入します。
In Stringには変数[Message]を使用するように戻します。

// Called when the game starts or when spawned
void ACPPSampleActor::BeginPlay()
{
	Super::BeginPlay();

	FString Message = "C++ Hello World!";

	// PrintStringノードと同じ処理
	// UKismetSystemLibraryクラスのPrintString関数を呼び出す
	UKismetSystemLibrary::PrintString(
		this
		, Message // Messageに戻す
		, true
		, true
		, TextColor// Textのカラー情報に変数TextColorを設定
		, Duration);
}

Ctrl + Sでファイルを保存し、Compileを行います。

Level Editorの[Play]ボタンをクリックします。

TextColorが変更されました。

【まとめ】C++とBlueprintの比較画像

Blueprintで実装した処理をC++で再現することが出来ました。
Blueprintを一度実装することで、何をしているのか把握できたおかげで
C++側の実装も理解しやすかったのではないでしょうか。
C++を理解している人はBlueprintの作りを把握できのではないでしょうか。

どちらかを理解していれば置き換え可能です。

まずは簡単なところからひとつひとつ理解していきましょう。

次回は「Componentを追加する」

最終的なソースコード

CPPSampleActor.h


#include "CoreMinimal.h"
#include "GameFramework/Actor.h"
#include "CPPSampleActor.generated.h"

UCLASS()
class CPP_BP_API ACPPSampleActor : public AActor
{
	GENERATED_BODY()
	
public:	
	// Sets default values for this actor's properties
	ACPPSampleActor();

	// PrintString関数のDurationに設定する変数
	const float Duration = 10.0f;

	// PrintString関数のTextColorに設定する変数
	const FLinearColor TextColor = FColor(255, 255, 255);

protected:
	// Called when the game starts or when spawned
	virtual void BeginPlay() override;

public:	
	// Called every frame
	virtual void Tick(float DeltaTime) override;
};

CPPSampleActor.cpp

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


#include "CPPSampleActor.h"
#include "Kismet/KismetSystemLibrary.h"
#include "Kismet/KismetStringLibrary.h" // 追加

// Sets default values
ACPPSampleActor::ACPPSampleActor()
{
 	// 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 ACPPSampleActor::BeginPlay()
{
	Super::BeginPlay();

	FString Message = "C++ Hello World!";

	// PrintStringノードと同じ処理
	// UKismetSystemLibraryクラスのPrintString関数を呼び出す
	UKismetSystemLibrary::PrintString(
		this
		, Message // Messageに戻す
		, true
		, true
		, TextColor  // Textのカラー情報に変数TextColorを設定
		, Duration);
}

// Called every frame
void ACPPSampleActor::Tick(float DeltaTime)
{
	Super::Tick(DeltaTime);

}



この記事が気に入ったらサポートをしてみませんか?