3DゲームにおけるUIの使い道
- プレイ画面とは別にして、表示するUI。(上に出てる制限時間とか)
- ワールド座標上に表示されるUI。(右側に白文字で書いてある”中央ウィンドウ”とか)
- プレイヤーの上や下に表示されるUI。(キャラの緑のHPバーとか)
引用 : https://valorant-5chnews.com/archives/3698
見た感じの動きはこのサイト参考
https://light11.hatenadiary.com/entry/2019/04/15/232416
Screen Space Overlay
まずUIと言われると思い浮かぶのがこれ。
画像のMAPの表示や制限時間表示などはUIっぽいUIの使い方。
CanvasにTextやImageを追加してみる
Canvasの設定のRenderModeをScreenSpace-Overlayにする
カメラで映している画像をDisplay1に映し、その映像の上からOverlay(被せる)する形でUIを表示する。
Screen Space Camera
これは Screen Space - Overlay に似ていますが、このレンダーモードでは、キャンバスは指定されたカメラの前に一定の距離で置かれます。
引用 : https://docs.unity3d.com/ja/2018.4/Manual/UICanvas.html
見た目Overlayとほとんど変わらない。カメラの指定距離先に表示なんでカメラを移動しても見た目変わらん。
変わるのは3D空間に配置されるから手前にObjectがあるとさえぎられること。
引用 : https://tech.pjin.jp/blog/2017/03/02/unity_ugui_canvas_rendermode/
Screen Space World
これはCanvasをワールド上に設置するタイプ
引用 : オーバーウォッチ
イメージこんな感じ、何層にもなってる円形の重なりが作れる。
もちろんオブジェクトの影に隠れる。
あれ?この3つだと壁越しのUI表示できなくない???
それはWorld SpaceをScreen Space Overlayへするから
参考: https://tsubakit1.hateblo.jp/entry/2016/03/01/020510
Updateで
position = RectTransformUtility.WorldToScreenPoint (Camera.main, target.position);
でWorld SpaceだったUIのCanvasの座標をCameraの映像にOverlayするCanvasに対しての座標に変換するといける。
つまりワールド座標を元に、UI座標に表示が可能なのである。
参考資料もう一つ
https://gametukurikata.com/ui/damagepointui
ゲームに実装するときに画像がフェードアウトするようにする方法の紹介
実際の手順
考え方がわかっても手順がわからないUnityあるある
工程
ターゲットの設置
UIのプレハブ作成
ターゲットについてるスクリプトでUIのプレハブ生成
動的にUIの座標を変化させる
ターゲットの設置
ターゲットとは、例えばダメージを受けたプレイヤーオブジェクトのこと
ダメージUIとかはそのプレイヤーオブジェクトによって生成されるのがいいよね?(ここは使い方によっては別の手法もあり)
今回は適当にCubeとかでよい
UIのプレハブ作成
UIのプレハブを作成する。
大事なのはCanvasごとプレハブにしないこと。UIとして表示する中身のTextだけでよい。また、座標は自動で変更なので操作しなくていいのと、文字サイズについても後で変更するべき。
ただし自分はTextのParagraphだけは真ん中真ん中の設定にしてる。これのほうが個人的にわかりやすい。
動的にUIの座標を変化させる
UI自身にワールド座標からUIの座標に来てもらえるようにScriptを追加する。
Targetによって生成された時点ではどこにいるかわからない状態なので、Targetの座標を参考にUI座標に移動しよう。
using UnityEngine;
using System.Collections;
using UnityEngine.UI;
public class UIFollowTarget : MonoBehaviour {
RectTransform rectTransform = null;
[SerializeField] Transform target = null;
public Vector2 offset;
void Awake() {
rectTransform = GetComponent<RectTransform>();
}
void Update() {
if (target != null) {
rectTransform.position = RectTransformUtility.WorldToScreenPoint(Camera.main, target.position) + offset;
} else {
Debug.LogError("だめ");
}
}
public void SetTarget(Transform targetTransform) {
target = targetTransform;
}
}
AwakeでUI自身が自分のUI座標にアクセスできるようにする(GetComponent())
AwakeじゃなくてもStartでもいい。
必要な情報はRectTransformUtility.WorldToScreenPointでTargetのワールド座標とMainCamera。Targetのワールド座標を取るために、TargetがUIプレハブを生成したときにTargetが情報を入れるようにする。それ用のSetTarget()を準備。
MainCameraはCamera.mainで取得できるのでそのまんま入れればOK。
ということでUpdateでUIのUI座標をTargetのワールド座標を元に算出し続ければ解決。
ターゲットについてるスクリプトでUIのプレハブ生成
次はTargetにUIを生成する機能を付ける。ここでは特定のCanvasに対して特定のUIを表示する機能を追加する。ダメージを食らったら、とかの条件はIfとかでなんとでもできるのでStartで表示するようにする。
UIInstantate.cs作成(名前は何でもいい)
using System.Collections;
using System.Collections.Generic;
using UnityEngine;
public class UIInstantate : MonoBehaviour{
public GameObject textUI;
public Canvas canvas;
void Start(){
GameObject UIObj = Instantiate(textUI,canvas.transform);
UIObj.GetComponent<UIFollowTarget>().SetTarget(transform);
}
}
Inspector上で表示するプレハブとCanvasをセットしておく
StartでセットしたUIプレハブをInstantiateして、それのTargetを自分に設定
表示の大きさを見てプレハブの文字サイズを変更することで調整するといい
終わりに
UI難しい。
このメモを数か月後に自分が見て、果たして理解できるのだろうか心配になる。
end