質問をすることでしか得られない、回答やアドバイスがある。

15分調べてもわからないことは、質問しよう!

新規登録して質問してみよう
ただいま回答率
85.39%
Unity

Unityは、Unity Technologiesが開発・販売している、IDEを内蔵するゲームエンジンです。主にC#を用いたプログラミングでコンテンツの開発が可能です。

Q&A

解決済

1回答

966閲覧

3つの物体にばねの特性を持たせながら、マウスで操作したいです。

integral2ydx

総合スコア7

Unity

Unityは、Unity Technologiesが開発・販売している、IDEを内蔵するゲームエンジンです。主にC#を用いたプログラミングでコンテンツの開発が可能です。

0グッド

0クリップ

投稿2021/11/01 08:09

イメージ説明

一番左の物体をマウスで動かしたときにほかの物体もばねの特性を持たせて動いてほしいです。

現状だと一番左の物体を動かしたとたんに、残りの物体は落下してしまいます。初めて使うコンポーネントなのでほとんど自分で試せていないです。すいません、、

C#

1コード 2public class NewBehaviourScript : MonoBehaviour 3{ 4 // 追加 5 private Vector3 screenPoint; 6 private Vector3 offset; 7 8 // Start is called before the first frame update 9 void Start() 10 { 11 12 } 13 14 // Update is called once per frame 15 void Update() 16 { 17 18 } 19 20 // 追加 21 void OnMouseDown() 22 { 23 this.screenPoint = Camera.main.WorldToScreenPoint(transform.position); 24 this.offset = transform.position - Camera.main.ScreenToWorldPoint(new Vector3(Input.mousePosition.x, Input.mousePosition.y, screenPoint.z)); 25 } 26 // 追加 27 void OnMouseDrag() 28 { 29 Vector3 currentScreenPoint = new Vector3(Input.mousePosition.x, Input.mousePosition.y, screenPoint.z); 30 Vector3 currentPosition = Camera.main.ScreenToWorldPoint(currentScreenPoint) + this.offset; 31 transform.position = currentPosition; 32 } 33}

気になる質問をクリップする

クリップした質問は、後からいつでもMYページで確認できます。

またクリップした質問に回答があった際、通知やメールを受け取ることができます。

バッドをするには、ログインかつ

こちらの条件を満たす必要があります。

guest

回答1

0

ベストアンサー

Spring Joint 2Dの「Auto Configure Distance」がオンになっていますので、transform.position = currentPosition;に呼応してバネの自然長が更新され、どんどんバネが伸びていっているのかもしれませんね。
試しにそれをオフにしてみてはいかがでしょうか。ただ個人的な意見を申し上げさせていただきますと、あれをオフにして解決するよりも、もっと物理シミュレーションと親和性の高い移動方法をとった方が面倒が少ないんではないかな...という気がします。

「Auto Configure Distance」をオフにするので動作上問題なさそうならかまわないのですが、たとえばもし「ボールにすごく強い力が加わったかのように暴れ回る」みたいな奇妙な挙動をするようでしたら、別案として...

  • 左端のボールのRigidbody 2Dの「Body Type」を「Kinematic」にする。
  • ドラッグ時の移動にMovePositionを使う。

というのを試してみてはいかがでしょう。

lang

1using UnityEngine; 2 3public class NewBehaviourScript : MonoBehaviour 4{ 5 private Vector3 screenPoint; 6 private Vector3 offset; 7 private new Rigidbody2D rigidbody2D; 8 9 void Start() 10 { 11 this.rigidbody2D = this.GetComponent<Rigidbody2D>(); 12 } 13 14 void OnMouseDown() 15 { 16 this.screenPoint = Camera.main.WorldToScreenPoint(transform.position); 17 this.offset = transform.position - Camera.main.ScreenToWorldPoint(new Vector3(Input.mousePosition.x, Input.mousePosition.y, screenPoint.z)); 18 } 19 20 void OnMouseDrag() 21 { 22 Vector3 currentScreenPoint = new Vector3(Input.mousePosition.x, Input.mousePosition.y, screenPoint.z); 23 Vector3 currentPosition = Camera.main.ScreenToWorldPoint(currentScreenPoint) + this.offset; 24 this.rigidbody2D.MovePosition(currentPosition); 25 } 26}

##ドラッグ開始時にバネ運動を開始する例

lang

1using UnityEngine; 2 3public class NewBehaviourScript : MonoBehaviour 4{ 5 // Rigidbody2Dをセットするためのフィールドを追加し、ここに 6 // インスペクター上で残り2つのボールをセットしておく 7 [SerializeField] private Rigidbody2D[] otherBalls; 8 9 private Vector3 screenPoint; 10 private Vector3 offset; 11 private new Rigidbody2D rigidbody2D; 12 13 void Start() 14 { 15 this.rigidbody2D = this.GetComponent<Rigidbody2D>(); 16 17 // Start時点では、他の2つのボールをKinematic状態にしておく 18 foreach (var otherBall in this.otherBalls) 19 { 20 otherBall.bodyType = RigidbodyType2D.Kinematic; 21 } 22 } 23 24 void OnMouseDown() 25 { 26 this.screenPoint = Camera.main.WorldToScreenPoint(transform.position); 27 this.offset = transform.position - Camera.main.ScreenToWorldPoint(new Vector3(Input.mousePosition.x, Input.mousePosition.y, screenPoint.z)); 28 29 // マウスボタンを押し下げたタイミングで、他の2つのボールをDynamic状態に変える 30 foreach (var otherBall in this.otherBalls) 31 { 32 otherBall.bodyType = RigidbodyType2D.Dynamic; 33 } 34 } 35 36 void OnMouseDrag() 37 { 38 Vector3 currentScreenPoint = new Vector3(Input.mousePosition.x, Input.mousePosition.y, screenPoint.z); 39 Vector3 currentPosition = Camera.main.ScreenToWorldPoint(currentScreenPoint) + this.offset; 40 this.rigidbody2D.MovePosition(currentPosition); 41 } 42 43 /* 44 // マウスボタンを離したら再びバネ運動をやめて固定したい場合... 45 void OnMouseUp() 46 { 47 // OnMouseUpで他の2つのボールをKinematic状態に変え、 48 // 速度・角速度もゼロにする 49 foreach (var otherBall in this.otherBalls) 50 { 51 otherBall.bodyType = RigidbodyType2D.Kinematic; 52 otherBall.velocity = Vector2.zero; 53 otherBall.angularVelocity = 0.0f; 54 } 55 } 56 */ 57}

OnMouseUpなしの場合

図1

OnMouseUpありの場合

図2

投稿2021/11/01 10:19

編集2021/11/03 16:39
Bongo

総合スコア10809

バッドをするには、ログインかつ

こちらの条件を満たす必要があります。

integral2ydx

2021/11/02 03:47

遅くなってすいません!返信ありがとうございます 追加のアドバイスもありがとうございます!動きも解消されたのですが、教えてくださったのと私のスクリプトとは何が違うのでしょうか?
Bongo

2021/11/02 18:31

回答中に載せましたコードはtransform.positionの操作で移動させていた部分をMovePositionに変更しただけのものですが、あれは「Rigidbody 2D - Unity マニュアル」(https://docs.unity3d.com/ja/current/Manual/class-Rigidbody2D.html )の「Rigidbody 2D の動作」の節にある... Rigidbody 2D コンポーネントは Transform をオーバーライドし、Rigidbody 2D によって決められた位置/回転へ更新します。Transform コンポーネントを手動で変更することによって Rigidbody 2D をオーバーライドすることもできますが (Unity はすべてのコンポーネントに関するすべてのプロパティーを表示するので)、オブジェクトが互いに通り抜けたり、中に入ったり、予期せぬ動きをしたりするなど、問題の原因となることもあります。 オブジェクトや子のオブジェクトに加えた Collider 2D コンポーネントは暗示的に Rigidbody 2D にアタッチされます。Collider 2D が Rigidbody 2D にアタッチされると、一緒に移動します。Collider 2D は 、Transform やコライダーオフセットを使って直接動かされることは決してありません。代わりに、Rigidbody 2D を動かします。こうすることで最良のパフォーマンスを得、正しく衝突を検出できます。1つの Rigidbody 2D にアタッチする複数の Collider 2D は互いに衝突しません。つまり、1つの合成コライダーとして効率的に動くひとまとまりのコライダーを作ることができます。すべてのコライダーがその Rigidbody 2D と同期して動いたり回転したりします。 ...との解説や、もっと下の方の「Body Type: Kinematic (キネマティック)」の節の... Kinematic__ (キネマティック) Rigidbody 2D はシミュレーションの下で、ただし、とても明確なユーザー制御の下で、動くようにデザインされています。動的な__Rigidbody 2D は重力と力の影響を受けますが、キネマティック Rigidbody 2D はこれらの影響を受けません。このため、キネマティック Rigidbody 2D は 動的な__Rigidbody 2D よりもシステムのリソースに負荷をかけません。キネマティック__ Rigidbody 2D はRigidbody2D.MovePosition または Rigidbody2D.MoveRotation を通して明白に再配置されるようにデザインされています。衝突を検知するには物理クエリを使用し、どこに、どのように Rigidbody 2D を移動するかはスクリプトを使って決定します。 ...といった記述に従ったものです。他にも「ジョイントとラグドールの安定性 - Unity マニュアル」(https://docs.unity3d.com/ja/current/Manual/RagdollStability.html )には... ジョイントで他の Rigidbody コンポーネントに接続されたキネマティックな Rigidbody コンポーネントでは、直接 Transform からアクセスしないでください。それを行うと、PhysX が対応する Rigidbody コンポーネントの内部速度を計算するステップが省かれ、ソルバーが不適切な結果を出します。一般的によく見られる悪い例は、2D プロジェクトで直接 Transform からアクセスし、リグのルートボーンの上の Transform.TransformDirection を変更してキャラクターを反転させることです。代わりに、Rigidbody2D.MovePosition や Rigidbody2D.MoveRotation を使用する方が、ずっと良い結果を得られます。 ...というような注意書きがありました。また「【Unity】 物理演算の基礎 - エフアンダーバー」(https://www.f-sp.com/entry/2019/02/04/175016#%E7%89%A9%E7%90%86%E6%BC%94%E7%AE%97%E3%81%AE%E6%B3%A8%E6%84%8F%E7%82%B9 )の「物理演算の注意点」にもMovePositionを使うべきとのアドバイスが見つかりました。 おそらくUnityの世界のTransformによる位置・姿勢制御と、Rigidbody2Dの裏方で物理シミュレーションを担当しているらしいBox2D(https://box2d.org/ )による位置・姿勢制御を継ぎ合わせる上でのしかたない事情なんじゃないかと思います。
integral2ydx

2021/11/03 05:35

参考資料での説明ありがとうございます!完全には理解できていないのですが、どうやら自分のスプリクトは典型的なよくある間違いをしてるんですねw Bongoさんの要約はわかりやすかったです!! transform.positionは使わないように気を付けます!!
integral2ydx

2021/11/03 07:19

一つ気になる点があるのですが、ゲーム開始時にすでにばねの物理演算が始まってしまうのですが、マウスを動かしたらばねが動き始めるような制御は可能でしょうか?
Bongo

2021/11/03 16:40

他の2つのボールのbodyTypeを必要に応じて切り替えてはいかがでしょうか。 回答文に例を追記しました。「マウスを動かしたら」とおっしゃるのは、「左端のボールのドラッグを開始したら」という解釈でよろしいでしょうか?
integral2ydx

2021/11/04 06:27

追加の質問にも答えてくださりありがとうございます! はいそういうことです!日本語不足ですいません。 質問ばかりですいませんが、どうやったらそんなにスクリプトかけるようになるのでしょうか?やりたいことがあるけど、それをプログラムで書けないのがとてももどかしいです。 自分はまだ一冊入門書をやり終えただけなので、圧倒的な経験不足は承知なのですが、今みたいにわからなくて詰まった場合は、このサイトで質問するというやり方を続けていいのでしょうか?
Bongo

2021/11/04 12:01

私の考えですと、何でもかんでも独力で解決できるようになろうと気負うことはないんじゃないかと思います。さすがにすべてを丸投げというのは非推奨でしょうが、ご質問者さんの場合は向上心をお持ちで好ましいと感じますので、ご自身の知りうる範疇で下調べいただいた上でご質問いただけるかと思います。そういったご質問は本サイトでも好意的に受け取られているように感じますので、過度に遠慮なさらずご質問いただいてけっこうではないでしょうか。 質問という形で問題点をteratail上に公開することで様々な方の意見を聞く機会ができますし、トラブル解決の事例が集積されることで同様のトラブルをお持ちの別の方の助けになるという側面もあるかと思います。 またご質問いただくだけでなく、ご自身の取り組んでる問題と関係ないようなトピックも気分転換のつもりで覗いてみるというのも面白いんじゃないでしょうか。興味の引かれた質問・回答を頭の隅にしまっておけば、別の時に役立つ場面があるかもしれません。 太刀打ちできそうなご質問を見かけましたら、回答に挑戦してみるのもいい刺激になるかと思います。私もちょくちょくあるのですが、これはこうすればいいだろう...と思って回答を始めてみると、実はそれではうまくいかないケースがあって自分の知らなかった機能について調べるハメになる...なんてこともあり、勉強になることも多いと感じます。
integral2ydx

2021/11/05 05:33

そうなんですね。これからもわからなくなったら、遠慮せずに質問していこうと思います! 気分転換に別の分野にもtり組んでみる。とても参考になりました! 親身になって答えてくださりありがとうございました。
integral2ydx

2021/11/05 06:08

一つききわすれていたのですが、ドラッグ時にばね運動を開始する例でother ballを結構使っているのですが、これはボールを増やした場合でも、増やしたものに適用されるのでしょうか?
Bongo

2021/11/05 21:12

はい、ボールの数に応じてインスペクター上のOther Ballsの要素数も増やして、そこにそれらボールをセットしてやればいいようにしたつもりです。 また、今回のコードではボールのRigidbody2Dを操作するだけですので、ジョイントに依存する箇所はないはずです。つまり、ボール同士をつなぐジョイントの種類やつなぎ方は何でもいいはずで、SpringJoint2Dに限らずHingeJoint2DやRelativeJoint2Dを使ったり、枝分かれするようなつなぎ方をすることも可能だろうと思います。 ただし、ボールの追加はあくまでもインスペクター上での手動操作となってしまいますので、たとえばもしゲームの進行に応じてボールが増減するような場合でしたら、otherBallsの管理も自動化するよう改修する必要があるでしょうね。
integral2ydx

2021/11/08 05:58

返信おそくなってすいません! ありがとうございます。何から何までアドバイスしてくださりとても勉強になりました。
integral2ydx

2021/12/15 09:20

すいません、追加で聞きたいのですが、ドラッグ中にすべてのボールをダイナミックでできるようにした場合ってドラッグできなくなりますか? 今Debug.Logで速度を表示させようと思っているのですが、ドラッグするボールは速度が0と表示されてしまうのですが、これは避けられないのでしょうか?
Bongo

2021/12/15 11:52

先ほどちょっと試してみたところ、ドラッグするボールがKinematicだとvelocityがゼロになってしまうみたいですね。 3D用のRigidbodyならキネマティック状態でMovePositionを使えばちゃんと速度を計算してくれたはずなので、てっきりRigidbody2Dでもそうなるものかと思い込んでいたのですが、どうやら勝手が違うようでした。 かといって単純にドラッグするボールをDynamicにしたところで、やはりMovePositionで適切な速度を計算している様子はなく、異常な挙動をしてしまいました。リファレンス(https://docs.unity3d.com/ja/current/ScriptReference/Rigidbody2D.MovePosition.html )にも... Note: MovePosition is intended for use with kinematic rigidbodies. との注意書きがあり、詳細な理由は説明されていないものの、とにかくMovePositionはキネマティックな物体に対して使うべきもののようですね。 しょうがないのでドラッグするボールはKinematicにしておいて、速度は自前で求めるのではいけないでしょうか。たとえばスクリプトに... // 前のフレームでの位置を記録しておくフィールド private Vector2 previousPosition; // 計算された速度 public Vector2 velocity; void FixedUpdate() { // 前のフレームからどれだけ移動したかを求め、それを経過時間で割って速度とする this.velocity = (this.rigidbody2D.position - this.previousPosition) / Time.deltaTime; // その後、次回の更新に備えて現在の位置をpreviousPositionに保存する this.previousPosition = this.rigidbody2D.position; Debug.Log(this.velocity); } みたいな風に記述してみるのはいかがでしょう。
integral2ydx

2021/12/16 06:49

なるほどです。2Dと3Dでは仕様が違うのですね。 教えてくださったスプリクトで表示されました!!すごいです! ちょっと話が変わるのですが、velocity.magnitudeとvelocityの記事を来たのですが、velocity.magnitudeは速さではなくて、長さあのでしょうか??velocity.magnitudeのほうがプラスマイナスとか(x,y)で表示されないので便利に思えるのですが、、
Bongo

2021/12/16 11:59

そうですね。日常会話で速度とか速さとか言う場合は、おっしゃるとおりスピードメーターで表示されるような速さが一般的だと思います。ですので、velocity.magnitudeの方が好都合そうでしたらそうしてしまってかまいません。 velocityは物理学に関する文脈で言うところの「速度」であり、これはベクトル量です(2DならVector2型、3DならVector3型)。そしてその速度ベクトルの長さ...つまりvelocity.magnitudeが「速さ」で、こちらはスカラー量です(float型)。「速度 - Wikipedia」(https://ja.wikipedia.org/wiki/%E9%80%9F%E5%BA%A6 )だとかの記事がご参考になるかもしれません。 物体の動きを計算する上では、向きの情報も持っているvelocityが必要になると思います。変なたとえですみませんが、北へ向かって時速100kmで疾走するトロッコの上から東へ向かって時速100kmでボールを投げたとしたら、ワールド空間上のボールの動きはトロッコの速度と投球の速度の和で表され、北東へ時速141kmで飛んでいくでしょう。 ですが単に動きの速さを表示したいのでしたら、おっしゃるようにvelocityはxとyに分かれていたり、プラスやマイナスの値になって、情報過多なのはもっともだと思います。そういう時にはvelocity.magnitudeの方がわかりやすいでしょうね。目的に応じて使い分けていただくのがいいかと思います。
integral2ydx

2021/12/17 05:41

なるほどです。いわれてみれば高校の物理でそのようなことを習った気がします。velocityが速度、velocity magnitudeが普段使っている速さ、、区別します。 質問ばかりで申し訳ないのですが、ここで求めている速さはthis.rigidbody2Dというようにアタッチしたものだけの(ボール1つだけの)速さなのでしょうか?それともSerializeFieldでアタッチしたものを含めた結果の速さを表しているのでしょうか?
Bongo

2021/12/17 11:11

あのコードの場合は、this.rigidbody2D.positionが前のフレームからどれだけ変化したかを求め、そこから速度を得ていますので、それはthis.rigidbody2Dの速度ということになりますね。ですのでスクリプトをアタッチしたボール1つについてのものになるでしょう。 otherBallsも含めたボール群全体の速度を求めたい場合は、this.rigidbody2DだけでなくotherBallsも計算式に組み込んでやる必要があるはずです。それぞれのボールの平均位置とか、あるいはボールの質量がバラバラなら質量も加味した重心の位置を求めて、それについて同様の方法で速度を計算することになるでしょうかね。
integral2ydx

2021/12/19 07:48

なるほどです。 ものすごく複雑になりそうですね。ちょっとレベルが格段に上がりそうなのでまずは一つでいろいろやってみようと思います、
integral2ydx

2022/01/13 15:30

すいません、追加で速度ではなく、加速度で計算しようとしたら ### Assets\Test.cs(40,14): error CS1061: 'Test' does not contain a definition for 'previousPosition' and no accessible extension method 'previousPosition' accepting a first argument of type 'Test' could be found (are you missing a using directive or an assembly reference?) ### こんな感じでエラーおこるのですが、原因わかったりしますか? // 計算された速度 public Vector2 velocity; float lastVelocity = 0.0f; void FixedUpdate() { // 前のフレームからどれだけ移動したかを求め、それを経過時間で割って速度とする this.velocity = (this.velocity - lastVelocity) / Time.deltaTime; // その後、次回の更新に備えて現在の位置をpreviousPositionに保存する this.previousPosition = this.rigidbody2D.position; Debug.Log(this.velocity); } }
guest

あなたの回答

tips

太字

斜体

打ち消し線

見出し

引用テキストの挿入

コードの挿入

リンクの挿入

リストの挿入

番号リストの挿入

表の挿入

水平線の挿入

プレビュー

15分調べてもわからないことは
teratailで質問しよう!

ただいまの回答率
85.39%

質問をまとめることで
思考を整理して素早く解決

テンプレート機能で
簡単に質問をまとめる

質問する

関連した質問