Nexus Lab. Blog

0から始めるUnity物理演算⑦バネで遊ぶ&重心速度不変

f:id:nexusyuumilo:20180128200232g:plain

Milo です。
1/30追記:コードを簡略化しました。
今日はバネを連結して見ました!
慶応大の入試問題でも登場の運動を解説します!
難易度:中級

この記事を書いたひと
インドカレー屋が好き。でも、ナンおかわりできるほどカレーの量多くなくね?


今回は関連記事全部読んでないと理解すんの無理です。でも10分もあれば全部読み終わります。つまり、20分もあれば慶応大の入試問題が解けちゃいます。こう言ったらなんか面白そうじゃないですか?
あと、前編と後編になっているので、ちょっとだけ頑張ってください。

過去の試み

nexusyuumilo.hateblo.jp
バネの実装の基本的な内容をこちらで紹介しています!
関連記事

実際の挙動

まずは尺取り虫とは何かってことですが、2つの物体をバネで繋げると尺取り虫のような動きをすることからそう読んでいるんです。
Unityで実装したので、これをみてください。
youtu.be

あとでまた載せますが、一応イメージだけつかんでください。

コード

コメントを書いておきました。Listを使っているのは、バネで繋げる物体が増えても対応できるようにするためです。
1/30追記:コードがあまりに汚かったので修正し、ListArrayを使用しません。

using System.Collections;
using System.Collections.Generic;
using UnityEngine;

public class SpringController : MonoBehaviour {
	public float equilibriumLength;	//バネの自然長を設定
	public float springConstant;	//バネ係数


	//子オブジェクトについての情報を格納するリスト
	List<GameObject> ConnectedObjectsList = new List<GameObject>();
	List<Rigidbody> RbLists = new List<Rigidbody>();	//他のオブジェクトの質量を取得するためのRigidbody
	List<Transform> ConnectedObjectsTransformList = new List<Transform>();	//他のオブジェクトの位置を取得するためのTransformのリス

	void Awake()
	{
		//全ての子オブジェクトから、Transform、gameObject、RigidBodyを取得する。
		foreach(Transform childObject in transform)
		{
			ConnectedObjectsTransformList.Add(childObject);
			GameObject gameObjectChild = childObject.gameObject;
			ConnectedObjectsList.Add(gameObjectChild);
			RbLists.Add(gameObjectChild.GetComponent<Rigidbody>());

			print(childObject);
		}
	}

	//引数は、位置、自然長、バネ係数
	void AddSpringForce(float el, float r)
	{
		
		for(int i=0; i < ConnectedObjectsList.Count; i++)
		{
			for(int k=0; k < ConnectedObjectsList.Count; k++)
			{
				Vector3 pos1 = transform.TransformPoint(ConnectedObjectsTransformList[i].position);
				Vector3 pos2 = transform.TransformPoint(ConnectedObjectsTransformList[k].position);

				Vector3 diff = pos2 - pos1;
				var elVector = diff.normalized * el;
				var force = r * (diff - elVector);	//自然長の長さを考慮して弾性力を設定
				RbLists[i].AddForce(force);
			}
		}
	}

	void FixedUpdate (){
		//弾性力を加える
		AddSpringForce(equilibriumLength, springConstant);

	}
	
}

Create Emptyした後、そのGameObjectにこのスクリプトをアタッチしてください。
その後、バネを取り付けたい複数の物体を子オブジェクトとして設定してください。
f:id:nexusyuumilo:20180130143052p:plain

あとはInspectorから自然長とバネ係数を設定するだけです。

ボールのRigidbodyで、Use Gravityをfalseにしておき、あとは片方のオブジェクトを縮ませてやれば尺取むし運動が実現できます。

運動を詳しく見ていく。

youtu.be

黄色い玉は2物体の重心位置、赤い玉は黄色い玉の運動を見やすくするためについてます〜。
注目すべき点はただ1つ!

重心位置は等速運動をしている

ですよね?常に同じ速度で前に進んでいます。
全編、後編に渡り、なぜこうなってしまうのかを説明して行きます。

2物体の運動を一瞬で理解するコツ

今までは1物体の運動しか扱いませんでしたが、これからは複数の物体を扱いたい、ですよね?
そんな時のコツ。物体の運動を
1、重心の運動
2、相対運動
の2つに分けます。これで必要十分、つまり完璧です。
物体の運動を一個一個処理するのではとても時間がかかります。だからこのような手法を取ることで、計算の手間も省きましょう。

今回は重心の運動だけ解説します。尺取り虫運動で大事なのはこれだけですww

重心の運動

重心は、すべての物体を1個の物体とみなした時、重力が働く点です。
難しいって?じゃあ「おへそ」だと思ってください。たくさんある物体のヘソ、ど真ん中が重心です。

重心の運動がわかれば「たくさんの物体が色々わちゃわちゃしててうざいけど、全体としてはどんな運動をしてるの?」ということがわかります!
今回の尺取り虫だと、ボールがビヨンビヨンしててウザイけど、全体としては等速運動、ただ前に進んでいるだけでしたね?こういう考え方が重心運動では大事です。マジ、何となくでいい。

重心位置を求める公式があるのですが、物体の数が多いと書くのがめんどいのでww、
2つの物体の重心を求める公式だけ教えますね!

2つの物体の重心位置X

 X= \displaystyle \frac{m_1x_1+m_2x_2}{m_1+m_2}
m_1x_1はそれぞれ物体1の質量と位置、m_2x_2は物体2のそれを示します。

f:id:nexusyuumilo:20180128175020p:plain

この尺取り虫だと、黄色い点が重心ですね。2つのボールの質量は同じなので、まぁ重心はど真ん中にくるわけです。

なんとなくわかってきましたか?
第1回からやってるけど、物体の運動を把握するって、要するに
「ある程度時間が経ったら、どこの位置にいるの?」
ってことだよね。
つまり、重心運動がわかる=重心の位置がわかる⇦そのためには速度を積分しよう⇦速度を出すには加速度を積分しよう
ってな思考回路に至ればいいわけです。
じゃあ重心について運動方程式を立てればいいですよね。

 F=Ma
⚠️注意すべきは、
Fは外力のみ、内力含まない。Mは物体すべての重さ、aは重心の加速度ってことです。
あれ?外力ってなんや?

外力と内力

力には2種類あります。外力と内力です。簡単に説明します。

  • 外力:物体たちに対し、全く関係ない第三者が加える力。
  • 内力:物体たちがお互いに加えあっていて、外には全く影響を及ぼしていない力。内部で完結してる力。

具体例を出しましょう。
ビリヤードがいいな。
ボールが2つあって、片方を棒で突きます。ボール2個の運動を知りたいので、棒は第三者です。
f:id:nexusyuumilo:20180128181215p:plain

第三者が、赤を突きました!この時赤には外力が加わります

f:id:nexusyuumilo:20180128181209p:plain
吹っ飛ばされて

f:id:nexusyuumilo:20180128181203p:plain

赤と青が激突。この時、2つには内力が働きます。赤が青を押すから、青は力を受ける。でもこの時、青も赤を押していますよね?だから、赤も力を受ける。こういう風に、「お互いに及ぼしあっている力」が内力です。

f:id:nexusyuumilo:20180128181206p:plain

もし赤と青の質量がぴったり同じなら、青が赤と同じ速度で吹っ飛んで行き、赤はピタッと静止します。
これは運動量保存則から証明できます。自分でやってみてください。コメントいただければ過程をお見せしても良いのですが、3行で証明終わります。

もうあなたは外力と内力の違いをマスターしました。

話を元に戻す。尺取り虫に、外力は働くか?

尺取り虫に外力は働いていますか?
答えはNO。だって重力が働かないようにUse Gravityをfalseにしてるからね。

f:id:nexusyuumilo:20180128182045p:plain

念のために図を書きました。バネは、伸び縮みによって力の向きが逆になりますが、まぁどのみち内力であることに変わりはない。

つまり重心の運動方程式
F=Ma
F=0であるから
a=0
はい、重心の加速度は0。よって、重心は加速せず常に同じ速度で運動します。

動画では、最初にバネを縮ませました。この時バネでビヨ〜ンと物体が吹っ飛ぶのですが、その後は一切外力を加えていません。
最初についた勢いのまま、重心は進んでいくんですね!

だから最初にどちらかの玉に速度を与えてやれば、
全体としてはずっとその速度で進み続けます!(ただし、Dragは0に設定して Use Gravityもfalseという、外力が一切働かない状態ですが。)

外力なしならわざわざUpdate()関数内で rigidbody.velocity = new Vector3...
と記述しなくても、等速で動いてくれるわけですね〜

まとめ

  • 複数の物体があるときには、運動の様子を重心運動と相対運動に分けるとスッキリする。
  • 重心運動の加速度は、外力によって変化する。内力は全く考えなくて良い!
  • 外力が働かなければ、物体全体は最初にもらった速度で動き続ける

関連記事

以下の記事を全て読んでいるか、高校レベルの力学を習得していることが前提です。
以下の記事を全て読んでいれば、高校なんて行かなくても全部理解できます。

nexusyuumilo.hateblo.jp
nexusyuumilo.hateblo.jp
nexusyuumilo.hateblo.jp