Ink

Contents related to tech, hobby, etc

XR ray Interactorの先にあるTMP_Text上の文字を取得する

|

XR ray Interactorの先にあるTMPText上の文字を取得する

TextMeshProの機能を使うと実は簡単に作れます。

Tl;Dr

  1. テキストをTextMeshPro.TMPTextの派生クラスを用いて作成する

  2. 1.のgameObjectにEventTriggerを追加し、 Pointer Click イベント用のハンドラを書く

    1. PointerEventData.worldPositionCamera.WorldToScreenPointを用いてスクリーン座標へ変換する

    2. TMPTextUtilities.FindIntersectingCharacterで文字のインデックスを取得する

    3. インデックスを元に、TMPText.textから取得する

バージョン情報

パッケージ等バージョン
Unity2022.1.24f1
TextMeshPro3.0.6
XR Interaction Toolkit2.0.4
UnityUI1.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]}");
        }
    }
}