テキストをオブジェクトに追従して表示させる

Qiitaに初めて記事を投稿させていただきます。みこしと申します。

# 概要
プレイヤーがオブジェクトと衝突した回数を、オブジェクトの頭上に追従して表示させる方法を紹介します。

# 結果
最終的にこの動画のようになります。
<blockquote class="twitter-tweet"><p lang="ja" dir="ltr"> デモ動画<a href="https://t.co/6tvXLwtob6">pic.twitter.com/6tvXLwtob6</a></p>&mdash; みこし (@Mikoshi_prog) <a href="https://twitter.com/Mikoshi_prog/status/1175041293468090369?ref_src=twsrc%5Etfw">September 20, 2019</a></blockquote> <script async src="https://platform.twitter.com/widgets.js" charset="utf-8"></script>

# 方法
<img width="630" alt="オブジェクトの配置.png" src="https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/498199/b2b3700d-f320-2189-f6e1-8feada2bbfc9.png">

オブジェクトの構成は上の図のようにします。動かすプレイヤーは、UnityのアセットにあるThirdPersonControllerを用いることにします。緑色の球を動かし、プレイヤーが球と衝突した回数を赤いテキストで球の上に表示させます。

Sphereの子にCanvasを設定し、さらにその子にTextを設定します。(上の図のHierarchy内でTextのアイコンが水色になっているのは、すでにTextをプレハブにしているためです。)

<img width="330" alt="Canvasの設定.png" src="https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/498199/1fd65e3c-0a36-2ba8-82ce-e5cb3f2cb03a.png">


CanvasはデフォルトではRender ModeがScreen Space - Overlayになっていますが、これを**World Space**に変更します。こうすることで、通常のオブジェクトと同じようにCanvasを3D空間中の好きな場所に配置できるようになります。

***CanvasをSphereの子にしているため、CanvasのInspectorに表示される座標は親のSphereを基準とした相対座標です。***したがって、Canvasの座標をPosX=0, PosY=0, PosZ=0にすればCanvasがSphereの中心に来ます。個人的に、CanvasがSphereの中心にある方が後でTextの位置調整をする際に楽です。

<img width="322" alt="Textの設定.png" src="https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/498199/aa94c65c-e1c7-ee92-12dc-6a55e4f99a41.png">

Textは球の少し上に配置したいため、Textの座標はPosX=0, PosY=0.7, PosZ=0くらいがよいと思われます。先ほどと同様にTextもCanvasの子なので、TextのInspectorに表示される座標はCanvasを基準とした相対座標です。そして、***Textはプレイヤーと球が衝突するたびに生成されるため、プレハブにしておかなければなりません。***

では次にコードを書いていきます。まずはSphereにアタッチするコードです。

```C#:SphereController.cs
using UnityEngine;
using UnityEngine.UI;

public class SphereController : MonoBehaviour
{
    public Text countText;
    private GameObject canvas;
    private int count;
    private bool positive;

    private void Start()
    {
        canvas = transform.Find("Canvas").gameObject;
        count = 0;
        positive = true;
    }

    private void Update()
    {
        if (transform.position.x > 6f) positive = false;
        else if (transform.position.x < -6f) positive = true;

        if (positive) transform.position += new Vector3(0.1f, 0f, 0f);
        else transform.position -= new Vector3(0.1f, 0f, 0f);
    }

    void OnCollisionEnter(Collision col) 
    { 
        count++;
        Text text = Instantiate(countText);
        text.transform.parent = canvas.transform;
        text.GetComponent<Text>().text = count.ToString();
    }
}
```
public Text countText;の部分でTextのプレハブを受け取ります。

Updateメソッド内でSphereの動きを制御しています。ポイントなのがOnCollisionEnterメソッド内で、***Textのプレハブを一旦インスタンス化し、Canvasの子に設定し、最後に文字を衝突回数の数字にするという流れになっています。***

次に、Textのプレハブにアタッチするコードです。

```C#:TextController.cs
using UnityEngine;

public class TextController : MonoBehaviour
{
    private void Start()
    {
        transform.localPosition = new Vector3(0f, 0.7f, 0f);
        Destroy(gameObject, 2);
    }

    private void Update()
    {
        transform.position += new Vector3(0f, 0.03f, 0f);
    }
}
```
Startメソッド内
1行目: Textの最初の出現位置を、親であるCanvasを基準とした***相対座標***で指定しています。
2行目: 出現してから2秒後に消滅させます。

Updateメソッド内で、Textが上に動き続けるように指定しています。

以上です。私のQiita初めての記事を読んでいただきありがとうございました！