前提・実現したいこと
ConfigurableJointでつないだカプセルをAddRelativeで動かした後、ConfigurableJointのLocked(X軸)で固定したいです。
※床に落としても崩れない、強固な固定を行いたいと考えてます。ConfigurableJointのLockが基本的に
ぶつけてもくずれないのでどうしてもこれを使いたいと考えてます。
発生している問題
現在位置・角度を取得してから、ロックをかければできるかなと思ったのですが、
初期位置に戻ってしまいます。
該当のソースコード
以下のコードで実施しましたが、初期位置に戻ってしまいました。
C#
1 //ジョイントロックの検討 2 if(Input.GetKey(KeyCode.V))//原点位置に戻ってしまう・・・ 3 { 4 Vector3 tmp = CapJoint.transform.localPosition; 5 Vector3 RotPosi = CapJoint.transform.localEulerAngles; 6 7 CapJoint.transform.localPosition = new Vector3(tmp.x,tmp.y,tmp.z); 8 CapJoint.transform.localEulerAngles = new Vector3(RotPosi.x,RotPosi.y,RotPosi.z); 9 10 this.configurableJoint = CapJoint.GetComponent<ConfigurableJoint>(); 11 this.configurableJoint.angularXMotion = ConfigurableJointMotion.Locked; 12 13 }
ご迷惑をおかけいたしますが、どなたかご教示いただけると幸いです。
よろしくお願いいたします。
気になる質問をクリップする
クリップした質問は、後からいつでもMYページで確認できます。
またクリップした質問に回答があった際、通知やメールを受け取ることができます。
バッドをするには、ログインかつ
こちらの条件を満たす必要があります。
回答1件
0
ベストアンサー
ご質問者さんがお試しの通り、Locked
状態にすると初期姿勢にロックされてしまうようですね。
下記のようにスペースバーを押すとangularXMotion
をロックするスクリプトを用意し...
C#
1using UnityEngine; 2using UnityEngine.UI; 3 4[RequireComponent(typeof(ConfigurableJoint))] 5public class JointController : MonoBehaviour 6{ 7 [SerializeField] private Text stateText; 8 private ConfigurableJoint joint; 9 10 private void Start() 11 { 12 this.joint = this.GetComponent<ConfigurableJoint>(); 13 } 14 15 private void Update() 16 { 17 if (Input.GetKeyDown(KeyCode.Space)) 18 { 19 this.joint.angularXMotion = ConfigurableJointMotion.Locked; 20 } 21 22 this.stateText.text = this.joint.angularXMotion.ToString(); 23 } 24}
外力でジョイントを屈曲させ、その状態でロックすると姿勢が勢いよく復帰して吹っ飛びました。
なにか初期姿勢をリセットするような機能はないものかと調べてみても結局見つからなかったのですが、下記のように...
C#
1using UnityEngine; 2using UnityEngine.UI; 3 4[RequireComponent(typeof(ConfigurableJoint))] 5public class JointController : MonoBehaviour 6{ 7 [SerializeField] private Text stateText; 8 private ConfigurableJoint joint; 9 10 private void Start() 11 { 12 this.joint = this.GetComponent<ConfigurableJoint>(); 13 } 14 15 private void Update() 16 { 17 if (Input.GetKeyDown(KeyCode.Space)) 18 { 19 this.joint.angularXMotion = ConfigurableJointMotion.Locked; 20 this.joint.swapBodies = !this.joint.swapBodies; 21 this.joint.swapBodies = !this.joint.swapBodies; 22 } 23 24 this.stateText.text = this.joint.angularXMotion.ToString(); 25 } 26}
「swapBodiesを切り替えてすぐ元に戻す」という一見無意味な行為をやったところ、どうやら初期姿勢が屈曲した状態に変わったようでした。
すみませんが、そもそもswapBodies
がどういう役割を持つのかよく分からないです。リファレンスの説明から想像すると「オブジェクトAにジョイントをアタッチしてオブジェクトBと接続した状態でswapBodies
をオンにすると、オブジェクトBにジョイントをアタッチしてオブジェクトAと接続した状態と同じ挙動をする」といった感じでしょうかね?
実際のところは何をやっているのかを追おうとしても、こういった物理シミュレーション関連はほとんどがネイティブコードになっていて(UnityCsReference/Dynamics.bindings.cs at master · Unity-Technologies/UnityCsReference · GitHub)手詰まりになり、結局謎のままでした。まあともかく、この両Rigidbody
の関係を入れ替える過程のどこかに初期姿勢を再設定する部分があるのかもしれません。
##ロック時にリミットを更新する案
実験用のスクリプトを下記のように変更しました。
C#
1using UnityEngine; 2using UnityEngine.UI; 3 4[RequireComponent(typeof(ConfigurableJoint), typeof(Rigidbody))] 5public class JointController : MonoBehaviour 6{ 7 [SerializeField] private Text stateText; 8 [SerializeField] private float torqueMagnitude = 20.0f; 9 private ConfigurableJoint joint; 10 private new Rigidbody rigidbody; 11 private bool isLocked; 12 private Vector3 polarAxis; 13 private Vector3 pole; 14 15 // axisとsecondaryAxisを接続相手の座標系に変換して保存するメソッドを作っておく 16 private void ResetPolarAxis() 17 { 18 this.pole = 19 this.joint.connectedBody.transform.InverseTransformDirection( 20 this.transform.TransformDirection(this.joint.axis)); 21 this.polarAxis = 22 Vector3.ProjectOnPlane( 23 this.joint.connectedBody.transform.InverseTransformDirection( 24 this.transform.TransformDirection(this.joint.secondaryAxis)), 25 this.pole); 26 } 27 28 // また、現在のsecondaryAxisの向きをconnectedBodyの座標系に変換して 29 // polarAxisの向きと比較することで角度の変化を算出するプロパティを用意しておく 30 private float Azimuth => Vector3.SignedAngle( 31 this.polarAxis, 32 Vector3.ProjectOnPlane( 33 this.joint.connectedBody.transform.InverseTransformDirection( 34 this.transform.TransformDirection(this.joint.secondaryAxis)), 35 this.pole), 36 this.pole); 37 38 // そしてロック状態を操作するためのプロパティを作る 39 private bool IsLocked 40 { 41 get => this.isLocked; 42 set 43 { 44 if (value == this.isLocked) 45 { 46 return; 47 } 48 49 this.isLocked = value; 50 if (value) 51 { 52 // まずロック時点のリミットを保存しておき... 53 var oldHighLimit = this.joint.highAngularXLimit; 54 var oldLowLimit = this.joint.lowAngularXLimit; 55 56 // ロック時点の基準方向からの回転角を取得しておく 57 var azimuth = this.Azimuth; 58 59 // そして回転をロック、基準方向を更新し... 60 this.joint.angularXMotion = ConfigurableJointMotion.Locked; 61 this.joint.swapBodies = !this.joint.swapBodies; 62 this.joint.swapBodies = !this.joint.swapBodies; 63 this.ResetPolarAxis(); 64 65 // ロック時点の回転角を使ってリミットを修正する 66 var newHighLimit = oldHighLimit; 67 newHighLimit.limit += azimuth; 68 var newLowLimit = oldLowLimit; 69 newLowLimit.limit += azimuth; 70 this.joint.highAngularXLimit = newHighLimit; 71 this.joint.lowAngularXLimit = newLowLimit; 72 73 // 参考情報としてリミットをコンソールに出力する 74 Debug.Log($"High Limit: {oldHighLimit.limit} -> {newHighLimit.limit}, Low Limit: {oldLowLimit.limit} -> {newLowLimit.limit}"); 75 } 76 else 77 { 78 this.joint.angularXMotion = ConfigurableJointMotion.Limited; 79 } 80 } 81 } 82 83 private void Start() 84 { 85 this.joint = this.GetComponent<ConfigurableJoint>(); 86 this.rigidbody = this.GetComponent<Rigidbody>(); 87 88 // Start時点でResetPolarAxisを実行して、初期基準方向を覚えておく 89 this.ResetPolarAxis(); 90 } 91 92 private void Update() 93 { 94 if (Input.GetKeyDown(KeyCode.Space)) 95 { 96 this.IsLocked = !this.IsLocked; 97 } 98 99 this.stateText.text = this.joint.angularXMotion.ToString(); 100 } 101 102 private void FixedUpdate() 103 { 104 this.rigidbody.AddRelativeTorque(this.joint.axis * (this.torqueMagnitude * Input.GetAxis("Vertical"))); 105 } 106}
動かした様子も撮影してみたものの、この図ではちょっと分かりにくかったかもしれません。すみません...
投稿2020/12/08 21:36
編集2020/12/10 20:57総合スコア10811
あなたの回答
tips
太字
斜体
打ち消し線
見出し
引用テキストの挿入
コードの挿入
リンクの挿入
リストの挿入
番号リストの挿入
表の挿入
水平線の挿入
プレビュー
質問の解決につながる回答をしましょう。 サンプルコードなど、より具体的な説明があると質問者の理解の助けになります。 また、読む側のことを考えた、分かりやすい文章を心がけましょう。
バッドをするには、ログインかつ
こちらの条件を満たす必要があります。
2020/12/10 02:27
2020/12/10 10:53
2020/12/10 19:52
2020/12/12 13:13