質問をすることでしか得られない、回答やアドバイスがある。

15分調べてもわからないことは、質問しよう!

新規登録して質問してみよう
ただいま回答率
85.48%
C#

C#はマルチパラダイムプログラミング言語の1つで、命令形・宣言型・関数型・ジェネリック型・コンポーネント指向・オブジェクティブ指向のプログラミング開発すべてに対応しています。

JSON

JSON(JavaScript Object Notation)は軽量なデータ記述言語の1つである。構文はJavaScriptをベースとしていますが、JavaScriptに限定されたものではなく、様々なソフトウェアやプログラミング言語間におけるデータの受け渡しが行えるように設計されています。

Unity

Unityは、Unity Technologiesが開発・販売している、IDEを内蔵するゲームエンジンです。主にC#を用いたプログラミングでコンテンツの開発が可能です。

Q&A

解決済

1回答

3638閲覧

Unity 動的に作成されたボタン上のテキストをタイマー処理で表示変更

Hutax

総合スコア32

C#

C#はマルチパラダイムプログラミング言語の1つで、命令形・宣言型・関数型・ジェネリック型・コンポーネント指向・オブジェクティブ指向のプログラミング開発すべてに対応しています。

JSON

JSON(JavaScript Object Notation)は軽量なデータ記述言語の1つである。構文はJavaScriptをベースとしていますが、JavaScriptに限定されたものではなく、様々なソフトウェアやプログラミング言語間におけるデータの受け渡しが行えるように設計されています。

Unity

Unityは、Unity Technologiesが開発・販売している、IDEを内蔵するゲームエンジンです。主にC#を用いたプログラミングでコンテンツの開発が可能です。

0グッド

0クリップ

投稿2016/10/09 12:39

###前提・実現したいこと
Unityを用いながら、プログラミングの勉強をしています。
その中で、今回もタイマー処理に関して行き詰ってしまったため、質問させていただきました。

今回実現したいことは、動的に作成されたボタンの子オブジェクトのテキストをタイマーで0になったときに表示を変えることです。

概要としましては、DBからphpで値を取得し、JSON形式でUnity側に送り、C#で表示しています。このとき、取得したJSONを表示するのに、プレハブ化したボタンを用意し、動的に表示するようなプログラムを作りました。
ここにタイマー処理を加え、ボタンの子オブジェクトのテキストの表示を変更するプログラムを考えているのですがうまくいきません。

ボタンプレハブには、子オブジェクトとしてテキストが3つ付いており、
・○の数を表示するテキスト
・×の数を表示するテキスト
・アルファベットを表示するテキスト
となっています。

##発生している問題
行き詰った内容としましては、作成したC# timer.csでは、JSONをしっかり解析し、動的にボタン上に表示されるのですが、
ここにタイマー処理を加えると、表示したいボタンとは別に新たにボタンが作成され、そのボタンのみタイマー処理で表示が切り替わってしまいます。

###該当のソースコード
timer.cs

C#

1using UnityEngine; 2using System.Collections; 3using MiniJSON; 4using UnityEngine.UI; 5using UnityEngine.SceneManagement; 6 7public class timer : MonoBehaviour 8{ 9 10 [SerializeField] 11 RectTransform prefab = null; 12 13 Text text; 14 public float Timer = 10; 15 16 void Start() 17 { 18 StartCoroutine(Connect()); 19 20 var item = GameObject.Instantiate(prefab) as RectTransform; 21 item.SetParent(transform, false); 22 text = item.Find("text").GetComponentInChildren<Text>(); 23 } 24 25 IEnumerator Connect() 26 { 27 // webサーバへアクセス 28 WWW www = new WWW("http://~~~.php"); 29 // webサーバから何らかの返答があるまで停止 30 yield return www; 31 Debug.Log(www.text); //phpからJSONが送られてきているかどうかの確認 32 33 // もし、何らかのエラーがあったら 34 if (!string.IsNullOrEmpty(www.error)) 35 { 36 // エラー内容を表示 37 Debug.LogError(string.Format("Fail Whale!\n{0}", www.error)); 38 yield break; // コルーチンを終了 39 } 40 41 string json = www.text; 42 43 IList List = (IList)Json.Deserialize(json); 44 45 string s; 46 s = "\r\n";//改行コード 47 48 foreach (IDictionary list in List) 49 { 50 string maru = (string)list["maru"]; 51 string batu = (string)list["batu"]; 52 53 var item = GameObject.Instantiate(prefab) as RectTransform; 54 item.SetParent(transform, false); 55 var maru = item.Find("maru").GetComponentInChildren<Text>(); 56 var batu = item.Find("batu").GetComponentInChildren<Text>(); 57 var text = item.Find("text").GetComponentInChildren<Text>(); 58 59 maru.text = "○ =" + maru.ToString() + "個"; 60 batu.text = "× =" + batu.ToString() + "個"; 61 62 text.text = "A"; 63 64 } 65 66 } 67 68 69 // Update is called once per frame 70 void Update() 71 { 72 Timer -= Time.deltaTime; 73 // マイナス値にならないようにしている 74 Timer = Mathf.Max(Timer, 0); 75 if (Timer == 0) 76 { 77 text.text = "B"; 78 Timer =10; 79 } 80 81 } 82}

###試したこと
timer.csの、void Update()より上の部分だけですと、○と×の数、アルファベットを表示したボタンが動的に作成されます。
ここでアルファベットの値を、10秒経過したらAからBに変えたいと考え、void Update()を書き加えたところ、ボタン上のアルファベットは何も変化せず、
新たにボタンが作成され、そのボタンのアルファベットがBとなってしまいます。

考えたこととしましては、foreach文の外でvoid Update()をおこなっているため、また別にボタンが作成され、そのボタンでのみ表示が変わってしまうのかなと考えています。
そのため、foreach文内でvoid Update()をくわえたところ、エラーが出てしまい、動きませんでした。

動的に作成されたボタン上の子オブジェクトのテキストを時間が来たら変更するには、どのようなプログラムを書けばよろしいのでしょうか。

プログラミングの勉強を始めたばかりなので、まだまだ未熟なところも多く、拙い文章で、分りにくい所も多々あると思いますが、何卒お力をお借りできませんでしょうか。
よろしくお願い致します。

気になる質問をクリップする

クリップした質問は、後からいつでもMYページで確認できます。

またクリップした質問に回答があった際、通知やメールを受け取ることができます。

バッドをするには、ログインかつ

こちらの条件を満たす必要があります。

guest

回答1

0

ベストアンサー

Connect内の以下の部分を修正してみてください。

C#

1var text = item.Find("text").GetComponentInChildren<Text>(); 2//↓修正 3text = item.Find("text").GetComponentInChildren<Text>();

「var」=新たに変数を定義しています。
つまり……
・「メソッド内で宣言したtext」と「クラスで宣言したtext」は別物である。
・今のコードだと「メソッド内で宣言したtext」に目的のTextコンポーネントが入っている。
なのにUpdateで書き換えようとしているのは「クラスで宣言したtext」→目的のTextが書き換わらない!
・「クラスで宣言したtext」に目的のTextコンポーネントが入るよう修正する。

ちなみに現状だと、クラスで宣言したtext変数にはStartでInstantiateされたオブジェクトのテキストが入っています。
修正後は「foreachで最後に作ったitemのTextコンポーネント」が入ります。


■複数のTextを扱う場合(コメント返答)
何がわからないのかわからないですが(配列の使い方は参考サイトに書いてある通りなので)……
「配列という概念自体がよくわからない」ということなら、「変数 配列」とかでググって頂ければ幸いです。
一応私が作るならこんな感じかな?というコードを載せます。変更箇所には「変更」とコメントを付けています。

C#

1using UnityEngine; 2using System.Collections; 3using MiniJSON; 4using UnityEngine.UI; 5using UnityEngine.SceneManagement; 6 7public class timer : MonoBehaviour 8{ 9 10 [SerializeField] 11 RectTransform prefab = null; 12 13 Text[] text; //変更:要素数固定なのでtype[]型にしました 14 public float Timer = 10; 15 16 void Start() 17 { 18 StartCoroutine(Connect()); 19/* 変更(不要なのでコメントアウト) 20 var item = GameObject.Instantiate(prefab) as RectTransform; 21 item.SetParent(transform, false); 22 text = item.Find("text").GetComponentInChildren<Text>(); 23*/ 24 } 25 26 IEnumerator Connect() 27 { 28 // webサーバへアクセス 29 WWW www = new WWW("http://~~~.php"); 30 // webサーバから何らかの返答があるまで停止 31 yield return www; 32 Debug.Log(www.text); //phpからJSONが送られてきているかどうかの確認 33 34 // もし、何らかのエラーがあったら 35 if (!string.IsNullOrEmpty(www.error)) 36 { 37 // エラー内容を表示 38 Debug.LogError(string.Format("Fail Whale!\n{0}", www.error)); 39 yield break; // コルーチンを終了 40 } 41 42 string json = www.text; 43 44 IList List = (IList)Json.Deserialize(json); 45 46 string s; 47 s = "\r\n";//改行コード 48 49 text = new Text[List.count]; //変更(追記):Textリストを初期化する 50 int id = 0; //変更(追記):配列に収める為のIDを用意する 51 52 foreach (IDictionary list in List) 53 { 54 string maru = (string)list["maru"]; 55 string batu = (string)list["batu"]; 56 57 var item = GameObject.Instantiate(prefab) as RectTransform; 58 item.SetParent(transform, false); 59 var maru = item.Find("maru").GetComponentInChildren<Text>(); 60 var batu = item.Find("batu").GetComponentInChildren<Text>(); 61 text[id] = item.Find("text").GetComponentInChildren<Text>(); //変更:配列にTextコンポーネントを入れる 62 63 maru.text = "○ =" + maru.ToString() + "個"; 64 batu.text = "× =" + batu.ToString() + "個"; 65 66 text[id].text = "A"; //変更:文章を指定する 67 68 id++; //変更(追記):配列に収める為のIDを用意する 69 } 70 71 } 72 73 74 // Update is called once per frame 75 void Update() 76 { 77 Timer -= Time.deltaTime; 78 // マイナス値にならないようにしている 79 Timer = Mathf.Max(Timer, 0); 80 if (Timer == 0) 81 { 82 text[0].text = "B"; //変更:配列0番に入っているTextコンポーネントの中身書き換え 83 text[1].text = "C"; //変更:配列1番に入っているTextコンポーネントの中身書き換え(使用例) 84 Timer =10; 85 } 86 87 } 88}

正直配列を覚えないとJSONを使ったシステムの作成は非常に困難だと思います。
(というかJSONをデシリアライズしたListが既に配列なんですけどね……)
これを機に覚えると今後の開発が楽になるかと思います。

投稿2016/10/10 06:38

編集2016/10/10 10:53
sakura_hana

総合スコア11427

バッドをするには、ログインかつ

こちらの条件を満たす必要があります。

Hutax

2016/10/10 09:51 編集

sakura_hana 様 ご回答とわかりやすい説明ありがとうございます。 ご教授いただいたことを実際に試したところ、無事foreachで作成したボタン上のテキストを変更できました。 しかし、foreachで作成されたボタン以外に、1つ別の何も表示のないボタンが作成されてしまいます。なぜなのでしょうか。 また、今回、取得して表示するJSONは [ {"maru":"10","batu":"5"}, {"maru":"20","batu":"8"} ] の2つとなっており、ご指摘がありました通り、foreachで最後に作ったitemのTextコンポーネントのみ変更されますが、このどちらも変更するにはどのようにプログラムを書き換えたらよろしいでしょうか。 お手数をおかけしたしますが、ご教授お願いできますでしょうか。
sakura_hana

2016/10/10 09:47

Startメソッド内でもInstantiateをしているので、これが何も無いボタンではないでしょうか? 作った全てのオブジェクトに対して処理をしたいということであれば、変数を配列化すればよいかと思います。 詳しい使い方は下記サイトをご覧ください。 http://myoujing.wpblog.jp/2014/08/874/
Hutax

2016/10/10 10:31

sakura_hana 様 ボタンの原因については解決できました。 ありがとうございます。 ご教授いただきましたサイトを基に、変数の配列化を考えましたが、私の勉強不足、理解不足のため、いまいち理解ができませんでした。教えていただいたのに申し訳ございません… 新たに自分なりに考えたことは、JSON取得において、データベースのidも一緒に取得し、idが1のときのtextの表示はAからBへ、idが2の時はAからCへとタイマーを用いて表示するという方法ですが、この方法だと、idの値がforeach文内でしか使えないのではないかと疑問もありますが…
Hutax

2016/10/10 12:26

sakura_hana 様 わざわざソースコードまで載せていただき、ありがとうございます。 お手数をおかけしました。 今からしっかりと配列を勉強し、利用できるようにしていきたいと思います。 質問にもわかりやすく教えてくださり、ありがとうございました。 遅くなりましたがベストアンサーとさせていただきます。
guest

あなたの回答

tips

太字

斜体

打ち消し線

見出し

引用テキストの挿入

コードの挿入

リンクの挿入

リストの挿入

番号リストの挿入

表の挿入

水平線の挿入

プレビュー

15分調べてもわからないことは
teratailで質問しよう!

ただいまの回答率
85.48%

質問をまとめることで
思考を整理して素早く解決

テンプレート機能で
簡単に質問をまとめる

質問する

関連した質問