UE5 C++&BP 04【C++版】Componentを追加する
前回のBlueprintにComponentを追加した内容をC++で再現します。
そもそもComponentの追加ができるのでしょうか?
Blueprintでは分かることがC++になったとたんよく分からなくなります。
C++でBlueprintが作られている限り出来ないことはないはず!
それではC++側の再現を始めます。
Unreal Engine 5から始める C++ & Blueprintの作業進捗とロードマップ公開中
【C++版】Componentを追加する
VisualStudioを開いて、編集するファイルを表示する
プロジェクトを閉じていたら、プロジェクトを開き、
「Chapter_2_5_Component」を開きます。
ToolsからVisual Studioを開きます。
Solution Explorerから今回編集する2つのファイルを開きます。
CPPSampleActor.cpp
CPPSampleActor.h
Blueprintで追加したComponentとComponentの親子構成をC++で再現します。
SceneComponentをRootComponentに設定する
Componentの一番上の階層のことをSceneRootと呼びます。
Actorを親クラスにしたBlueprintには最初RootComponentにSceneComponentが設定されています。
SceneComponentは階層のグループを作成したりする、Transform情報だけ持つコンポーネントです。
C++でRootComponentにSceneComponentを設定する処理を実装します。
「CPPSampleActor.hのpublic」に変数を追加します。
VariableType:USceneComponent*
VariableName:DefaultSceneRoot
USceneComponent*の「*」はポインタです。
「USceneComponentのポインタ型」というのが正式な名称です。
ポインタについては別の機会で説明します。
public:
// Sceneコンポーネント
UPROPERTY(EditAnywhere)
USceneComponent* DefaultSceneRoot;
UPROPERTY(EditAnywhere)
UPROPERTYはプロパティ指定子というUnreal独自のプロパティをどのように使用したり、設定するか宣言します。
[EditAnyWhere]はDetailパネルで値を編集できるようにする設定です。
「CPPSampleActor.cpp」ACPPSampleActor関数 (Constractor)
[SceneComponent:DefaultSceneRoot]を[RootComponent]に設定する処理を実装します。
クラス名::クラス名()はConstructorです。Constructorはクラスを作成する時に呼ばれる関数です。BeginePlay関数より先に呼ばれます。
Componentの追加や設定はConstructorで行います。
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;
// SceneComponentを作成する
DefaultSceneRoot = CreateDefaultSubobject<USceneComponent>(TEXT("SceneComponent"));
// SceneComponentをRootComponentに設定する
RootComponent = DefaultSceneRoot;
}
Ctrl + Sでファイルを保存し、Compileを行います。
C++ではBlueprintのようにEditorで確認することが出来ないので、レベルに配置した「CPPSampleActor」を選択します。
[Derail]パネルでComponentの構成を確認します。
Detailパネルに表示される名称は、VarableName(左)、SubobjectFName(右)、(Inherited)は継承したという意味です。
SubobjectFNameには任意の文字列を設定することが出来ます。
StaticMeshComponentを追加する
次に、[StaticMeshComponent]を追加します。
VariableNameは「StaticMesh」に設定します。
StaticMeshComponentのStaticMeshには「SM_SampleActor」を設定します。
「CPPSampleActor.hのpublic」に変数を追加します。
VariableType:UStaticMeshComponent*
VariableName:StaticMesh
public:
// StaticMesh Component
UPROPERTY(EditAnywhere)
UStaticMeshComponent* StaticMesh;
[StaticMeshComponent StaticMesh]を追加します。
変数[StaticMesh]のStaticMeshプロパティに「SM_SampleActor」を設定します。
変数[StaticMesh]は[SceneComponent DefaultSceneRoot]にアタッチします。
// 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;
// SceneComponentをRootComponentに設定する。
DefaultSceneRoot = CreateDefaultSubobject<USceneComponent>(TEXT("SceneComponent"));
RootComponent = DefaultSceneRoot;
// StaticMeshComponentを作成する
StaticMesh = CreateDefaultSubobject<UStaticMeshComponent>(TEXT("StaticMeshComponent"));
// StaticMeshをLaodしてStaticMeshComponentのStaticMeshに設定する
UStaticMesh* Mesh = LoadObject<UStaticMesh>(NULL, TEXT("/Game/CPP_BP/Meshes/SM_SampleCube"), NULL, LOAD_None, NULL);
StaticMesh->SetStaticMesh(Mesh);
// StaticMeshComponentをRootComponentにAttachする
StaticMesh->SetupAttachment(RootComponent);
}
StaticMeshComponentからSceneComponentのアタッチはSetupAttachment関数で行っています。
(Componentの変数名)->SetupAttachment( (Attachしたい親となるComponentの変数名) );
StaticMeshの読み込み処理はLoadObject関数で行っています。
2番目の引数で[SM_SampleCube]のPath(ファイルまでの場所を表す文字列)をしています。
Pathが分からない時はアセットをマウスオーバーすると、「Path:/Game/CPP_BP/Meshes」とSM_SampleCubeが置かれているフォルダまでの文字列書かれています。
「/Game/CPP_BP/Meshes/SM_SampleCube 」とすることで、「SM_SampleCube」の場所を指定することができます
Ctrl + Sでファイルを保存し、Compileを行います。
Compileを行うと、変数[DefaultSceneRoot]の子として[StaticMesh]が追加されます。
[StaticMesh]プロパティには「SM_SampleCube」が設定されています。
Viewportには「SM_SampleCube」が表示されます。
ArrowComponentを追加する
次に、[ArrowComponent]を追加します。
VariableNameは「Arrow」に設定します。
「Arrow」は位置を移動したので、Locationの設定を変更します。
「CPPSampleActor.h」を編集します。
[ArrowComponent]をC++で宣言する時にはヘッダファイル「ArrowComponent.h」をincludeします。
ArrowComponent.hの親フォルダである[Component]までしかIncludePathが設定されていないので、"Components/ArrowComponent.h"と記述します。
#include "Components/ArrowComponent.h" // 追加
[ArrowComponent]の変数を宣言します。
VariableType:UArrowComponent*
VariableName:Arrow
プロパティ識別子のVisibleAnywhereはプロパティは表示されるが、設定を変更できないようにする設定です。
public:
// Arrow Component
UPROPERTY(VisibleAnywhere)
UArrowComponent* Arrow;
「CPPSampleActor.cpp」ACPPSampleActor関数 (Constractor)を編集します。
ArrowComponentを作成します。
位置を設定します(SetRelativeLocation関数)。
StaticMeshにArrowをアタッチします。
// 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;
// SceneComponentを作成する
DefaultSceneRoot = CreateDefaultSubobject<USceneComponent>(TEXT("SceneComponent"));
// SceneComponentをRootComponentに設定する
RootComponent = DefaultSceneRoot;
// StaticMeshComponentを作成する
StaticMesh = CreateDefaultSubobject<UStaticMeshComponent>(TEXT("StaticMeshComponent"));
// StaticMeshをLaodしてStaticMeshComponentのStaticMeshに設定する
UStaticMesh* Mesh = LoadObject<UStaticMesh>(NULL, TEXT("/Game/CPP_BP/Meshes/SM_SampleCube"), NULL, LOAD_None, NULL);
StaticMesh->SetStaticMesh(Mesh);
// StaticMeshComponentをRootComponentにAttachする
StaticMesh->SetupAttachment(RootComponent);
// ArrowComponentを作成する
Arrow = CreateDefaultSubobject<UArrowComponent>(TEXT("ArrowComponent"));
Arrow->SetRelativeLocation(FVector(30.0f, 0.0f, 0.0f));
Arrow->SetupAttachment(StaticMesh);
}
Ctrl + Sでファイルを保存し、Compileを行います。
変数[Arrow]が変数[StaticMesh]の子として追加されました。
Locationも移動した位置が設定されています。
PointLightComponentを追加する
最後に、[PointLightComponent]を追加します。
VariableNameは「PointLight」に設定します。
[ArrowComponent]と同様に移動した位置をLocationに設定します。
「CPPSampleActor.h」を編集します。
PointLightComponentもArrowComponentと同様にヘッダファイルのincludeを追加します。
#include "Components/PointLightComponent.h" // 追ぷ
[PointLightComponent]の変数を追加します。
VariableType:UPointLightComponent*
VariableName:PointLight
public:
// PointLightComponent Component
UPROPERTY(EditAnywhere)
UPointLightComponent* PointLight;
「CPPSampleActor.cpp」ACPPSampleActor関数 (Constractor)を編集します。
ArrowComponentを作成します。
位置を設定します(SetRelativeLocation関数)。
StaticMeshにArrowをアタッチします。
// 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;
// SceneComponentを作成する
DefaultSceneRoot = CreateDefaultSubobject<USceneComponent>(TEXT("SceneComponent"));
// SceneComponentをRootComponentに設定する
RootComponent = DefaultSceneRoot;
// StaticMeshComponentを作成する
StaticMesh = CreateDefaultSubobject<UStaticMeshComponent>(TEXT("StaticMeshComponent"));
// StaticMeshをLaodしてStaticMeshComponentのStaticMeshに設定する
UStaticMesh* Mesh = LoadObject<UStaticMesh>(NULL, TEXT("/Game/CPP_BP/Meshes/SM_SampleCube"), NULL, LOAD_None, NULL);
StaticMesh->SetStaticMesh(Mesh);
// StaticMeshComponentをRootComponentにAttachする
StaticMesh->SetupAttachment(RootComponent);
// ArrowComponentを作成する
Arrow = CreateDefaultSubobject<UArrowComponent>(TEXT("ArrowComponent"));
// ArrowComponentの位置を設定する
Arrow->SetRelativeLocation(FVector(30.0f, 0.0f, 0.0f));
// ArrowComponentをStaticMeshComponentにAttachする
Arrow->SetupAttachment(StaticMesh);
// PointLightComponentを作成する
PointLight = CreateDefaultSubobject<UPointLightComponent>(TEXT("PointLightComponent"));
// PointLightComponentの位置を設定する
PointLight->SetRelativeLocation(FVector(130.0f, 0.0f, 0.0f));
// PointLightComponentをStaticMeshComponentにAttachする
PointLight->SetupAttachment(StaticMesh);
}
Ctrl + Sでファイルを保存し、Compileを行います。
[PointLight]が[StaticMesh]の子として追加されました。
Locationも移動した位置に設定されています。
ViewportにPointLightが表示されました。
[Play]ボタンをクリックします。
BlueprintとC++同じ構成のComponentを実装した状態です。
当然ながら同じ動きをします。
【まとめ】C++とBlueprintの比較画像
最初はどうやってコンポネントを実装するのか不安でした。
実装してみたら今までで一番アッサリ動いてくれました。
Componentの組み立て方はBlueprintでボタンカチカチ、マウスでDrag&Dropで作る方が簡単ですね。
C++で作る場合は頭の中にBlueprintEditorが無いと難しそうです。
BlueprintでComponentを組み立てて、プロパティの値だけ抽出する。
それから、C++で変更すると良さそうです。
やはり、C++を組もうと思ったら、Blueprintもいじれないといけない。
両方必要なのだと改めて実感しました。
最終的なソースコード
CPPSampleActor.h
// Fill out your copyright notice in the Description page of Project Settings.
#pragma once
#include "CoreMinimal.h"
#include "GameFramework/Actor.h"
#include "Components/ArrowComponent.h" // 追加
#include "Components/PointLightComponent.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();
// Scene Component
UPROPERTY(EditAnywhere)
USceneComponent* DefaultSceneRoot;
// StaticMesh Component
UPROPERTY(EditAnywhere)
UStaticMeshComponent* StaticMesh;
// Arrow Component
UPROPERTY(VisibleAnywhere)
UArrowComponent* Arrow;
// PointLightComponent Component
UPROPERTY(EditAnywhere)
UPointLightComponent* PointLight;
// DurationのGet関数
float GetDuration() { return Duration; }
// TextColorのGet関数
FLinearColor GetTextColor() { return TextColor; }
protected:
// Called when the game starts or when spawned
virtual void BeginPlay() override;
public:
// Called every frame
virtual void Tick(float DeltaTime) override;
private:
// PrintString関数のDurationに設定する変数
const float Duration = 10.0f;
// PrintString関数のTextColorに設定する変数
const FLinearColor TextColor = FColor(255, 255, 255);
};
CPPSampleActor.cpp ACPPSampleActor() (Constructor)
// 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;
// SceneComponentを作成する
DefaultSceneRoot = CreateDefaultSubobject<USceneComponent>(TEXT("SceneComponent"));
// SceneComponentをRootComponentに設定する
RootComponent = DefaultSceneRoot;
// StaticMeshComponentを作成する
StaticMesh = CreateDefaultSubobject<UStaticMeshComponent>(TEXT("StaticMeshComponent"));
// StaticMeshをLaodしてStaticMeshComponentのStaticMeshに設定する
UStaticMesh* Mesh = LoadObject<UStaticMesh>(NULL, TEXT("/Game/CPP_BP/Meshes/SM_SampleCube"), NULL, LOAD_None, NULL);
StaticMesh->SetStaticMesh(Mesh);
// StaticMeshComponentをRootComponentにAttachする
StaticMesh->SetupAttachment(RootComponent);
// ArrowComponentを作成する
Arrow = CreateDefaultSubobject<UArrowComponent>(TEXT("ArrowComponent"));
// ArrowComponentの位置を設定する
Arrow->SetRelativeLocation(FVector(30.0f, 0.0f, 0.0f));
// ArrowComponentをStaticMeshComponentにAttachする
Arrow->SetupAttachment(StaticMesh);
// PointLightComponentを作成する
PointLight = CreateDefaultSubobject<UPointLightComponent>(TEXT("PointLightComponent"));
// PointLightComponentの位置を設定する
PointLight->SetRelativeLocation(FVector(130.0f, 0.0f, 0.0f));
// PointLightComponentをStaticMeshComponentにAttachする
PointLight->SetupAttachment(StaticMesh);
}