【Unity】uGUIをキャラクターの上に表示する手っ取り早い方法【RenderMode別】


RenderModeによって異なる、HUDの表示方法


uGUIをキャラクターの頭上に表示(HUD)して、オブジェクトの移動に追従させる方法は、CanvasのRenderModeによって異なります。
今回はその実装の手っ取り早い方法について、RenderMode別に解説します。
RenderModeについての詳しい解説は、こちら をご覧ください。

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

Screen Space – Overlayの場合


CanvasのRenderModeがScree Space – Overlayの場合、UIの位置をキャラクターに合わせて変化させるためには、キャラクターのワールド座標をスクリーン座標に変換してからUIに教える必要があります。

ワールド座標からスクリーン座標への変換は、RectTransformUtilityクラスに用意されているWorldToScreenPointメソッドを使用します。

同期させたいUIオブジェクトに適用するスクリプトです。

using UnityEngine;

public class UIController_Overlay : MonoBehaviour {

	[SerializeField]
	private Transform targetTfm;

	private RectTransform myRectTfm;
	private Vector3 offset = new Vector3(0, 1.5f, 0);

	void Start() {
		myRectTfm = GetComponent<RectTransform>();
	}

	void Update() {
		myRectTfm.position 
			= RectTransformUtility.WorldToScreenPoint(Camera.main, targetTfm.position + offset);
	}
}

WorldToScreenPointメソッドは、第1引数に描画するカメラ(コンポーネント)の指定、第2引数に変換対象のTransformのPosition(Vector3)を指定することで、Canvas平面上に対応するVector2の値を返します。

例えば下記のスクリプトは、位置を変化させたいUIオブジェクトにアタッチします。

UIを追従させる対象のPlayerオブジェクトからワールド座標を取得し、メインカメラにおけるスクリーンポジションを算出してRectTransformのPositionに値を代入しています。

ちなみに、変換される座標はPivotが基準になるため、キャラクターの頭上に表示するためにオフセットで調整しています。

Screen Space – Cameraの場合


RenderModeがScree Space – Cameraの場合、UIはカメラが描画ことになります。
そのため、Scree Space – Overlayでの変換にもうひと手間加え、ワールド座標から算出したスクリーン座標を、カメラの描画角を基準としたローカル座標に変換します。

ローカル座標への変換は、RectTransformUtilityクラスのScreenPointToLocalPointInRectangleメソッドを使用します。

using UnityEngine;

public class UIController_Camera : MonoBehaviour {

	[SerializeField]
	private RectTransform canvasRectTfm;
	[SerializeField]
	private Transform targetTfm;

	private RectTransform myRectTfm;
	private Vector3 offset = new Vector3(0, 1.5f, 0);

	void Start() {
		myRectTfm = GetComponent<RectTransform>();

	}

	void Update() {
		Vector2 pos;

		Vector2 screenPos = RectTransformUtility.WorldToScreenPoint(Camera.main, targetTfm.position + offset);

		RectTransformUtility.ScreenPointToLocalPointInRectangle(canvasRectTfm, screenPos, Camera.main, out pos);

		myRectTfm.position = pos;

	}
}

ScreenPointToLocalPointInRectangleメソッドは、第1引数にCanvasのRectTransform、第2引数に変換するスクリーン座標、第3引数にUIを描画するカメラ(コンポーネント)、第4引数にoutパラメータを付与したVector2の変数を渡します。

outに渡す引数は事前に宣言しておきます。算出された値はoutの変数に入ります。

World Spaceの場合


RenderModeがWorld Spaceの場合、UIは通常のゲームオブジェクトと同じようにワールド座標系に配置できます。
したがって、手っ取り早くプレイヤーの位置と同期させるなら、プレイヤーの子オブジェクトにしてしまいましょう。
ただし、Rotationも同期されてしまうため、UIがカメラの方向を向くようにスクリプトで処理します。

using UnityEngine;

public class UIController_WorldSpace : MonoBehaviour {

	private RectTransform myRectTfm;

	void Start() {
		myRectTfm = GetComponent<RectTransform>();
	}

	void Update() {
		// 自身の向きをカメラに向ける
		myRectTfm.LookAt(Camera.main.transform);
	}
}

一番手っ取り早い感ありますね。

おまけ(列挙型を使ってRenderModeに動的に対応する)


別々のスクリプトを用意するのが面倒だったので、列挙型のRenderModeを使って一つのスクリプトにまとめてみました。
RenderModeが切り替わっても自動で対応できます。

using UnityEngine;
using System.Collections;
using UnityEngine.UI;

public class UIController : MonoBehaviour {

	[SerializeField]
	private Canvas canvas;
	[SerializeField]
	private Transform targetTfm;

	private RectTransform canvasRectTfm;
	private RectTransform myRectTfm;
	private Vector3 offset = new Vector3(0, 1.5f, 0);

	void Start() {
		canvasRectTfm = canvas.GetComponent<RectTransform>();
		myRectTfm = GetComponent<RectTransform>();
	}

	void Update() {
		Vector2 pos;
		
		switch (canvas.renderMode) {

			case RenderMode.ScreenSpaceOverlay:
				myRectTfm.position = RectTransformUtility.WorldToScreenPoint(Camera.main, targetTfm.position + offset);

			break;

			case RenderMode.ScreenSpaceCamera:
				Vector2 screenPos = RectTransformUtility.WorldToScreenPoint(Camera.main, targetTfm.position + offset);
				RectTransformUtility.ScreenPointToLocalPointInRectangle(canvasRectTfm, screenPos, Camera.main, out pos);
				myRectTfm.localPosition = pos;
				break;

			case RenderMode.WorldSpace:
				myRectTfm.LookAt(Camera.main.transform);

			break;
		}
	}
}

私はこれ↑を使ってます。

以上です。

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

【新着】uGUIをキャラクターの上に表示する手っ取り早い方法【RenderMode別】

Unityの記事一覧にもどる

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

PAGE TOP