使用UE:Ver.5.0.3
今回紹介するのはシーソー。
Pluginで簡単セッティング。
なんとPluginは無料で公開中。
物理の上のキャラクターの重力も検出。
床下の物体にもめり込みません。
使わないときは自動でスイッチOFF。
土台はゴールド、床はレザーで豪華に仕上げました。
👇公式の解説動画
👇自作したPluginを使用しています。
KishiroLibrary
Blueprint
Viewport
ArrowComponentは回転の中心に、回転軸の方向を向かせておく。
回転させたいメッシュの子供にしておけば位置がズレなくて良いと思う。
回転の向きはArrowと向かい合った方向から見たとき、
時計回りがプラス、反時計回りがマイナスになる。
Construction Script
Initial Settingはプラグインの関数。
Physical Rotは、プラグインの中で定義した構造体(Physical Rotation)の変数。
Event Graph
サーバーで実行。
力の情報を入れたマップを作成してから回転させる。
回転後、条件を満たしたらTickを止める。
物理の上のキャラクターのための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ごとに座標軸の向きが異なる。
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);
}
}
ポインタ型について
設定の問題かもしれないが、キャラクターが触れるものの物理を有効化させると問題が起きる。
動画内で紹介されていたシーソーは、マルチプレイには向かないと思う。
いろいろと設定をいじってみたが、解決はできなかった。
見た目の演出に使うのであれば問題ないと思うので、積極的に使うようにはしてみたい。
位置の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してます
ブログの更新をお知らせ
コメント