経緯
Unity3DでScore情報などを画面に2Dで出すuGUIを操作中、Text(自分)の文字をScriptから取得して変更しようとしてもなかなかうまくいかなかった。
超初歩的な内容だが、インターネットにuGUI以前のUnityGUIに関する情報が混在していることや、自身の間違った推測、ましてや自分がUnity自体初心者なためScriptとUnityとの関係性やつなぎ方が分かっておらず、かなりはまってしまったので、備忘録と、もしかしたらいるかもしれない第二の自分のために。
#方法
##事前準備
- 「Hierarchy -> Create -> UI -> Text」でCanvas/TextをHierarchyに追加
- 「Project -> Assets」で右クリックをして「Create -> C# Script」でNewBehaviourScriptを作成して適当にリネーム
- 「Hierarchy -> Canvas/Text」にさっき作ったC# ScriptをAdd Compornent
##追加する記述
using UnityEngine;
using System.Collections;
using UnityEngine.UI; // <---- 追加1
public class ***: MonoBehaviour
{
private Text targetText; // <---- 追加2
void hoge(){
this.targetText = this.GetComponent<Text>(); // <---- 追加3
this.targetText.text = "ChangeText"; // <---- 追加4
#ポイント
1. using UnityEngine.UI; //<---- 追加1
まずはまったポイントがコレ。UnityEngine.UIを追加し忘れていた。
追加し忘れていたというか、てっきり自分は1行目の
using UnityEngine;
でUnityEngine配下と思われるUnityEngine.UIも利用できるようになっているのかと思ってしまったが、別途UnityEngine.UIをusingで指定する必要があった。これがないと、追加2でエラーが出る。
2. private Text targetText; //<---- 追加2
privateでText型のtextを宣言している。追加1でUnityEngine.UIを追加していないと、そもそもこの「Text」って何?というエラーが出る。
3. this.targetText = this.GetComponent<Text>(); //<---- 追加3
自身のComponent「Text」の値をとってくる、というもの。これがないとどのText(Component)を変更するのかをscriptから判断できない。ちなみにUnityのUI上でここを指定することもできる。その場合はこの記述はいらない(補足1)。
4. this.targetText.text = "ChangeText"; //<---- 追加4
Textクラスのフィールド「text」に値を代入する。
#補足
補足1 this.targetText.GetComponent<Text>();を使わず、UnityのUI上で済ましてしまうやり方
Script上の「private Text targetText」のアクセス修飾子をpublicに変更することで、Unityの
「Hierarchy -> Canvas/Text」選択時の
「Inspector ->***(Add ComponentしたC# script) -> Text」の項目が
「None (Text)」となっていることがわかる。
ここに、
「Hierarchy -> Canvas/Text」
をドラッグ&ドロップすると、Unity UI上でscriptの
「public Text targetText」に「Hierarchy -> Canvas/Text」がアタッチされ、移行targetTextはアタッチしたCanvas/Textを参照するようになる。
こうすれば、上記の
this.targetText.text = this.GetComponent\<Text>();
は不要になる。
補足2 上記scriptを「Canvas/Text」ではなく「Canvas」にAddComponentしたら動かない
ちなみに、上記scriptをCanvas自身にAddComponentしたらこのコードは動かない。
理由は
this.targetText.text = this.GetComponent\<Text>(); //追加3
の「this.」がCanvas自身になってしまい、Canvas自身にはTextがないので動かない。
この場合、取得したいTextは子要素になるため、
GameObject child = transform.Find("Text").gameObject;
this.targetText.text = child.GetComponent\<Text>();
とすることで、子要素を取得し、その子要素にAddされているComponent<Text>を取得することもできる。
しかし、個別のText等のコンポーネントにいちいちScriptをAddComponentしていくのは非現実的なのと、子要素の名前を指定して取得するケースはGameObjectの構成を変更した途端に全て修正する必要ができてしまう。
そのため、例外的に対応する以外は、やはり大元となるGameObjectにControllerのようなclassを用意し、多数ある子GameObjectをpublicにしてUnity上からアタッチするほうがよいと思われる。
###おわりに
何かご指摘やもっと良い方法等がありましたらコメントお願いします!