Skip to content
第09回 ゲージの表示と変化

4 / 4 頭上表示と座標変換 ​

このステップの目的

3D空間での大きさを保つ方法と、画面上の大きさを保つ方法を比較します。

World Spaceの配置 ​

このページは選択課題です。Lesson09をLesson09World.unityとして別名保存します。対象の移動だけを確認するため、空のGameObjectをTargetとして原点へ置きます。Main CameraをPosition (0, 0, -10)、Rotation (0, 0, 0)にします。

CanvasをTargetの子へ移し、Render ModeをWorld Space、Rect TransformのWidth 400、Height 100、Pivot (0.5, 0.5)、Local Position (0, 1, 0)、Local Rotation (0, 0, 0)、Scale (0.01, 0.01, 0.01)にします。GaugeBackgroundはCanvas中央のままです。

World Spaceでは、UIのローカルの幅にTransformのScaleを掛けた値が3D空間での幅になります。この例の幅300のゲージは3ユニットです。親TargetのScaleは(1, 1, 1)を維持します。

ScriptsフォルダーへFaceCamera.csを作り、Canvasへ追加してTarget CameraにMain Cameraを割り当てます。

csharp
using UnityEngine;

public class FaceCamera : MonoBehaviour
{
    [SerializeField] private Camera targetCamera;

    private void LateUpdate()
    {
        if (targetCamera != null)
            transform.rotation = targetCamera.transform.rotation;
    }
}

Playし、TargetのPosition Zを0 → 10 → 0へ変えます。遠ざかると小さくなり、元へ戻すと同じ大きさに戻ります。カメラと回転をそろえる処理をビルボードと呼びます。確認後はPlayを終了して保存します。

固定サイズの頭上表示 ​

こちらを選ぶ場合は元のLesson09をLesson09Overlay.unityとして別名保存し、CanvasをOverlayのまま使います。Canvasの直下にあるGaugeBackgroundのAnchor Min・MaxとPivotは中央(0.5, 0.5)、Scaleは(1, 1, 1)です。前のWorld Space用の設定は引き継ぎません。

Targetを原点へ作り、Main Cameraは前節と同じ位置・回転にします。空のGameObjectをUIFollowerとして作成し、次のWorldToCanvasFollower.csを追加します。非表示にするゲージとは別の、常に有効なGameObjectへ置くことで、画面へ戻ってきたときも更新できます。

csharp
using UnityEngine;

public class WorldToCanvasFollower : MonoBehaviour
{
    [SerializeField] private Transform target;
    [SerializeField] private Vector3 worldOffset = Vector3.up;
    [SerializeField] private Camera worldCamera;
    [SerializeField] private RectTransform canvasRect;
    [SerializeField] private RectTransform uiRect;

    private void LateUpdate()
    {
        if (uiRect == null)
            return;
        if (target == null || worldCamera == null || canvasRect == null)
        {
            uiRect.gameObject.SetActive(false);
            return;
        }

        Vector3 position = target.position + worldOffset;
        Vector3 viewport = worldCamera.WorldToViewportPoint(position);
        bool visible = viewport.z >= worldCamera.nearClipPlane
            && viewport.z <= worldCamera.farClipPlane
            && viewport.x >= 0f && viewport.x <= 1f
            && viewport.y >= 0f && viewport.y <= 1f;
        uiRect.gameObject.SetActive(visible);
        if (!visible)
            return;

        Vector3 screenPoint = worldCamera.WorldToScreenPoint(position);
        RectTransformUtility.ScreenPointToLocalPointInRectangle(
            canvasRect, screenPoint, null, out Vector2 localPoint);
        uiRect.anchoredPosition = localPoint;
    }
}

Target、World Camera、Canvas Rect、UI Rectへ、それぞれTarget、Main Camera、Canvas、GaugeBackgroundを割り当てます。ここではOverlayなので座標変換のカメラ引数はnullです。別のCanvasモードへそのまま流用しません。

PlayしてTargetのZを0 → 10 → -20 → 0へ変えます。距離が変わってもゲージの大きさは一定で、カメラの後ろでは消え、戻すと再表示されます。Xを100へ変えた画面外も確認し、最後は原点へ戻します。

画面上の位置へ変換しただけでは、手前の壁による遮蔽を判定できません。常に状態を見せる用途か、壁の後ろでは隠す用途かを別に決めます。この例の対象は位置・大きさ・画面外からの復帰です。

チェックリスト
  • 選んだ方式で、距離による大きさの変化を説明できる。
  • 固定サイズ方式を選んだ場合、画面外・カメラ後方からの再表示を確認した。
  • 基準の位置へ戻し、採用したSceneとPrefabを保存した。