Skip to content

102 3 力学コントローラー(後編)

miuccie-miurror edited this page Jul 26, 2017 · 2 revisions

後編では、前編で作成した掴むUIを物理空間上に置かれた様々なオブジェクトに対して適用させるために、 Jointコンポーネントを使用した引き出しを実装してみたいと思います。

** 今回のサンプルシーンの場所 **
https://github.com/yumemi-inc/vr-studies/tree/master/vol1/VR-studies/Assets/VR-studies/2_VR-controller/2-3_GrabController


ステージの作成

床などを含めた基本的なステージは、前編で使ったものをそのまま使用します。

シーンに3Dオブジェクトを追加してタンスを表現します。ここではCubeを組み合わせて以下のように配置してみました。

さらに、引き出しのコンテナ部分に力学演算を作用させるためにRigidbodyコンポーネントをアタッチします。 Containerという名前で空のGameオブジェクトを作成し、各構成Cubeをまとめてその子にしてContainerのみにRigidBodyをアタッチします。 また引き出しに重量感を出すためMassとDragの値を少し上げておきます。

次に同じContainerに、引き出しの物理制約を持たせるために、Configuarable Jointコンポーネントをアタッチします。

Configuarable Jointコンポーネントでは、XYZの各座標に沿って、アンカーポイントや稼働可能距離、稼働可能角度などを詳細に設定することができます。

ここでは画面手前方向が正のX座標になっているので、Anchorの座標は原点のまま、X MotionをLimitedに、そのほかの距離や角度はLockedに設定し、 Linear LimitをContainerのX Scaleと同じ0.3として引き出せるX距離に限界値を設定しています。


GrabController.csの修正

掴んだ際に、掴まれたオブジェクトそのものが持つRigidbodyを操作するのではなく、指定された別のRigidbody全体を操作可能にするために、前編で作成したGrabController.csを修正します。

前編で作成したGrabController.csを、Hierarchyパネル上の[CameraRig]/Controller (right/left)にアタッチしたら、掴まれる対象となるオブジェクトが持つべきメソッドを、以下のようにIGrabControllerTargetインタフェースとして定義します。

public interface IGrabControllerTarget {
  Rigidbody GetTargetRigidbody();
}

コリジョン発生時にはこのインタフェースを実装しているオブジェクトのみをヒット対象とし、 さらにトリガーボタンが引かれた際には、Fixed Jointと接続するRigidbodyをこのインタフェース経由で取得するように修正します。

// コリジョンイベントの検知
void OnTriggerEnter( Collider other ) {

  // 掴めるオブジェクトが衝突した場合のみ検知する
  if ( other.gameObject.GetComponent<IGrabControllerTarget>() != null ) {
    hitObject = other.gameObject;
  }
}

// トリガーボタンイベントの検知
public void OnTriggerClicked( object sender, ClickedEventArgs e ) {

  if ( hitObject ) {

    // 剛体をジョイントにアサイン
    var grabTarget = hitObject.GetComponent<IGrabControllerTarget>();
    joint.connectedBody = grabTarget.GetTargetRigidbody();
  }
}

GrabControllerTarget.csの作成

新規にGrabControllerTarget.csを作成し、以下のように、IGrabControllerTargetのメソッドを実装します。

public class GrabControllerTarget : MonoBehaviour, GrabController.IGrabControllerTarget {

	public Rigidbody rigidbody = null;

	void Awake () {
		if (rigidbody == null) {
			rigidbody =	this.GetComponent<Rigidbody> ();
		}
	}

	public Rigidbody GetTargetRigidbody() {
		return rigidbody;
	}
}

これを、Hierarchyパネル上のContainer内のKnobオブジェクトにアタッチし、さらにRigidbodyプロパティティに親のContainerオブジェクトのRigidbodyをアサインしてください。


シーンの実行

シーンを実行すると、引き出しのノブ部分のみが掴めて、引っ張ると手前に引き出せて、特定距離以上引き出そうとするときちんと止まったでしょうか?

以下のサンプルシーンでは、他にもさまざまなインタラクションのサンプルを作成してみましたので参考にしてください。

** 今回のサンプルシーンの場所 **
https://github.com/yumemi-inc/vr-studies/tree/master/vol1/VR-studies/Assets/VR-studies/2_VR-controller/2-3_GrabController