気になる質問をクリップする
クリップした質問は、後からいつでもMYページで確認できます。
またクリップした質問に回答があった際、通知やメールを受け取ることができます。
バッドをするには、ログインかつ
こちらの条件を満たす必要があります。
回答2件
0
ベストアンサー
パドルの移動方法はどのようにしていますでしょうか?Rigidbodyの位置をスクリプトから変更する場合、方法が不適切だとうまく力が伝達されないかもしれません。
一案としては、パドルのisKinematicをオンにして、MovePositionで動かす方法があるかと思います。
(参考:[Unity] positionとMovePositionの違いを比べた - 弱火でじっくり)
C#
1using UnityEngine; 2 3[RequireComponent(typeof(Rigidbody))] 4public class Mallet : MonoBehaviour 5{ 6 [Range(0.0f, 50.0f)] public float MaxSpeed = 10.0f; 7 public Vector2 MovableRangeX = new Vector2(float.NegativeInfinity, float.PositiveInfinity); 8 public Vector2 MovableRangeZ = new Vector2(float.NegativeInfinity, float.PositiveInfinity); 9 private Vector3 destination; 10 11 private new Rigidbody rigidbody; 12 private void Start() 13 { 14 this.rigidbody = this.GetComponent<Rigidbody>(); 15 this.rigidbody.isKinematic = true; 16 this.destination = this.rigidbody.position; 17 } 18 19 private void Update() 20 { 21 // パドルの移動先をマウススクリーン座標をXZ平面上に投影した位置に設定 22 // この辺はご質問者さんの設計に応じて変えてみてください 23 this.SetDestination(Input.mousePosition); 24 } 25 26 private void SetDestination(Vector3 screenPoint) 27 { 28 const float dyThreshold = 0.001f; 29 var ray = Camera.main.ScreenPointToRay(screenPoint); 30 var oy = ray.origin.y; 31 var dy = ray.direction.y; 32 if (-dy > dyThreshold) 33 { 34 this.destination = ray.origin - ((oy / dy) * ray.direction); 35 36 // パドルがフィールド外に出られないよう位置を制限 37 this.destination.x = Mathf.Clamp(this.destination.x, this.MovableRangeX.x, this.MovableRangeX.y); 38 this.destination.z = Mathf.Clamp(this.destination.z, this.MovableRangeZ.x, this.MovableRangeZ.y); 39 } 40 } 41 42 43 private void FixedUpdate() 44 { 45 // パドルの移動量が過大にならないように制限 46 var deltaPsition = this.destination - this.rigidbody.position; 47 var clampedDeltaPosition = Vector3.ClampMagnitude(deltaPsition, this.MaxSpeed * Time.fixedDeltaTime); 48 var newPosition = clampedDeltaPosition + this.rigidbody.position; 49 50 // パドルはキネマティックにしておき、MovePositionで位置を変化させる 51 this.rigidbody.MovePosition(newPosition); 52 } 53}
めり込み現象について追記
パックを静かにフィールド隅に押しつけてみたところ、確かにパドルがパック内にめり込んでいきますね。
(確認しやすくするため、パックを大きくしています)
フィールド壁面はStaticなので物理的作用を受けず、パドルもキネマティックなため物理的作用を受けないということになるでしょう。動くことができるのはパックだけという状況で力の釣り合いを解決した結果、上図のようなめり込んだ状態に落ち着いたのだろうと思います。
パックを無理やり壁面に押しつけようとした場合、感覚的にはパドルが押し返されてめり込まないのが自然でしょうね。destination
をめり込まない位置に補正してやる手もあるかもしれませんが、別な案として、パドルの移動方法を変えてみるというのはどうでしょう。
パドルを非キネマティックな通常の剛体に戻し、移動はパドルにdestination
座標へ向かう力をかけることにより行うことにしました(マウスポインタとパドルをダンパー付きの固いバネで繋ぐようなイメージで作ってみました...コード上で記述する代わりに、ジョイントをうまく使って同様の動作をさせることもできそうです)。
パドルが非キネマティックになったので、パックから受けた抗力によってパドルが移動できるようになりました。
C#
1using UnityEngine; 2 3[RequireComponent(typeof(Rigidbody))] 4public class Mallet : MonoBehaviour 5{ 6 public Vector2 MovableRangeX = new Vector2(float.NegativeInfinity, float.PositiveInfinity); 7 public Vector2 MovableRangeZ = new Vector2(float.NegativeInfinity, float.PositiveInfinity); 8 [Range(0.0f, 10000.0f)] public float SpringStiffness = 1000.0f; 9 [Range(0.0f, 10000.0f)] public float VelocityDamper = 100.0f; 10 [Range(0.0f, 10000.0f)] public float DestinationDamper = 10.0f; 11 12 private Vector3 destination; 13 private new Rigidbody rigidbody; 14 15 private void Start() 16 { 17 this.rigidbody = this.GetComponent<Rigidbody>(); 18 this.rigidbody.isKinematic = false; // パドルを非キネマティックに変更 19 this.destination = this.rigidbody.position; 20 } 21 22 private void Update() 23 { 24 this.SetDestination(Input.mousePosition); 25 } 26 27 private void SetDestination(Vector3 screenPoint) 28 { 29 const float dyThreshold = 0.001f; 30 var ray = Camera.main.ScreenPointToRay(screenPoint); 31 var oy = ray.origin.y; 32 var dy = ray.direction.y; 33 if (-dy > dyThreshold) 34 { 35 this.destination = ray.origin - ((oy / dy) * ray.direction); 36 this.destination.x = Mathf.Clamp(this.destination.x, this.MovableRangeX.x, this.MovableRangeX.y); 37 this.destination.z = Mathf.Clamp(this.destination.z, this.MovableRangeZ.x, this.MovableRangeZ.y); 38 } 39 } 40 41 private void FixedUpdate() 42 { 43 // パドルを目標地点(マウス位置)に引きつける力をかける 44 this.rigidbody.AddForce(this.GetSpringForce()); 45 } 46 47 private Vector3 GetSpringForce() 48 { 49 var velocity = this.rigidbody.velocity; 50 var speed = velocity.magnitude; 51 var velocityDirection = speed < 1E-5f ? Vector3.zero : velocity / speed; 52 var relativePosition = this.destination - this.rigidbody.position; 53 var sqrDistance = relativePosition.sqrMagnitude; 54 55 // 目標地点とパドルの距離に比例する引っぱり力...とりあえず「バネ復元力」と呼ぶことにする 56 var springForce = relativePosition * this.SpringStiffness; 57 58 // パドルの速度に比例する抵抗力の大きさ...速度の過大な上昇を防ぐ 59 var velocityDamperForceMagnitude = this.VelocityDamper * speed; 60 61 // 目標地点とパドルの距離の2乗に逆比例する抵抗力の大きさ...目標地点に近づいたら急激なブレーキをかける 62 var destinationDamperForceMagnitude = this.DestinationDamper / sqrDistance; 63 64 // パドルの運動量の大きさ×秒間フレーム数 65 var momentumThreshold = (speed * this.rigidbody.mass) / Time.fixedDeltaTime; 66 67 // 抵抗力の大きさ...位置抵抗と速度抵抗の和 68 // ただしmomentumThresholdを越えないようにし、パドルの運動を完全停止させるのに 69 // 必要な以上の力が加わらないようにしたい(抵抗力によって運動方向が逆向きになってしまう状況を防ぐ) 70 // パドルは速度×質量の運動量を持っており、同量の力積を逆向きに加えれば完全停止する 71 // なので、1フレーム中に加わる力積がそれを越えないようにクランプしてやればいいはず 72 var damperForceMagnitude = Mathf.Min( 73 velocityDamperForceMagnitude + destinationDamperForceMagnitude, 74 momentumThreshold); 75 76 // 最終的な力は目標地点方向へのバネ復元力と速度方向と逆方向への抵抗力の和とする 77 var force = springForce - (damperForceMagnitude * velocityDirection); 78 return force; 79 } 80}
投稿2018/06/10 00:38
編集2018/06/11 18:56総合スコア10807
0
すり抜けは、collision detectionをcontinuousにすればいいです。これで当たり判定が継続的なものになります。また、physics materialで跳ね返りやすくするというのも一つの手です
投稿2018/06/11 09:23
退会済みユーザー
総合スコア0
バッドをするには、ログインかつ
こちらの条件を満たす必要があります。
あなたの回答
tips
太字
斜体
打ち消し線
見出し
引用テキストの挿入
コードの挿入
リンクの挿入
リストの挿入
番号リストの挿入
表の挿入
水平線の挿入
プレビュー
質問の解決につながる回答をしましょう。 サンプルコードなど、より具体的な説明があると質問者の理解の助けになります。 また、読む側のことを考えた、分かりやすい文章を心がけましょう。
バッドをするには、ログインかつ
こちらの条件を満たす必要があります。
2018/06/10 13:20
2018/06/10 21:57
2018/06/11 15:41 編集
2018/06/12 17:09