Unreal Engine 4.25 の C++ でアクターを移動する最低限のコードを書く

UE4.25 で C++ を使ってプログラムを書こうと思ったときに、どうやって書くんだったか思い出すための忘備録です。キャプチャ画面は 4.25 のものですが、4.26 でも同じ手順でできることは確認しました。

# 準備

- Unreal Engine 4.25.4
- Windows 10
- Visual Studio 2019 

空のプロジェクトを選んで、C++ プロジェクトを選択しています。スターターコンテンツは無しにしてます。アプリ名は SimpleCpp としました。

![image.png](https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/266247/be10ee94-7e36-7bc6-848a-b93e85b90555.png)

# やること

レベル中に配置したアクターを上下に往復運動させるプログラムを C++ で書きます。C++のコードは UE のエディタではなく、Visual Studio で基本書きます（VSCode などのエディタで書くこともできます）。

# 手順

- Actor クラスのサブクラスを C++ で作る（UEエディタで）
- Visual Studio などで C++ のクラスのコードを編集する
- C++で作ったクラスのサブクラスを UE のエディタ上で作る
- レベルに配置してビルドする

こんな感じです。

![image.png](https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/266247/a6152d6d-1fda-e4e6-25d6-a381630c6132.png)

この状態から始めます。

## Actor のサブクラスのC++で作る。

![image.png](https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/266247/834d67c2-42ee-f11f-76de-0e6d436a52b2.png)

コンテンツブラウザで右クリックメニューを出し「新規C++クラス」を選びます。

![image.png](https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/266247/b4fff71c-d99b-bd6c-9e12-3878951428b2.png)

注意：4.25 まではコンテンツブラウザで「コンテンツ」のパスが選ばれていてもC++クラスを作成できますが、4.26 から上のように「パスの選択」で「C++クラス」に変更してからでないと、右クリックメニューの中に「新規C++クラス」の選択肢が出ないようです。

![image.png](https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/266247/b1edbcd5-0ba8-1bc8-a2d6-65ba1c3d5a32.png)


「ファイル」のメニューから「新規C++クラス」を選ぶこともできます。この場合は、コンテンツブラウザのパスの選択にかかわらず、C++クラスを作成できるメニューを選べるようです。

![image.png](https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/266247/3beb25de-4bb7-6f96-bd31-3f87c1b5565d.png)

親クラスを選ぶウィンドウが出るので、Actor クラスを選んで「次へ」を押します。

![image.png](https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/266247/207c2125-78b0-b8bf-a9d6-077ff1207af4.png)

クラス名を入力して「クラスを作成」を押します。ここでは名前はデフォルトのまま（MyActor）にしてます。これでC++のクラスファイルが作成されます。

![image.png](https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/266247/9d5186e3-dbd4-6cf8-5511-62ff697fcfe2.png)

作成されたクラスは、コンテンツブラウザの「パスの選択」のアイコンで「C++クラス」を選ぶと、UEエディタ内で確認できます。

![image.png](https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/266247/93e260f9-0302-9189-a561-bd31b5832bb6.png)

MyActor クラスを選んでダブルクリックすると、Visual Studio 上で MyActor.cpp が開かれて編集できます。

![image.png](https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/266247/8c0b2733-0e80-26bb-e03b-914706d1991f.png)


なお、C++プロジェクトを選ぶと Visual Studio が UEのエディタと同時に開きます（デフォルトでは）。MyActor クラスを UE側で開かなくても、クラスを作成すれば Visual Studio のウィンドウ上に自動的に反映されます。

## アクターを動かすコードを C++ で記述する

フレーム毎に呼び出される Tick の中で、アクター（自分自身）のZ座標を変更することで移動を実現しています。 

.h 側は、アクターの初期位置と初期速度（Z軸方向のフレーム毎の移動量）を保持する変数を追加しています。

```MyActor.h
#pragma once

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

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

protected:
	// Called when the game starts or when spawned
	FVector startLocation; // 追加
	float velocity;        // 追加

	virtual void BeginPlay() override;

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

};
```

クラス名が MyActor ではなく、AMyActor になっていますが、間違いではありません。アクターのサブクラスは、C++ のクラスにするときに A が勝手に頭につくようです（UE エディタ上で Actor と表示されるクラスも、C++ では AActor クラスという名前になっています）。一方で、UEのエディタ側では、C++クラス名の先頭の A は表示されません。この仕様については、知っておく必要があります。

```MyActor.cpp
#include "MyActor.h"
#include "Math/UnrealMathUtility.h"

// Sets default values
AMyActor::AMyActor()
{
 	// 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; // これが true でないと Tick は呼び出されない

}

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

        // 初期速度と初期位置の設定をする
	velocity = 1.0f;                           // 追加
	startLocation = this->GetActorLocation();  // 追加
} 

// Called every frame
void AMyActor::Tick(float DeltaTime)
{
	Super::Tick(DeltaTime);
	
        // ここから追加
	FVector location = this->GetActorLocation(); 
	location.Z += velocity; 
	if (location.Z < startLocation.Z || location.Z > startLocation.Z + 500.0f ) {  
		velocity = -velocity;
	}
	this->SetActorLocation(location);
        // ここまで追加
        // 初期位置のZ+500まで上昇したら下降に転じて、0まで下がったらまた上昇させる
}
```

アクターの位置を取得する `GetActorLocation` やアクターの位置を設定する `SetActorLocation` はブループリントと同じような感覚で使えます。基本的に、ブループリントで使える関数はC++でもほぼ同じように使えます。（Timelineのようなマクロは、C++では使えないものもあります）

コードを追加したら、Visual Studio 側でビルド（F6キー）するか、UEのエディタ側で「コンパイル」を押します。エラーが出た場合は修正します。

## C++で作ったクラスのサブクラスを作る

C++のコードを追加したらUEエディタに戻って、MyActor クラスのサブクラス（ブループリントクラス）を作る。

![image.png](https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/266247/d7b478ee-657f-0b18-de62-f18139ce28e1.png)

コンテンツブラウザで右クリックメニューを出し、「ブループリント」から「ブループリントクラス」を選ぶ。

![image.png](https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/266247/3cc03740-d90a-2dbf-74f7-f2cb25958b1b.png)

親クラスを選択するウィンドウでは、下の検索のところでMyActorと入れて、先ほどC++でコードを書いたクラスを見つけて選びます。選んだら「選択」を押します。

![image.png](https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/266247/65b14fc0-5773-45f9-6af3-754a018bda97.png)

作成すると、NewBluprint みたいな名前が自動的につきます。ここでは SubMyActor という名前に変更しています。

![image.png](https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/266247/680d0433-8c71-8020-1c14-797635b3fca1.png)

SubMyActor クラスをダブルクリックすると、上のようなウィンドウが開きます。アクターにはスタティックメッシュがないので、このままではレベルに配置しても何も表示されません。「コンポーネントの追加」でメッシュを割り当てておきます。

![image.png](https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/266247/e4224a92-c78e-9039-1115-9b7b0051fab3.png)

ここでは Cube のメッシュをコンポーネントとして追加してみました。ここで Cube コンポーネントの「トランスフォーム」の「ムーバブル」を選択しておきます（デフォルトでは選択されるはず）。

![image.png](https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/266247/74de0c47-3723-d0b0-952d-f65be09f8b3c.png)

メッシュをアクターに追加すると、レベルエディタ内にアクターの形状が表示されるようになります。アクターをカメラから見える位置に配置します。

![image.png](https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/266247/8907bb3a-d672-7ed0-b85f-ca1d714b33d7.png)

配置したら、一度ビルドしておきます。

なお、C++のクラスのままだと、エディタでレベル内に配置することができないので、便宜上このようにしています。C++側でアクターをスポーンするようなコードを書けば、ブループリントクラスを作らなくてもレベル内に配置することもできます（たぶん）。

# 実行

![image.png](https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/266247/1da651df-3fc3-e810-9d99-bc199b566de9.png)

プレイすると、ここまでの手順に間違いがなければ、配置したCubeが上下に移動するはずです。静止画だけど・・・

# 参考

- [UnrealEngine4 リフレクション(C++とBluePrint連携)まわりの調査](https://qiita.com/YukiMiyatake/items/d45ec2fb0762da2c504e)