XR ray Interactorの先にあるTMPText上の文字を取得する
TextMeshProの機能を使うと実は簡単に作れます。
Tl;Dr
テキストをTextMeshPro.TMPTextの派生クラスを用いて作成する
1.のgameObjectにEventTriggerを追加し、
Pointer Click
イベント用のハンドラを書くPointerEventData.worldPositionをCamera.WorldToScreenPointを用いてスクリーン座標へ変換する
TMPTextUtilities.FindIntersectingCharacterで文字のインデックスを取得する
インデックスを元に、TMPText.textから取得する
バージョン情報
パッケージ等 | バージョン |
---|---|
Unity | 2022.1.24f1 |
TextMeshPro | 3.0.6 |
XR Interaction Toolkit | 2.0.4 |
UnityUI | 1.0.0 |
工程
最初2工程は前回の記事と同じ内容になります。簡単のためこちらにも記載しています。
テキストメッシュを作成する
XR Interaction Toolkit対応のCanvasを作り、その子供にTextMeshProUGUIを 作成します。便宜上、このgameObjectを「テキストメッシュ」と呼ぶことにし ます。
テキストメッシュがXR Ray Interactorのイベントに反応出来るようにする
テキストメッシュは、デフォルトではEventSystemのイベントに反応しません。 そこで、EventTriggerを用いてXR Ray Interactorのイベントに反応出来るよ うにします。
!写真
テキストメッシュにEventTriggerコンポーネントを追加し、 Pointer Click
イベントを追加します。
そのコールバック関数として、 BaseEventData
を受け取って void
を返
す関数を作成します。ここでは、 pointerClick
として定義しておくことに
します。(写真では BufferUI.pointerClick
となっています)
using UnityEngine.EventSystems;
using TMPro;
public class PointerClickExample {
/// 作成したテキストメッシュへの参照
private TMP_Text m_text;
public void pointerClick(BaseEventData d) {
var pointerEv = d as PointerEventData;
if (pointerEv == null) {
return;
}
}
}
交差点がどの文字上にあるのかを取得する
TMPro.TMPTextUtilities.FindIntersectingCharacterを用いると、与えた点 と交わっている文字を取得することが出来ます。
しかし、その際与える座標は ワールド座標系 ではありません 。 camera
引数で与えたカメラのスクリーン座標系である必要があるようです。
"あるようです"というのは、ドキュメント上には記載がなく自分で試した時に
上手くいったのがそれだったからです。又、インターネットで調べた所
Input.mousePosition
を用いているものが多くあり、それもスクリーン座標
系であるからという推測でもあります。
イベントの発生したカメラのスクリーン座標系の座標を取得する
pointerClickイベントが発生した時のRaycastとの交差点は、 PointerEventData.pressPositionで取得出来ます。これは PointerEventData.pressEventCameraのカメラのスクリーン座標系の座標となっ ています。
(おまけ) PointerEventData.pointerPressRaycast.worldPosition
からの取得
カメラのワールドToスクリーン座標変換関数を用いると、これからも取得する ことが出来ます。
pointerEv.pressEventCamera.WorldToScreenPoint(pointerEv.pointerPressRaycast.worldPosition)
文字インデックスから文字を取得する
FindIntersectingCharacter
を用いて、 TMP_Text.text
のインデックス
を取得することが出来ます。そのインデックスを用いることで、文字を取得す
ることが出来ます。
文字が見付からなかった際は -1 を返すようなので、そこで条件分岐が必要で す。
using UnityEngine.EventSystems;
using TMPro;
public class PointerClickExample {
/// 作成したテキストメッシュへの参照
private TMP_Text m_text;
public void pointerClick(BaseEventData d) {
var pointerEv = d as PointerEventData;
if (pointerEv == null) {
return;
}
var pos = new Vector3(pointerEv.pressPosition.x, pointerEv.pressPosition.y, 0f);
var idx = TMP_TextUtilities.FindIntersectingCharacter(m_text, pos, pointerEv.pressEventCamera, false);
if (idx == -1) {
Debug.Log("文字が見付かりませんでした");
} else {
Debug.Log($"index: {idx}, 選択された文字: {m_text.text[idx]}");
}
}
}