背景
長尺ロープ再現用に計算負荷を減らすことを目的としています。
↓の動画のようにロープの延長・引き戻しを根本から「発生・消滅」するように再現したいと考えております。
※AssetStore『ObiRope』の画像
###今回やろうとしていること
基準となるボール(JyakanBall)の初期位置からの移動量(2m毎)に移動したときに
初期位置からボールをinstantiateで発生させ、 ジョイントで連結させたいと考えてます。
これでロープ形状を作ってみようと思います。
###知りたいこと
instantiateで発生させた物体に、すでに発生させた物体へConfigurableJointで連結させる方法を知りたいです。
現在作成途中のC#
上下の矢印キーで一定速度で前後動させ、初期位置からの移動距離をmagnitude
public GameObject JyakanBall; public GameObject FirstBall ;//最初に出てくるボール。こいつの動きを基準にする。 public Transform FirstPosiBase; // ボール発射初期位置 public float speed = 10; // ボールの速度 private int counter = 0;//ボール採番用 private float Distance ; // Start is called before the first frame update Rigidbody Rb; void Start() { Rb = FirstBall.GetComponent<Rigidbody>() ; Vector3 FirstPosition = FirstPosiBase.transform.position;//ボールの発生する位置の設定 Vector3 Direction = FirstBall.transform.forward;//初期ボール位置のZ軸方向 FirstBall.transform.position = FirstPosition;//初期位置に初期ボールを移動させる } // Update is called once per frame void FixedUpdate() { Vector3 BallPosition = FirstBall.transform.position; Vector3 FirstPosition2 = FirstPosiBase.transform.position; Distance = (FirstPosition2 - BallPosition).magnitude; Debug.Log (Distance) ; if(Input.GetKey(KeyCode.UpArrow)) { Rb.velocity = new Vector3(0,0,speed); } else if(Input.GetKey(KeyCode.DownArrow)) { Rb.velocity = new Vector3(0,0,-speed); } else { Rb.velocity = Vector3.zero; }
追記(2021年7月26日)
距離2m時点では、1個発生するのですが、 4mほど動かした結果、Instantiateが止まらず、ダダ洩れるような状態になってしまいました。
いただいた動画のように一つずつの発生方法について、ご教示いただけると幸いです。
追記 ロープの巻き取りについて
「ホースリールのように」と申し上げましたが、実際は回転部分はダミーで、ただアニメーションで回すだけで、根本部分から今回のロープ発生を考えています。
初歩的な質問でお手数をおかけいたしますが、ご教示いただけると幸いです。
気になる質問をクリップする
クリップした質問は、後からいつでもMYページで確認できます。
またクリップした質問に回答があった際、通知やメールを受け取ることができます。
バッドをするには、ログインかつ
こちらの条件を満たす必要があります。
2021/07/06 09:26
回答2件
0
ベストアンサー
ボールを生成するのはおっしゃるようにInstantiate
を使えばいいでしょうし、不要なボールはDestroy
で削除してやればいいかと思います。
ボールの生成・削除自体よりも、むしろどういう条件で生成するか、削除するかということの方が悩みどころかもしれませんね。
ちょっと思いつきを申し上げさせていただきますと...
- 操作ボールと鎖の末端ボールとの距離がボール設置間隔以上に離れたらボールを追加する。
- 操作ボールと鎖の末端ボールをつなぐ線分が大きく折れ曲がっている場合、末端ボールを削除する。
という規則はどうでしょうか。下記のようなスクリプトを試したところ...
lang
1using UnityEngine; 2 3public class ChainGenerator : MonoBehaviour 4{ 5 public GameObject jyakanBall; // ボールのプレハブ...すでにRigidbodyを持っていると想定 6 public GameObject firstBall; // firstBallはあらかじめシーン上に存在していると想定 7 public Transform firstPosiBase; // ボール発射初期位置 8 public float speed = 10; // ボールの速度 9 public float interval = 2.0f; // ボールを設置する間隔 10 11 private Rigidbody firstRigidbody; 12 private Rigidbody terminalRigidbody; 13 private ConfigurableJoint primaryJoint; 14 private ConfigurableJoint secondaryJoint; 15 16 private void Start() 17 { 18 this.firstRigidbody = this.firstBall.GetComponent<Rigidbody>(); 19 var firstPosition = this.firstPosiBase.transform.position; 20 this.firstBall.transform.position = firstPosition; 21 22 // 初期位置に根元のボールを設置 23 this.terminalRigidbody = Instantiate(this.jyakanBall, firstPosition, Quaternion.identity).GetComponent<Rigidbody>(); 24 25 // ヒエラルキー上で確認しやすくするため、ボールには「プレハブ名 連番」のスタイルの名前を付ける 26 // 根元のボールは0番とする 27 this.terminalRigidbody.name = $"{this.jyakanBall.name} 0"; 28 29 // 根元は初期位置に固定することにする 30 this.terminalRigidbody.gameObject.AddComponent<FixedJoint>(); 31 32 // firstBallはまず根元と接続する 33 this.primaryJoint = this.firstRigidbody.gameObject.AddComponent<ConfigurableJoint>(); 34 this.primaryJoint.connectedBody = this.terminalRigidbody; 35 } 36 37 private void FixedUpdate() 38 { 39 // terminalRigidbodyに対するfirstBallの相対位置をrelativePositionとする 40 var ballPosition = this.firstRigidbody.position; 41 var relativePosition = ballPosition - this.terminalRigidbody.position; 42 43 // その相対位置ベクトルの長さがinterval以上であればボールを追加する 44 while (relativePosition.magnitude >= this.interval) 45 { 46 // terminalRigidbodyからintervalだけ離れた位置に新規ボールを設置する 47 var newTerminalPosition = this.terminalRigidbody.position + Vector3.ClampMagnitude(relativePosition, this.interval); 48 var newTerminalRigidbody = Instantiate(this.jyakanBall, newTerminalPosition, Quaternion.identity).GetComponent<Rigidbody>(); 49 var previousTerminalName = this.terminalRigidbody.name; 50 var previousTerminalIndex = int.Parse(previousTerminalName.Substring(previousTerminalName.LastIndexOf(' ') + 1)); 51 newTerminalRigidbody.name = $"{this.jyakanBall.name} {previousTerminalIndex + 1}"; 52 53 // ジョイントもアタッチし、既存のジョイントをつなぎ替える 54 this.secondaryJoint = newTerminalRigidbody.gameObject.AddComponent<ConfigurableJoint>(); 55 this.secondaryJoint.connectedBody = this.terminalRigidbody; 56 this.secondaryJoint.xMotion = ConfigurableJointMotion.Locked; 57 this.secondaryJoint.yMotion = ConfigurableJointMotion.Locked; 58 this.secondaryJoint.zMotion = ConfigurableJointMotion.Locked; 59 this.primaryJoint.connectedBody = newTerminalRigidbody; 60 61 // 新しいボールを次のterminalRigidbodyとし、relativePositionも更新する 62 this.terminalRigidbody = newTerminalRigidbody; 63 relativePosition = ballPosition - this.terminalRigidbody.position; 64 } 65 66 // secondaryJointが存在するならば、つまり根元とfirstRigidbodyの間に1つ以上ボールが 67 // 存在するならば、さらにrelativePositionがどれだけ折れ曲がっているかを調べる 68 while ((this.secondaryJoint != null) && (Vector3.Dot(relativePosition, this.terminalRigidbody.position - this.secondaryJoint.connectedBody.position) < 0.0f)) 69 { 70 // もし90°を超えて曲がっていれば、鎖を縮めようとしているものと見なし 71 // ジョイントのつなぎ替えを行い、terminalRigidbodyを削除する 72 this.primaryJoint.connectedBody = this.secondaryJoint.connectedBody; 73 Destroy(this.terminalRigidbody.gameObject); 74 75 // primaryJointの接続先を次のterminalRigidbodyとし、secondaryJointとrelativePositionも更新する 76 this.terminalRigidbody = this.primaryJoint.connectedBody; 77 this.secondaryJoint = this.terminalRigidbody.GetComponent<ConfigurableJoint>(); 78 relativePosition = ballPosition - this.terminalRigidbody.position; 79 } 80 81 // キーボード操作でfirstRigidbodyを移動 82 // (ご質問者さんの場合は速度のY成分も含めて書き換えている様子ですが、それだと 83 // 落下の動きがゆったりしてしまい、挙動の実演には向かないかな...と思いまして、 84 // Y成分を残すようにしています) 85 var velocity = this.firstRigidbody.velocity; 86 velocity.z = 0.0f; 87 if (Input.GetKey(KeyCode.UpArrow)) 88 { 89 velocity.z += this.speed; 90 } 91 if (Input.GetKey(KeyCode.DownArrow)) 92 { 93 velocity.z -= this.speed; 94 } 95 this.firstRigidbody.velocity = velocity; 96 } 97}
下図のような動きになりました。
投稿2021/07/24 11:03
総合スコア10807
バッドをするには、ログインかつ
こちらの条件を満たす必要があります。
2021/07/26 12:23
2021/07/26 14:13
2021/07/26 16:01
2021/07/26 23:04
2021/07/27 02:44
2021/07/28 13:00
2021/07/28 15:19 編集
2021/07/29 01:18
0
##根元をボール発生源にする件について
スクリプトを下記のように変更してみました。上矢印キーで先端を引っ張ってボールを引き出し、下矢印キーで根元のリールを巻き取ってボールを回収するイメージで作ってみました。
lang
1using UnityEngine; 2 3public class ChainGenerator2 : MonoBehaviour 4{ 5 public GameObject jyakanBall; // ボールのプレハブ...すでにRigidbodyを持っていると想定 6 public GameObject firstBall; // FirstBallはあらかじめシーン上に存在していると想定 7 public Transform firstPosiBase; // ボール発射初期位置 8 public float speed = 10; // ボールの速度 9 public float interval = 2.0f; // ボールを設置する間隔 10 public float angularLimit = 6.0f; // ジョイントの曲がる角度の上限 11 public float spring = 100.0f; 12 public float damper = 10.0f; 13 14 private Rigidbody rootRigidbody; 15 private Rigidbody firstChildRigidbody; 16 private Rigidbody firstRigidbody; 17 private ConfigurableJoint primaryJoint; 18 private ConfigurableJoint secondaryJoint; 19 private Vector3 connectedAnchor; 20 private SoftJointLimit highLimit; 21 private SoftJointLimit lowLimit; 22 private JointDrive drive; 23 private bool isWinding; 24 25 // primaryJointを巻き取りモードに切り替えるプロパティ 26 private bool IsWinding 27 { 28 get => this.isWinding; 29 set 30 { 31 this.isWinding = value; 32 var joint = this.primaryJoint; 33 if (value) 34 { 35 joint.connectedAnchor = joint.connectedBody.transform.InverseTransformPoint(this.rootRigidbody.position); 36 joint.zMotion = ConfigurableJointMotion.Locked; 37 } 38 else 39 { 40 joint.zMotion = ConfigurableJointMotion.Free; 41 } 42 } 43 } 44 45 private void Start() 46 { 47 this.firstRigidbody = this.firstBall.GetComponent<Rigidbody>(); 48 var firstPosition = this.firstPosiBase.transform.position; //ボールの発生する位置の設定 49 this.firstBall.transform.position = firstPosition; //初期位置に初期ボールを移動させる 50 51 // 初期位置に根元のボールを設置 52 this.rootRigidbody = Instantiate(this.jyakanBall, firstPosition, Quaternion.identity).GetComponent<Rigidbody>(); 53 54 // 「firstChildRigidbody」はrootRigidbodyと直結している直接の子を表す 55 // まずはfirstBallをfirstChildRigidbodyとする 56 this.firstChildRigidbody = this.firstRigidbody; 57 58 // ヒエラルキー上での確認を容易にするため、ボールには「プレハブ名 連番」の形の名前を付ける 59 // rootRigidbodyは特別扱いで連番は付けず(さしあたり「プレハブ名 Root」とする)、firstBallを0番とする 60 this.rootRigidbody.name = $"{this.jyakanBall.name} Root"; 61 this.firstChildRigidbody.name = $"{this.jyakanBall.name} 0"; 62 63 // 根元は初期位置に固定することにする 64 this.rootRigidbody.gameObject.AddComponent<FixedJoint>(); 65 66 // rootRigidbodyとfirstChildRigidbodyを接続する 67 this.connectedAnchor = Vector3.back * this.interval; 68 this.highLimit = new SoftJointLimit {limit = this.angularLimit}; 69 this.lowLimit = this.highLimit; 70 this.lowLimit.limit *= -1.0f; 71 this.drive = new JointDrive 72 { 73 maximumForce = float.MaxValue, 74 positionSpring = this.spring, 75 positionDamper = this.damper 76 }; 77 this.primaryJoint = this.rootRigidbody.gameObject.AddComponent<ConfigurableJoint>(); 78 { 79 var joint = this.primaryJoint; 80 joint.rotationDriveMode = RotationDriveMode.XYAndZ; 81 joint.angularXDrive = joint.angularYZDrive = this.drive; 82 joint.xMotion = joint.yMotion = ConfigurableJointMotion.Locked; 83 joint.zMotion = ConfigurableJointMotion.Free; 84 joint.angularXMotion = joint.angularYMotion = ConfigurableJointMotion.Limited; 85 joint.angularZMotion = ConfigurableJointMotion.Locked; 86 joint.highAngularXLimit = joint.angularYLimit = this.highLimit; 87 joint.lowAngularXLimit = this.lowLimit; 88 joint.anchor = Vector3.zero; 89 joint.autoConfigureConnectedAnchor = false; 90 joint.connectedAnchor = Vector3.zero; 91 joint.connectedBody = this.firstChildRigidbody; 92 } 93 } 94 95 // 下矢印キーを押し下げると巻き取りモード、離すと通常モードとする 96 private void Update() 97 { 98 if (Input.GetKeyDown(KeyCode.DownArrow)) 99 { 100 this.IsWinding = true; 101 } 102 103 if (Input.GetKeyUp(KeyCode.DownArrow)) 104 { 105 this.IsWinding = false; 106 } 107 } 108 109 private void FixedUpdate() 110 { 111 var rootPosition = this.rootRigidbody.position; 112 var rootRotation = this.rootRigidbody.rotation; 113 114 // キーボード操作でfirstRigidbodyを移動 115 var velocity = this.firstRigidbody.velocity; 116 velocity.z = 0.0f; 117 if (this.IsWinding) 118 { 119 // 巻き取りモードの場合、connectedAnchorを縮めることでリールの巻き取りを表現する 120 this.primaryJoint.connectedAnchor = Vector3.MoveTowards( 121 this.primaryJoint.connectedAnchor, 122 Vector3.zero, 123 this.speed * Time.deltaTime); 124 125 // secondaryJointが存在するならば、つまりfirstChildRigidbodyの次に1つ以上ボールが 126 // 存在するならば、さらにconnectedAnchorがほぼゼロまで縮んだかを調べる 127 while ((this.secondaryJoint != null) && (this.primaryJoint.connectedAnchor.sqrMagnitude < 0.01f)) 128 { 129 // connectedAnchorが縮みきっていればジョイントのつなぎ替えを行い、firstChildRigidbodyを削除する 130 var newFirstChildRigidbody = this.secondaryJoint.connectedBody; 131 var newFirstChildPosition = newFirstChildRigidbody.position; 132 var newFirstChildRotation = newFirstChildRigidbody.rotation; 133 DestroyImmediate(this.firstChildRigidbody.gameObject); 134 this.primaryJoint.connectedAnchor = newFirstChildRigidbody.transform.InverseTransformPoint(rootPosition); 135 newFirstChildRigidbody.position = rootPosition; 136 newFirstChildRigidbody.rotation = rootRotation; 137 this.primaryJoint.connectedBody = newFirstChildRigidbody; 138 newFirstChildRigidbody.position = newFirstChildPosition; 139 newFirstChildRigidbody.rotation = newFirstChildRotation; 140 141 // primaryJointの接続先を次のfirstChildRigidbodyとし、secondaryJointも更新する 142 this.firstChildRigidbody = newFirstChildRigidbody; 143 this.secondaryJoint = newFirstChildRigidbody.GetComponent<ConfigurableJoint>(); 144 } 145 } 146 else 147 { 148 if (Input.GetKey(KeyCode.UpArrow)) 149 { 150 velocity.z += this.speed; 151 } 152 153 // firstChildRigidbodyに対するrootRigidbodyの相対位置をrelativePositionとする 154 var ballPosition = this.firstChildRigidbody.position; 155 var ballRotation = this.firstChildRigidbody.rotation; 156 var relativePosition = rootPosition - ballPosition; 157 158 // その相対位置ベクトルの長さがinterval以上であればボールを追加する 159 var distance = relativePosition.magnitude; 160 while (distance >= this.interval) 161 { 162 // firstChildRigidbodyからintervalだけ離れた位置に新規ボールを設置する 163 var newFirstChildPosition = ballPosition + Vector3.ClampMagnitude(relativePosition, this.interval); 164 var newFirstChildRigidbody = Instantiate(this.jyakanBall, rootPosition, rootRotation).GetComponent<Rigidbody>(); 165 var previousFirstChildName = this.firstChildRigidbody.name; 166 var previousFirstChildIndex = int.Parse(previousFirstChildName.Substring(previousFirstChildName.LastIndexOf(' ') + 1)); 167 newFirstChildRigidbody.name = $"{this.jyakanBall.name} {previousFirstChildIndex + 1}"; 168 169 // ジョイントもアタッチし、既存のジョイントをつなぎ替える 170 this.firstChildRigidbody.position = rootPosition; 171 this.firstChildRigidbody.rotation = rootRotation; 172 this.secondaryJoint = newFirstChildRigidbody.gameObject.AddComponent<ConfigurableJoint>(); 173 { 174 var joint = this.secondaryJoint; 175 joint.rotationDriveMode = RotationDriveMode.XYAndZ; 176 joint.angularXDrive = joint.angularYZDrive = this.drive; 177 joint.xMotion = joint.yMotion = joint.zMotion = ConfigurableJointMotion.Locked; 178 joint.angularXMotion = joint.angularYMotion = ConfigurableJointMotion.Limited; 179 joint.angularZMotion = ConfigurableJointMotion.Locked; 180 joint.highAngularXLimit = joint.angularYLimit = this.highLimit; 181 joint.lowAngularXLimit = this.lowLimit; 182 joint.anchor = Vector3.zero; 183 joint.autoConfigureConnectedAnchor = false; 184 joint.connectedAnchor = this.connectedAnchor; 185 joint.connectedBody = this.firstChildRigidbody; 186 } 187 this.primaryJoint.connectedBody = newFirstChildRigidbody; 188 newFirstChildRigidbody.position = newFirstChildPosition; 189 newFirstChildRigidbody.rotation = Quaternion.Lerp(ballRotation, rootRotation, this.interval / distance); 190 this.firstChildRigidbody.position = ballPosition; 191 this.firstChildRigidbody.rotation = ballRotation; 192 193 // 新しいボールを次のfirstChildRigidbodyとし、ballPositionとrelativePositionも更新する 194 this.firstChildRigidbody = newFirstChildRigidbody; 195 ballPosition = this.firstChildRigidbody.position; 196 relativePosition = rootPosition - ballPosition; 197 distance = relativePosition.magnitude; 198 } 199 } 200 201 this.firstRigidbody.velocity = velocity; 202 } 203}
デフォルトの設定値で動かすと下図のようになります。
鎖の硬さについてですが、設定値をもっと硬くしてもさほど挙動は変化しなさそうでした。制限角度を大きくするなどの柔らかくする方向ではそれなりの効果があったのですが...
もっと硬くして、制限角度を0°にしたとしてもけっこうたわんでしまうかと思います。これはもはや物理シミュレーション上の限界なのかもしれません。これ以上硬い棒を表現するとなると、下図のようにボールの間隔を広げてジョイントの数を減らす必要があるかもしれません。
投稿2021/07/28 13:00
総合スコア10807
バッドをするには、ログインかつ
こちらの条件を満たす必要があります。
あなたの回答
tips
太字
斜体
打ち消し線
見出し
引用テキストの挿入
コードの挿入
リンクの挿入
リストの挿入
番号リストの挿入
表の挿入
水平線の挿入
プレビュー
質問の解決につながる回答をしましょう。 サンプルコードなど、より具体的な説明があると質問者の理解の助けになります。 また、読む側のことを考えた、分かりやすい文章を心がけましょう。