見出し画像

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独自のプロパティをどのように使用したり、設定するか宣言します。

プロパティを宣言する時、Property Specifiers を宣言に追加して、Unreal Engine および Unreal Editor の各部で、プロパティがどのように動作するのかを制御することができます。

プロパティ指定子

[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);
}

いいなと思ったら応援しよう!