0
0

Delete article

Deleted articles cannot be recovered.

Draft of this article would be also deleted.

Are you sure you want to delete this article?

【UE5】Custom Gravityで一人称キャラクターを惑星に沿って歩かせる

0
Posted at

image.png

背景

UE5 の Custom Gravity を使うと、惑星の表面に立ってそのまま歩き回る実装ができます。
今回は、UE5 の Custom Gravity を使って、惑星中心方向に重力がかかる一人称視点キャラクターを実装したときに、キャラクターの向きが正しく揃わなかったため、自分が行った対処法を共有します。

今回の実装で参考にしたEpic の Custom Gravity チュートリアルです。
https://dev.epicgames.com/community/learning/tutorials/w6l7/unreal-engine-custom-gravity-in-ue-5-4

記事は三人称視点がベースでしたが、これを自分の一人称視点の環境で試したところ、一部正しく動かない状態になりました。

フォーラムも確認したところ、作者自身は First Person テンプレートでは未検証としており、差分によって追加調整が必要になるケースがありそうでした。

原因は特定しきれていないのですが、この記事では、自分の環境ではこの対応でうまくいったという内容をメモとして共有します。

発生した課題

一人称視点では次のような状態になりました。

  • 重力方向に沿って移動できる
  • しかし、キャラクターの向きが惑星表面に正しく揃わない

ezgif.com-optimize (1).gif

このように、途中でキャラクターが宙に浮いてしまいます。

方針

そこで、Character クラスの Tick 内で毎フレームキャラクターの回転を補正することにしました。

そのために、惑星表面に沿った前方向ベクトル Forward を求めます。

ステップは以下です。

  1. 惑星中心方向から重力方向を求める
  2. 重力方向の逆向きからキャラクターの上方向ベクトル Up を作る
  3. カメラの前方向ベクトル CameraForwardUp に垂直なベクトル Right を作る
  4. UpRight に垂直なベクトル Forward を作る
  5. Forward を使ってキャラクターの回転を作る

image.png

実装コード

以下が、最終的に動作した Character クラスの Tick の例です。

void AMyCharacter::Tick(float DeltaTime)
{
	Super::Tick(DeltaTime);

	if (!CurrentPlanet)
	{
		return;
	}

	const FVector PlanetLocation = CurrentPlanet->GetActorLocation();
	const FVector ActorLocation = GetActorLocation();

	// 惑星中心へ向かう重力方向を計算
	const FVector GravityDirection = (PlanetLocation - ActorLocation).GetSafeNormal();
	GetCharacterMovement()->SetGravityDirection(GravityDirection);

	// 重力の逆向き = キャラクターの上方向ベクトル Up を計算
	const FVector UpVector = -GravityDirection;

	// カメラの前方向ベクトル CameraForward を取得
	const FVector CameraForward = GetFirstPersonCameraComponent()->GetForwardVector();

	// Up と CameraForward に垂直なベクトル Right を作る
	FVector RightVector = FVector::CrossProduct(UpVector, CameraForward);

	// Right と Up に垂直なベクトル Forward を作る
	const FVector ForwardVector = FVector::CrossProduct(RightVector, UpVector).GetSafeNormal();

	// Forward(X) と Up(Z) から回転を生成
	const FRotator TargetRotation = FRotationMatrix::MakeFromXZ(ForwardVector, UpVector).Rotator();

	// キャラクターに回転を適用
	SetActorRotation(TargetRotation);
}

各ステップで何をしているか

1. 惑星中心方向から重力方向を求める

const FVector GravityDirection = (PlanetLocation - ActorLocation).GetSafeNormal();
GetCharacterMovement()->SetGravityDirection(GravityDirection);

キャラクター位置から惑星中心へ向かうベクトルを作り、それを重力方向として設定しています。

2. 重力の向きからキャラクターの上方向ベクトル Up を作る

const FVector UpVector = -GravityDirection;

重力は下方向なので、その逆向きがキャラクターの上方向 Upになります。

3. カメラの前方向ベクトルCameraForwardUp に直交するベクトルRightを作る

const FVector CameraForward = GetFirstPersonCameraComponent()->GetForwardVector();

惑星表面に沿ったキャラクターの前方向を求めたいのですが、カメラの向き CameraForward をそのまま使うと問題があります。

カメラは上を向いたり下を向いたりできるため、CameraForward には Up 成分が含まれます。
そのまま回転を作ると、惑星表面に沿わない斜めの前方向になってしまいます。

そこで外積を使って、一度 UpCameraForward の両方に垂直なベクトル Right を作ります。

FVector RightVector = FVector::CrossProduct(UpVector, CameraForward);

つまり、

  • RightUp に垂直

  • RightCameraForward に垂直

になります。

4. UpRight に直交するベクトルForwardを作る

const FVector ForwardVector = FVector::CrossProduct(RightVector, UpVector).GetSafeNormal();

さらに RightUp から、両方に垂直なベクトルを作ります。
これが、惑星表面に沿った前方向ベクトル Forward になります。

この時点で、

  • ForwardUp に垂直

  • ForwardRight に垂直

なので、重力基準の直交座標系が作れます。

5. Forwardをキャラクターの回転にセットする

const FRotator TargetRotation = FRotationMatrix::MakeFromXZ(ForwardVector, UpVector).Rotator();
SetActorRotation(TargetRotation);

UE では通常、

  • X 軸 = Forward

  • Y 軸 = Right

  • Z 軸 = Up

です。

そのため、Forward を X、Up を Z としてRotatorを作ると、
キャラクターの向きを惑星表面に沿わせることができます。

結果

この処理を入れることで、一人称視点でもキャラクターの向きが惑星表面に沿って正しく揃うようになりました。
ezgif.com-optimize (1).gif

おわりに

この記事では、UE の Custom Gravity を使って一人称視点で惑星歩行を実装したときに詰まった点と、その対処法を共有しました。
今回の実装が唯一の正解とは限りませんが、同じところでハマった人の参考になれば嬉しいです。

0
0
0

Register as a new user and use Qiita more conveniently

  1. You get articles that match your needs
  2. You can efficiently read back useful information
  3. You can use dark theme
What you can do with signing up
0
0

Delete article

Deleted articles cannot be recovered.

Draft of this article would be also deleted.

Are you sure you want to delete this article?