【UE4】任意のオブジェクトを周回させる超簡単な方法

ブループリントを使って何かをする記事は沢山あるので、当ブログでは C++ を使った方法(初期化処理の一部でブループリントを使います)について扱います。

Unity で任意のオブジェクトの周りを周回させる方法を以下の記事で扱いましたが、今回は Unreal Engine 4 を使った方法を紹介します。

上記の記事では、数学の計算式を C# のコードに直して、それを使いました。
あらゆる状況に応用が利くので便利なのですが、今回は別の方法でやってみたいと思います。

執筆時に扱った Unreal Engine のソースコードのバージョンは 4.25.4
プラットフォームは Windows 10 (64ビット版) を対象としています。
ビルドに使用したアプリ(IDE)は Microsoft Visual Studio 2017 です。

以降、Unreal Engine 4 を UE4 と略記します。 

どのような仕組みで実現するか?

こういう仕組みができれば、計算式を使わずに実現できそうです。


自転しているオブジェクトがあるとします.

※オブジェクトの形状は問いません。


このオブジェクトに棒をくっつけると…。


オブジェクトの自転に合わせて、くっつけた棒も一緒に回転します。


さらに棒の先にボールをくっつけると、ボールも一緒に回転します。


このボールだけ見えるようにすれば、何かのオブジェクトの周りを回っているように見えるようになります。
棒の長さを調節すれば、自転するオブジェクトからどれくらい離して回転させるか?を調節できます。

思考を具象化する

仕組みはこれ以上ないくらいシンプルです。
これなら、小難しい計算式を使う必要はありません。
このロジックは Unity にも通用します。

オブジェクト(あるいはコンポーネント)の親子関係の仕組みと、相対座標を使えば実現できそうです。

具体的な手順
プロジェクトの新規作成

サードパーソンシューティング、C++ でプロジェクトを作成します。

ブループリントの新規作成

レベルに配置するブループリントを新規作成します。

親クラスは、とりあえず Actor にしておきます。
※親クラスは後で変更します。

コンポーネントにキューブを追加して、コンパイルして、保存します。
※スケールがデフォルトの 1.0 だと大きすぎるので、0.1 にしていますが、スケールはお好みで。

C++ クラスの新規作成

ブループリントの親クラス(C++)を新規作成します。

C++ クラスの親クラスも Actor にします。

ファイル名を TestActor にしていますが、任意です。

C++ のコード入力

新規作成した TestActor に以下のコードをコピペします。
※UE4 エディタを閉じる必要はありません。

TestActor.h

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

#pragma once

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

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

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

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

	// ブループリント側で、このポインタにキューブを設定します。
	UPROPERTY(EditAnywhere, BlueprintReadWrite, Category = "UI")
		class UStaticMeshComponent* StaticMeshComponent;

	//	中心からの距離
	UPROPERTY(EditAnywhere, BlueprintReadWrite, Category = "UI")
		float DistanceFromCenter = 150.0f;

	//	角速度(1秒間に回転する角度)
	UPROPERTY(EditAnywhere, BlueprintReadWrite, Category = "UI")
		FVector RotateSpeed = {90.0f, 120.0f, 360.0f};
};

TestActor.cpp

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

#include "TestActor.h"
#include "Kismet/GameplayStatics.h"
#include "GameFramework/Character.h"

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

	// ぬるぽチェック
	check(this->StaticMeshComponent);
}

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

	//	プレイヤーがいる位置にセット
	ACharacter* c = UGameplayStatics::GetPlayerCharacter(this, 0);
	if (c) { this->SetActorLocation(c->GetActorLocation()); }

	//	変更する角度を設定(自転させる)
	FQuat q = FQuat::MakeFromEuler(this->RotateSpeed * DeltaTime);
	this->AddActorLocalRotation(q);

	//	自転後のキューブの相対位置を再設定
	this->StaticMeshComponent->SetRelativeLocation(FVector(this->DistanceFromCenter, 0.0f, 0.0f));
}

ビルドに成功すると、ホットリロードによって UE4 エディタも更新されます。

コードに関してですが、前述の例で言うと、キューブ(StaticMeshComponent)が棒にくっつけたボール、DistanceFromCenter が棒の長さになります。

ブループリントの親クラスを変更

ブループリントを開き、「クラス設定」→「詳細」→「クラスオプション」→「親クラス」で、親クラスを TestActor に変更します。

ブループリントで初期化処理を追加

ブループリントの BeginPlay に以下の処理を追加します。

追加したら、ブループリントをコンパイルして保存します。

ブループリントをレベルに置く

「コンテンツブラウザ」から「ビュー」にドラッグ&ドロップして、レベルに配置します。
レベル内であれば、配置する位置はどこでも構いません。

プレイして動作確認

Tick() で毎フレーム、プレイヤーキャラクターの位置に移動させているので、プレイヤーキャラクターの周りを周回しているように見えます。
キューブのコリジョンがプレイヤーキャラクターや地形やカメラなど…あらゆるものに干渉するので、キューブのコリジョンは無効にしています。
※コリジョンを無効にする手順は省略しています。

FRotator を使って回転させることもできますが、Pitch(Y軸)が特定の角度になるとジンバルロックを起こすため、FRotator を使わずに回転させています。
オイラー角をすぐにクォータニオンに変換して、クォータニオンを使って回転させます。
ジンバルロックについて知識がないと、FRotator で回転させてドハマリします。
とはいえ、Pitch の回転をしないとか、回転させるとしても限られた範囲内なら、FRotator を使っても良いと思います。

参考にした記事

ジンバルロックやクォータニオンについて知識を深めたい場合は以下の記事が参考になります。

Unity 向けですが、クォータニオンの仕組みや使い方を把握できます。

コメントを残す

メールアドレスが公開されることはありません。 * が付いている欄は必須項目です