【UQ1】シーソー【BP Only】

使用UE:Ver.5.0.3

Seesaw

今回紹介するのはシーソー。
Pluginで簡単セッティング。
なんとPluginは無料で公開中。
物理の上のキャラクターの重力も検出。
床下の物体にもめり込みません。
使わないときは自動でスイッチOFF。
土台はゴールド、床はレザーで豪華に仕上げました。

👇公式の解説動画

【解説編】アンリアルクエスト-グレイマンからの5つの挑戦状-【落ちる床・シーソー】

👇自作したPluginを使用しています。
KishiroLibrary

Blueprint

Viewport

ArrowComponentは回転の中心に、回転軸の方向を向かせておく。
回転させたいメッシュの子供にしておけば位置がズレなくて良いと思う。
回転の向きはArrowと向かい合った方向から見たとき、
時計回りがプラス、反時計回りがマイナスになる。

Construction Script

Initial Settingはプラグインの関数。
Physical Rotは、プラグインの中で定義した構造体(Physical Rotation)の変数。

Event Graph

サーバーで実行。

力の情報を入れたマップを作成してから回転させる。
回転後、条件を満たしたらTickを止める。

Detect Characterでは、床上のコリジョンからキャラクターの重力情報をとってくる。
Trace Physicsでは、床上にあるSimulate Physicsの物体(これからは単に物理と呼ぶ)の重力情報をとってくる。

キャラクターによって質量を変えられる思うが、今回は単純に一定の質量にした。

物理のみをOverlapして、他をIgnoreするTraceを使用。
Blockだと複数のActorの情報を持ってこれないから注意。
TraceのHalf SizeはActorの回転によって回転しないので、RootのWorld Rotationを作用させた。
回転による影響は消し切れていないので、StartとEnd位置を調整して、SphereTraceにした方が良いかも。

物理の上のキャラクターのためのTrace。

シーソーの床下部分においてあるコリジョン(Stop)によるイベント。
これで跳ね返ることで、床下の物体にめり込まないで済む。
使っているのは両方ともプラグインの関数。

マルチキャストで実行する処理。
Simulate Physicsを適用している物体に大きさ0の力を加えている。
力を加えないと回転運動に取り残され、めりこんだり、空中に浮いたりする。

知識・考察

便利だったノード達

大きさ(VectorLength)
内積(DotProduct)
外積(CrossProduct)

C++
ベクトルの大きさ

Vector.Size()

内積

FVector::DotProduct(VectorA, VectorB)

外積

FVector::CrossProduct(VectorA, VectorB)

GetAxesはRotatorの分解をする。

XはForward、YはRight、ZはUPだと思われる。
GetAxes

void UKismetMathLibrary::GetAxes(FRotator A, FVector& X, FVector& Y, FVector& Z)
{
	FRotationMatrix R(A);
	R.GetScaledAxes(X, Y, Z);
}

GetForwardVector、GetRightVector、GetUPVectorを一気にやったのと同じ働きをした。
GetForwardVector

FVector UKismetMathLibrary::GetForwardVector(FRotator InRot)
{
	return InRot.Vector();
}

GetRightVector

FVector UKismetMathLibrary::GetRightVector(FRotator InRot)
{
	return FRotationMatrix(InRot).GetScaledAxis(EAxis::Y);
}

GetUpVector

FVector UKismetMathLibrary::GetUpVector(FRotator InRot)
{
	return FRotationMatrix(InRot).GetScaledAxis(EAxis::Z);
}

つまり、RotatorをRotationMatrixに変換させるにはFRotationMatrixの引数の中にRotatorを入れればよいことが分かる。
また、GetAxesの中で行っているように、前に変数名(ここではRとしている)をおけば、その変数の中に変換されたRotationMatrixが格納されるということだろう。
また作られた回転行列に対して、GetScaledAxesをすれば、引数に入れられた3つの値に、それぞれForward,Right,UpのRotatorが格納されるということだと思う。
3つ一気に取り出すのではなく、1つずつ取り出したいときはGetScaledAxisをして、引数の中に対応した軸の名前を入れてあげれば良いのだろう。
少し調べただけでも、回転には、Rotator、RotationMatrix、Quatが使われていることが分かった。
オイラー角なども使われているかも。難解。

VectorをRotatorで回転させる。
VectorとRotatorのMultiplyではないから注意。
Rotate Vector Around Axisというノードもあったので、機会があれば使いたい。

RotateVector

FVector UKismetMathLibrary::GreaterGreater_VectorRotator(FVector A, FRotator B)
{
	return B.RotateVector(A);
}	

RotateVectorAroundAxis

FVector  UKismetMathLibrary::RotateAngleAxis(FVector InVect, float AngleDeg, FVector Axis)
{
	return InVect.RotateAngleAxis(AngleDeg, Axis.GetSafeNormal());
}

AngleDegは多分Angle Degreeのこと。
単位は英語を調べた感じだと、ラジアンではなく度だと思う。

角度と軸からRotationをつくることができる。

FRotator UKismetMathLibrary::RotatorFromAxisAndAngle(FVector Axis, float Angle)
{
	FVector SafeAxis = Axis.GetSafeNormal(); // Make sure axis is unit length
	return FQuat(SafeAxis, FMath::DegreesToRadians(Angle)).Rotator();
}

ベクトルが確実に単位ベクトルならば、FQuatの式を使えばよい。
Quaternionを使っていることが分かる。
また、その中では角度はRadianを使っていることが分かる。

Rotatorの変換をまとめる。

RotatorをQuatに変換する。
Quatの積をとる。
Rotatorに戻す。

FRotator UKismetMathLibrary::ComposeRotators(FRotator A, FRotator B)
{
	FQuat AQuat = FQuat(A);
	FQuat BQuat = FQuat(B);

	return FRotator(BQuat*AQuat);
}

staticな関数の中では、はじめの引数であるUObjectにthisは使えない。下の方法が良さそう。

UKismetSystemLibrary::PrintString(GEngine->GetWorld(), FString::Printf(TEXT("%f"), Fulcurm.X), true, true, FColor::Red, 0);

わざわざKismetSystemLibraryをincludeしないといけないし面倒ではある。
C++のPrintStringを他の人がどうやって使っているのか気になる。

ためしたことなど

しばらく悩んだこと。
Set World Rotationは、ComponentのRotationをセットする。(ただし座標軸はLocal。worldの座標軸ではない。)
WorldRotationというのは、親の回転情報を引き継ぐことを示すだけで、回転の座標軸がWorldになるわけではない
問題の例として、シーソーのメッシュをWorld座標におけるY軸で回転させる場合を考える。
軸として使うArrowの向きはY軸方向。軸の方向を用いてメッシュをSetWorldRotationで回転。
しかし変な方向に回転する、ということが起きる。
これはWorld座標とLocal座標のずれが原因にある。
World座標からのLocal座標のずれは、World座標におけるActorの回転が影響している。
これをLocal座標にとって正しくするには、ActorのWorldRotationの逆行列をArrowComponentに作用させればよい。

Actorを回転させると、座標軸も回転する。
回転する前の座標軸をWorld座標軸、回転させた後の座標軸をLocal座標軸とここでは呼ぶ。
World座標軸はLevelにおいてWorldを指定したときにあらわれる座標軸。
Local座標軸はLevelにおいてLocalを指定したときにあらわれる座標軸、またはBlueprintのViewport上でRootを選んだときの座標軸と考えても良い。
LevelにおいてWorld座標ならば、全てのActorの座標軸が同じ方向を向いていて、Local座標ならばActorごとに座標軸の向きが異なる。

Local座標
World座標

MapにおけるAddではKeyが同じ場合は、後にAddしたものが上書き。
Findと相性が良い。
Plugin(KishiroLibrary)におけるPhysical Rotation Structの関数Add Force Mapにおいて使用した。
Findによってみつけたものは、ポインタ型の値として取り出される。
その値は変数の前に*を付けることで通常変数に戻せるのだと思う。

AddForceMap

void UKishiroLibraryBPLibrary::AddForceMap(FVector StartPoint, FVector Force, FPhysicalRotationStruct& Struct)
{
	const FVector* ForcePtr = Struct.ForceMap.Find(StartPoint);
	if (ForcePtr)
	{
		Struct.ForceMap.Add(StartPoint, Force + *ForcePtr);
	}
	else
	{
		Struct.ForceMap.Add(StartPoint, Force);
	}
}

ポインタ型について

ポインタ型変数とは - Qiita
ポインタ型とはメモリー上のアドレスを記憶する変数の型のことただしポインタ型は派生型といって単独では存在できずInt型へのポインタ型、String型へのポイント型と言ったように他の型と合わせて作ら…

設定の問題かもしれないが、キャラクターが触れるものの物理を有効化させると問題が起きる。
動画内で紹介されていたシーソーは、マルチプレイには向かないと思う。
いろいろと設定をいじってみたが、解決はできなかった。
見た目の演出に使うのであれば問題ないと思うので、積極的に使うようにはしてみたい。
位置のReplicate Movementも、あまり効果がない。

staticの関数では多分使えない。

解説動画内の情報

キーボードのPause/Breakキー
もしくはShift F1でカーソルを出して、一時停止をクリック。

F8キー

Simulate Physicsをtrueにすると親子関係が崩れる。
Simulate Physicsをfalseに戻し、Attach Component to Componentをすると元に戻すことができる。
Actorの親からはずれたComponentの親はWorldになる。

Relativeな移動をすると、World原点を中心とした移動になってしまうので注意。

Delete Unused Variables

toggledebugcamera

予測変換には出てこないけど、実行できる。
Traceとばして、Traceの当たったところにあるActorのこと調べている。
ejectのように操作キャラクターから離れられる。
ejectと違って、再生モードがselected Viewportじゃなくても大丈夫。

Fov 画角を変えることができるらしいができなかった。少なくともテンキーの±では動くスピードがかわるだけ。
Fならフリーズできたが、Yではフリーズできなかった。

stat fps

FPS(Frames per second)を表示。
つけるのも消すのも同じコマンド。

show collision

コリジョンを見れる。これは別動画で紹介されてたもの。

Twitterしてます

ブログの更新をお知らせ

コメント

タイトルとURLをコピーしました