【Unity】uGUIをキャラクターの上に表示する手っ取り早い方法【RenderMode別】
▶
【Unity】3Dアクションゲームを作ろう!#7 ステージの作成(Skybox・落下判定)
▶
【Unity】3Dアクションゲームを作ろう!#8 ステージの作成(スイッチ・扉)
▶
【Unity】3Dアクションゲームを作ろう!#9 プレイヤーのHP管理
▶
【初心者Unity】JsonUtilityクラスでJSONを扱う方法
▶
【初心者Unity】スクリプトからコンポーネントを追加する方法
RenderModeによって異なる、HUDの表示方法
uGUIをキャラクターの頭上に表示(HUD)して、オブジェクトの移動に追従させる方法は、CanvasのRenderModeによって異なります。
今回はその実装の手っ取り早い方法について、RenderMode別に解説します。
RenderModeについての詳しい解説は、こちら をご覧ください。
※使用しているUnityのバージョンは2017.1.0f3です。
[Unity_317×90]
Screen Space – Overlayの場合
© Unity Technologies Japan/UCL
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の場合
© Unity Technologies Japan/UCL
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の場合
© Unity Technologies Japan/UCL
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; } } }
私はこれ↑を使ってます。
以上です。
▶
【Unity】3Dアクションゲームを作ろう!#7 ステージの作成(Skybox・落下判定)
▶
【Unity】3Dアクションゲームを作ろう!#8 ステージの作成(スイッチ・扉)
▶
【Unity】3Dアクションゲームを作ろう!#9 プレイヤーのHP管理
▶
【初心者Unity】JsonUtilityクラスでJSONを扱う方法
▶
【初心者Unity】スクリプトからコンポーネントを追加する方法
ゲーム制作関連のオススメ連載リンク
とっても手軽なゲーム制作体験!
Unityゲーム開発基礎
実際のリリースゲームを題材にしたハンズオンゲーム制作連載
実践unityゲーム開発