Unityで動く床を実装するときにハマる罠とその解決方法


Unityで動く床を実装するときにハマる罠とその解決方法


Unityで移動する床を作り、いざプレイヤーが乗ってみたら足場だけ動いてプレイヤーが滑ってるぅ…。
なんてことありませんか?
生徒さんからの質問では、あるある中のあるあるです。

Rigidbodyコンポーネントはちゃんとアタッチしてあるのに…。
物理マテリアルで摩擦も設定してあるのに…滑る…。
とかよく聞かれます。

それって足場オブジェクトを transform.Translate メソッドとか、transform.position を直接変更するような処理で動かしてませんか?
それだとRigidbodyは仕事をしません。

transform による移動は、「位置の変更」です。転位・ワープとも言えます。
ちょっとずつ移動しているように見えても、厳密にはちょっとずつワープしているため、そこに摩擦のような物理演算は発生しません。
上に乗っているオブジェクト(以後プレイヤーとする)が滑って見えるのはこのためです。

解決方法としては主に以下の2つ

足場を Rigidbody を使って移動させる
足場に乗ったプレイヤーを、足場オブジェクトの子要素にする

それぞれ長所と短所があるため、順番に見ていきましょう。

※使用しているUnityのバージョンは5.4.0です。

足場を Rigidbody を使って移動させる


ひとつ目は、足場をRigidbodyを使って移動させる方法です。
以下のようなvelocity(速度)を変更する移動であれば、物理演算が行われるため、足場とプレイヤーの間に摩擦が発生します。
摩擦を介してプレイヤーの速度も変更されるため、足場と一緒に移動するようになります。

	Rigidbody rb = GetComponent<Rigidbody>();
	rb.velocity = new Vector3(1f, 0, 0);

ただし、良くも悪くも物理演算が正確であるため、摩擦力と足場の速度をしっかりと想定しておかないと、摩擦力を超えて滑って落ちることもあります。
また、垂直方向の足場の移動(特に下がる場合)は摩擦が発生しないため、自由落下よりも速く落としてしまうと、プレイヤーが浮いてしまいます。

足場に乗ったプレイヤーを、足場オブジェクトの子要素にする


ふたつ目は、足場に乗ったオブジェクトが、足場の子要素になる方法です。
乗った瞬間を検知したプレイヤーが、自身の親要素を足場オブジェクトに変更し、離れたら元に戻します。
足場の移動は transform を使った移動で問題ありません。
以下は、プレイヤーにアタッチするスクリプトです。

	void OnCollisionEnter(Collision col) {
		if (col.gameObject.tag == "MoveStage") {
			transform.SetParent(col.transform);
		}
	}

	void OnCollisionExit(Collision col) {
		if (col.gameObject.tag == "MoveStage") {
			transform.SetParent(null);
		}
	}

子要素となったプレイヤーの transform は、親要素である足場の transform からの相対位置として扱われます。
この方法なら、足場がどんなに縦横無尽に高速で移動したとしても、プレイヤーは足場にぴったり張り付いたままです。
仮に、プレイヤーを操作して移動させて場合、動く足場の上で通常通り移動します。

欠点としては、親要素を変更するSetParentの処理は、比較的重めの処理であることです。
プレイヤーの周りで局所的に使用するぐらいでは負荷というほど問題はないため、あまり気にする必要はありませんが。

以上です。

最近よく読まれている記事

Unityで2Dゲームの背景をカメラに合わせて自動で回り込ませる方法
Unity 練習問題 7

Unityの記事一覧にもどる

  • このエントリーをはてなブックマークに追加

PAGE TOP