UE4でC++を使ってオブジェクトを回してみる

# 概要
Blueprintを使わずC++でオブジェクトを回してみる

# 手順
## 対象アクタの作成
コンテンツブラウザの新規作成からC++クラスを作成します．
![image.png](https://qiita-image-store.s3.amazonaws.com/0/225893/372ef872-6a01-d719-0d58-b0a4486fd81a.png)

親クラスにはActorを選択します．
![image.png](https://qiita-image-store.s3.amazonaws.com/0/225893/e5b3484d-5ae0-e1ac-33c9-ec9e681e254b.png)

適当に分かる名前をつけます．ここではRotateCubeとします．
![image.png](https://qiita-image-store.s3.amazonaws.com/0/225893/21b42946-216e-98d3-d8e0-b60370234d96.png)

立ち上がってきたVisualStuidoなりX codeなりで，`RotateCube.h`と`RotateCube.cpp`を編集していく．
もし立ち上がらなければコンテンツブラウザのC++クラスディレクトリ(実際はプロジェクト名/source以下)内にC++クラスが生成されているので，そこから開ける．

## C++で動作を書く
まずはヘッダファイルの方に利用する変数を宣言しておく．テンプレートは生成されているので，publicで座標格納用と回転角度格納用の変数だけ宣言しておく．

```C++:RotateCube.h
// Fill out your copyright notice in the Description page of Project Settings.

#pragma once

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

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

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

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

	UPROPERTY(EditAnywhere, Category = "Rotation")
	FRotator RotationValue;
};

```
ここで宣言したオブジェクトはこれだけです．

- FRotator RotationValue

FRotatorは，(Pitch, Yaw, Roll)の3つのfloat精度の値を持ち，順にY軸中心，X軸中心，Z軸中心の回転角度を保持できるC++構造体です．XYZじゃないので注意です．本体の定義は`Engine\Source\Runtime\Core\Public\Math\Rotator.h`にあります．
参考：[FRotator](https://api.unrealengine.com/INT/API/Runtime/Core/Math/FRotator/index.html)

そんなに長い実装ではないので，読んでみると動作を把握できます．
なお，C++構造体はデフォルトがpublicアクセシビリティのクラスなので，使い勝手は通常のクラスとほぼ同等です．
参考：[C++ における class と struct の違い](https://qiita.com/pink_bangbi/items/e25302df7f4ba7fa0db4)

また，オブジェクト宣言の1行上で`UPROPERTY`によるエディタからのアクセスの設定を行っています．これはアノテーションなのでセミコロンが不要なことに注意です．
`UPROPERTY`の詳細な説明はしませんが，ここでは以下のようなことを設定しています．

#### EditAnywhere
エディタやブループリントに値を公開し，編集可能にする． 
#### Category = "Rotation"
公開時のカテゴリを設定．任意の文字列を当てられる．

---

次に，`RotateCube.cpp`に移動・回転処理を実装します．

```C++:RotateCube.cpp
// Fill out your copyright notice in the Description page of Project Settings.

#include "RotateCube.h"

// Sets default values
ARotateCube::ARotateCube()
{
 	// 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;
	RotationValue = FRotator(.0f, .0f, .0f);
}

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

// Called every frame
void ARotateCube::Tick(float DeltaTime)
{
	Super::Tick(DeltaTime);
	AddActorLocalRotation(RotationValue*DeltaTime, false, 0, ETeleportType::TeleportPhysics);
}
```

まず，`RotateCube.h`で宣言したRotateValueの値を，コンストラクタ内ですべて`0`に初期化しています．コンストラクタはエンジン上でアクタを設置した時に一度だけ実行されます．

次に，`Tick()`内で`RotateValue`に保存されている角度だけ回転を行う処理を記述します．
ここでは，`AddActorLocalRotation`というメソッドを使って回転を行っています

~~`AddActorLocalRotation`は4つの引数を取るのですが，最初以外僕自身よくわかっていないのでわかりません．どうも他オブジェクトと接触したときの挙動や，回転時の動き方？の設定を与えているようなのですが，違いがわかりませんでした．誰か教えてください．~~

8/10追記．
`AddActorLocalRotation`は，引数に以下の値を取ります．

| 引数名 	| 型 	|
|-------------------	|--------------------	|
| DeltaRotation 	| FRotator or FQuat& 	|
| bSweep 	| bool 	|
| OutSweepHitResult 	| FHitResult* 	|
| Teleport 	| ETeleportType 	|
### DeltaRotation
現在の回転角に加算する角度を渡します．FRotatorとFQuatの2種類のC++構造体インスタンスを受け付けることができます．FQuatを渡した場合はそのまま参照渡しされ，FRotatorを渡した場合は渡した先でFQuatに変換されて処理されます．

### bSweep
移動・回転中にアクタが他のコリジョンと接触した場合，そこで動作を停止するかを指定します．壁にあたったら止まるかどうかということです．

### OutSweepHitResult
bSweepにtrueが渡った場合，ここに渡された接触情報が判定されて動作を決定します．必要ない場合nullptrを渡しておきます．

### Teleport
移動方式を指定します．ETeleportTypeはint8の列挙体で定義されており，NoneとTeleportPhysicsの2種類の値が存在します．Noneに設定した場合，指示されたアクタの移動・回転は高速移動になり，動作には慣性が適用されます．一方TeleportPhysicsを設定した場合は指定値分のテレポートになり，慣性は適用されません．

今回の実装では，`FRotator`である`RotateValue`を変換せず渡す方式にします．ただし，そのまま渡すとゲームを動かすマシンによって時間あたりの回転速度が変わってしまうので，`Tick()`に渡される一つ前のフレームとの差分`DeltaTime`を乗算した値を渡すことにします．~~そして不明な後ろの引数はネットにあったものを参考にしました(許して)．~~今回は他オブジェクトとの接触は考慮せず`Sweep`は`false`,差分はテレポートで問題ないので結果以下のようになります．

```
AddActorLocalRotation(RotationValue*DeltaTime, false, 0, ETeleportType::TeleportPhysics);
```

これで実装は終了です．
エディタ上部のコンパイルボタンを押して正常にコンパイルできることを確認してください．
![image.png](https://qiita-image-store.s3.amazonaws.com/0/225893/4edd2028-f858-fc79-c8de-35f83461fe15.png)


# 設置して動かしてみる

コンテンツブラウザからC++クラスが格納されているディレクトリを開き，実装した`RotateCube`をレベルにドラッグ&ドロップで追加します．
正常に追加されると右上のアウトライナにRotateCubeから生成されたアクタが表示されるので，クリックして詳細を確認します．
すると，詳細内のRotationタブ内から，`UPROPERTY`で公開設定した`RotationValue`の値が編集できるようになっています．
![image.png](https://qiita-image-store.s3.amazonaws.com/0/225893/c05b4bf1-7649-556a-9766-c333ea547846.png)
値はコンストラクタで設定した初期値0になっていると思われますので，任意の値に編集してみます．
![image.png](https://qiita-image-store.s3.amazonaws.com/0/225893/9d59d00a-a4e2-34ae-fe32-c64abe32dd2d.png)

これでアクタは回転するようになりましたが，メッシュが設定されておらず回転しても人間に見えないので，コンポーネントを追加よりキューブを追加してみます．
![image.png](https://qiita-image-store.s3.amazonaws.com/0/225893/22dfa46e-7691-9df2-3454-9e5c2f550505.png)
するとやっとレベル上に立方体が見えるようになりました．
![image.png](https://qiita-image-store.s3.amazonaws.com/0/225893/e4b99852-9a9a-ff17-d9bd-d50a361bb9e7.png)
これは見た目となるメッシュを追加したにすぎないため、他に回したいメッシュがあればそちらを選択すれば無事回ることでしょう。たぶん。

# 実行
位置を調整し，実行してみると回転するはずです．
お疲れ様でした．
![ezgif-5-7996235e4a.gif](https://qiita-image-store.s3.amazonaws.com/0/225893/82ccc828-e6be-70c5-f68a-d3cc7bc7f635.gif)

# 感想
エディタの実装に飛んで見て回るの楽しい