スーパーマリオオデッセイのニュードンクシティでは、縄跳びのミニゲームが遊べます。こんな感じで物理挙動に従って動く縄をUnityで作る方法をまとめました。
今回作った縄跳びアプリケーションはこんな感じになりました。
この記事では、縄を物理挙動に従ってシミュレーションする方法にフォーカスして説明します。キャラクタをジャンプさせる方法などは次の記事を参考にしてみて下さい。
目次は次のようになります。
縄をリアルに動かす方法
縄は20点の質点を使って表現しています。質点を使って縄や布を表現する方法自体は、古くからクロスシミュレーションなどでよく使われている手法です。
この20点の質点をPhysicsを使って動かすことで、リアルな縄の動きをシミュレーションします。ただ、各質点にPhysicsを設定しただけではすぐにバラバラになってしまいます。
そこで質点がバラバラに落下しないよう、各質点を接続する必要があります。質点同士を接続するにはUnityのHinge Jointを使用します。「ヒンジ」とは蝶番のことで、質点の移動範囲を円形に固定することができます。
このHinge Jointをすべての質点間に設定することで、物理挙動に従った縄のうごきを実現できます。2Dでチェーンをつくる場合は、次の記事も参考になると思います。
縄の質点をつくる
まずは縄の質点をつくります。ヒエラルキーウインドウで「Create」→「3D Object」→「Sphere」を選択してください。スケールは0.3程度の大きさに変更しておいてください。
作成したオブジェクトを選択し、インスペクタから「Add Component」で「Rigidbody」と「Phsyics/Hinge Joint」コンポーネントをアタッチしてください。ロープを回したときに床と衝突するように「Enable Collision」にチェックを入れます。また、床と衝突したときにヒンジが破綻しないように「Enable Preprocessing」にチェックを入れておきましょう。
アタッチできたらヒエラルキーウインドウのSphereをプロジェクトウィンドウにドラッグ&ドロップしてPrefab化します。作成したPrefabを再びシーンビューにドラッグして合計20個のSphereがX軸上に一列に並ぶように配置します。
ヒンジで質点をつなぐ
続いて質点間のヒンジを繋いでいきましょう。まず一番左のSphereを選択して、インスペクタのHinge JointコンポーネントのConnected Body欄に、一つ右側のSphereをドラッグ&ドロップしてください。
同じ要領で全てのヒンジを順番に接続します。最後に両端のSphereは重力に従って落下しないようKinematicの設定をします。
両端のSphereを選択して、Physicsコンポーネントの「Use Gravity」のチェックを外してください。また「Is Kinematic」にチェックを入れておいてください。
これで物理挙動に従ってだらんと垂れ下がる縄ができました。ここでは分かりやすいように床を追加しています。次は縄を回すスクリプトを作成します。
縄をまわす
縄を回すのは、そんなに難しくありません。縄跳びなら縄を回す人の区割りを両端のSphereにお願いするだけです。
ここでは両端のSphereに回転させる次のスクリプトをアタッチしましょう。
using System.Collections; using System.Collections.Generic; using UnityEngine; public class Rotate : MonoBehaviour { float radius = 1.4f; float speed = 7; float x; float angle = 0; void Start () { x = transform.position.x; } void Update () { angle += speed; float y = 1.2f * radius * Mathf.Sin (-angle * Mathf.Deg2Rad); float z = radius * Mathf.Cos (angle * Mathf.Deg2Rad); transform.position = new Vector3(x, y, z); } }
このスクリプトでは、ゲームオブジェクトをX軸を中心にして回転させているだけです。縄を回す軌跡が楕円になるように、Y軸方向の移動には少しオフセットをのせています。
スクリプトがつくれたら両端のShpereにドラッグ&ドロップしてアタッチしてください。ロープがちゃんと回転するのが確認できます。
表示を縄っぽくする
最後に各質点を繋いだ線を引いてなわとびの縄っぽくしましょう。Unityで線を引くにはLine Rendererという(そこそこ)便利な機能が用意されているのでそれを使います。
ヒエラルキーウインドウで「Create」→「Empty Object」を選択し、空のゲームオブジェクトを作成、名前をRopeに変更しておきます。
続いて、いま作成したRopeをヒエラルキーウインドウで選択し、インスペクタから「Add Component」→「Line Renderere」でコンポーネントをアタッチします。
最後にLine Rendererを使って各質点の間に線を引くスクリプトを作成します。プロジェクトウィンドウでRopeスクリプトを作成し、次のプログラムを入力してください。
using System.Collections; using System.Collections.Generic; using UnityEngine; public class Rope : MonoBehaviour { public GameObject[] vertices = new GameObject[20]; LineRenderer line; void Start () { line = GetComponent<LineRenderer>(); line.material = new Material(Shader.Find("Unlit/Color")); line.positionCount = vertices.Length; foreach (GameObject v in vertices) { v.GetComponent<MeshRenderer> ().enabled = false; } } void Update () { int idx = 0; foreach (GameObject v in vertices) { line.SetPosition(idx, v.transform.position); idx++; } } }
このスクリプトでは各質点の座標を取得し、LineRendererを使ってその間に線を引いています。LineRendererを使うにはマテリアルを設定する必要があるため、Startメソッドの中でマテリアルと線の太さ、質点の数などを指定しています。
作成したRopeスクリプトをヒエラルキーウインドウのRopeオブジェクトにドラッグ&ドロップしてアタッチします。
最後に、アタッチしたスクリプトのVertices欄に質点オブジェクトの実体を設定します。ヒエラルキーウインドウでRopeを選択し、インスペクタからVertexs欄に各質点オブジェクトをドラッグ&ドロップしてください。
ゲームを実行すると、質点のSphereは非表示になり、縄が表示されます。