Unityで物理-重みで傾く棒の表現-HingeJoint

この記事のUnityのバージョン
Unity 2019.1.0f2

重みで傾く棒の表現

とりあえず重みで棒が傾くようにしたい。
以下のような状況を再現したいです。

それと色々と問題を記述してuGUIで物理をしないようにした理由も記述します。

ジョイントの種類

2Dの場合、以下のように大量のJointがあり、何を使用していいのかと迷います。
Distance Joint 2D
Fixed Joint 2D
Friction Joint 2D
Hinge Joint 2D
Relative Joint 2D
Slider Joint 2D
Spring Joint 2D
Target Joint 2D
Wheel Joint 2D
Wheel Joint 2D

今回は、HingeJoint3Dのほうのマニュアルに書いてある、
”ドアに最適ですが、鎖や振り子などをモデル化するのにも使用できます”
を見て、HingeJoint2Dを使用します。

3D

2D

HingeJointの設定

まず、Hierarchy上に当たり用のhitCubeと棒としてbarを用意します。

hitCubeにはRigidbody2d,BoxCollider2Dをアタッチします。

barにも同じように上記をアタッチします。
bar側は重力の影響を受けさせないよう、Rigidbody2dのGravityScaleはゼロにしてしまいましょう。
ゼロに設定していない場合、後述のAnchorを端に寄せると勝手にバーが下がっていきます。


そしてbarにHingeJoint2Dをアタッチします。

AutoConfigureConnectedAnchorについて

AutoConfigureConnectedAnchorをチェックすると、
AnchorとConnectedAnchorを一緒の位置にしておくことが可能です。

Joint.Anchor
関節の動きを制限させるアンカーのローカル座標

Joint.ConnectedAnchor
位置は、接続された Rigidbody のローカル座標、Rigidbody が接続されていない場合はワールド座標から取得

とマニュアルに書いてあります。

今回は接続するものはありません。
回転させる軸を決めるのがAnchorで、現在の配置位置からの相対座標を設定します。
ConnectedAnchorはlocalPositionを無視してワールド座標での位置へ強制的に配置します。
なので、UnityのGameウィンドウをFreeAspectにして画面サイズを動的にいじると
AutoConfigureConnectedAnchorがonの場合、ConnectedAnchorの位置は変化します。
これは、Canvasが動的にScale変更している影響を受けて配置されるワールド座標が変化しているためです。
逆にOffにした状態のときにGameウィンドウサイズが変わると、思ってもみない位置に出てきます。
同じ位置に出ているものの、Canvasがスケールしてしまっているので
uGUI的には別の位置に出てしまう、ということになります。

親がスケールを持つとややこしいことに

barに親オブジェクトを用意し、親にスケールをかけるとややこしくなります。
X,Yともに同じスケールを変更している場合は、
かけたScale分だけ子に逆のScale(掛けて1倍になるように)をすれば問題ありません。
しかし同じスケールでない場合は問題が起こります。

※子のScaleを1にしておきたい場合
Width,Height,Colliderの値を変更、
Anchorの座標は相対座標のため、修正する必要があります。
AutoConfigureConnectedAnchorがonの場合はそれだけでUI座標を更新してくれますが
offの場合はConnectedAnchorも調整が必要になります。

スケールが違う挙動

barの親のscale Xが2, Y が1だったとします。
子のbarのscale Xを0.5にしてみましょう。

動作していない分には見栄え上問題ありません。
しかし動作させてみると…

縦に横に伸びたり縮んだりします。
これはSpriteRendererなどでも起こりえます。
見る感じ、Scaleをかけるタイミングが物理挙動する場合は違うんでしょうね。
TRSはUnityだと、スケール→回転→移動の順ですが、
回転後にスケールかかってるのかな。回転も表示物は荒ぶる…。
あと当たりをすり抜けているように見えますが、
表示の回転が狂ってるだけで当たりは正しい回転しています。

結論

重みで棒が傾くようにしたい。は結構簡単に出来ました。
しかし、Scaleの挙動を見て、落とし穴にはまらないように別ルートを通るようにしました。

最終的に安易にuGUI上で物理表現しておいて、
奥深い階層に入れてScaleによる挙動変化に戸惑わないよう、
絶対Scale変更しない領域のワールド座標でSpriteRendererで
しよう、という結論に至り実装を修正しました。

次回は別のJointに触れられればと思います。

コメントする

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

このサイトはスパムを低減するために Akismet を使っています。コメントデータの処理方法の詳細はこちらをご覧ください