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

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

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

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

Unity

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

Q&A

解決済

2回答

2901閲覧

スクリプトから作成したプレハブの子オブジェクトを操作できない

LunarEclipse

総合スコア6

C#

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

Unity

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

0グッド

0クリップ

投稿2018/08/30 06:38

編集2018/08/31 03:53

前提・実現したいこと

以下の図のように
「グループA、Bに表示された画像からそれぞれ1つのみ選択し決定ボタンを押す」
という動作を求めるUIを作成しています。なお、表示される画像は毎回異なります。

グループA [画像1][画像3][画像4]
グループB [画像2][画像5]
[決定]

これに対し、トグルを利用し次のようなプレハブを作成し利用したいと考えています。

▼Toggle    トグルグループ設定でグループ内で1つしか選べないようにする予定
_▼Background 画像変更スクリプト「ImageSet」をアタッチ
__▼Checkmark 

「ImageSet」
Start(){
Image img = GetComponent<Image>();
}
SetImage(){
img.sprite = 画像
}

発生している問題

このプレハブを

GameObject ins = Instantiate(”Toggle”) as GameObject;

として生成し、Canvasの子要素に設定するなどして画面に表示させることには成功しましたが、画像の変更の仕方がよく分かりません。

###試したこと
insがプレハブ化したToggleをインスタンス化したものならば、画像はその子要素なので子要素を取得すれば操作できると考えましたが、

ins.transform.Find("Background").gameObject.GetComponent<ImageSet>().SetImage();

このように記述すると次のようなエラーが表示され、これによるとimg.spriteがnullであると言っているようです。

NullReferenceException: Object reference not set to an instance of an object ImageSet.SetImage () (at Assets/Script/ImageSet.cs:36)

Start()が起動していないのではないかと疑い、試しにGetCompornentを画像変更の直前で行ったところ、
エラーは発生しませんでしたが画像は変更されないままでした。

###質問
以上より、ご教示いただきたい点は次の2点です
1.そもそもToggleの背景画像を動的に変えるというアイデアは実現可能なのか?
→可能ならばどのようにスクリプトを修正すればよいですか?
2.ToggleではなくImageを配置しクリックイベントでオンオフを管理する方法にしてしまったほうが手っ取り早いのか?

###画像
ログ
呼び出し元
ImageSet

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

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

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

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

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

guest

回答2

0

自己解決

Start()を使用せずにAwake()を使用したところChange()が動作する前にAwake()の処理を行うことができるようです。

投稿2018/08/31 14:59

LunarEclipse

総合スコア6

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

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

0

ImageSetのStart()内の
Image img = GetComponent<Image>();
これは
img = GetComponent<Image>();
だと思います。(クラス変数imgが存在すること前提)

上のコードだと、ローカル変数imgに取得したImageを入れているので、クラス変数imgはnullのままであり、SetImage()を実行した時に「nullのspriteにアクセスしようとする」為にNullReferenceExceptionになります。
(Toggleは無関係です)


ぶっちゃけToggleコンポーネントは
「タッチされた時にどのImageの色をどう変えるか、どの画像を使うか(Transition > TargetGraphic)」と
「オンオフ時にどのImageを表示非表示するか(Graphic)」しか行いません。
(現在は前者にBackgroundのImageが、後者にはCheckmarkのImageが入っていると思います)

これ以外はそれぞれのImageが独立して存在しているだけなので、画像を変えるなり色を変えるなり好きにしてOKです。

別にクリックイベントで自力でオンオフしてもいいのですが、トグルグループに該当する機能を作るとなると「Imageの配列持って、オンでない画像はオフにして」という動作になるのでちょっと面倒かなーと思います。
なので今回についてはトグルで処理した方が良いかと。

投稿2018/08/30 08:04

sakura_hana

総合スコア11427

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

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

LunarEclipse

2018/08/30 15:35 編集

すみません、Image型クラス変数imgが存在することを明示しようとして一番まずい書き方をしてしまいました。 現在次のような状態でテストしております. プレハブ生成時にpic1は表示されますが、Change()を呼び出してもpic2を表示することができず、★の行のNullReferenceが返されます。 public class ImageSet : MonoBehaviour { private Image img; public Sprite pic1; //Unityでプレハブにアタッチ public Sprite pic2; //Unityでプレハブにアタッチ private void Start() { img = GetComponent<Image>(); img.sprite = pic1; } public void Change() { img.sprite = pic2;★ } } また、呼び出し元のスクリプトで次のようにプレハブを生成した直後にすぐpic2に切り替えるようにしてみたところ、NullReferenceが返されることは無くなりましたが画像は変わりませんでした。 GameObject ins = Instantiate(prefab, pos, Quaternion.identity) as GameObject; ins.transform.parent = parent.transform; ins.transform.Find("Background").gameObject.GetComponent<ImageSet>().Change();
sakura_hana

2018/08/31 02:15

>プレハブ生成時にpic1は表示されますが、Change()を呼び出してもpic2を表示することができず、★の行のNullReferenceが返されます。 こちらについては、Change()をどんなタイミングで呼んでいるのでしょうか。 例えば別のスクリプトのUpdateでやっている場合、ImageSetのStartより早くChangeが呼ばれている可能性もあります(ただその場合エラーで止まるのでpic1も入らなさそうな気がするので、おかしい挙動ではあります)。 それかもしくは、Change時点でimgコンポーネントが削除されているケースですが、普通に使っていればまず無いかなーとは思います。 >プレハブを生成した直後にすぐpic2に切り替えるようにしてみた 理由がわからないです。本当にChangeのソースコードはこれだけでしょうか。 Changeの中にDebug.Logを仕掛けてimgとpic2がどんな値を取っているか確認してみてください。 なお単純に「Change時にimgがnull」が原因であれば、Changeの先頭で if (img == null) img = GetComponent<Image>(); とでも書いておけばとりあえず動くとは思います。
LunarEclipse

2018/08/31 04:12

本文側に取得したログ、呼び出し元のスクリプト、ImageSetスクリプトの画像を追加しました。 ログを見るとChange()が先に呼ばれ、picture2が貼られたのちStart()によりpicture1が貼られているようで、実際にStart()がらpicture1を貼る部分を削除したところpicture2が表示されました。 エラーが出ていた直接の原因はChange()が先に呼ばれてしまうためChange時にimgがnullということですね。 ではStart()が先に呼び出されるようにするにはどうしたらよいでしょうか。 現在は実験的に生成後すぐにChangeするコードにしていますが、エラーが発生した当初は表示するプレハブを全部生成し、その後spriteを貼るという動作だったのでStart()が呼び出される間もなくChange()が呼ばれていたとは考えにくいのでは?と思ってしまうのですが…。
sakura_hana

2018/09/03 01:46

コメント遅れて申し訳無いです。 Start()は公式ドキュメント曰く「最初のフレームのアップデート前」に呼ばれるそうなので、その前に他の処理が割り込むとこのようなケースになるようですね。 https://docs.unity3d.com/ja/current/Manual/ExecutionOrder.html 正確なところが私もあやふやだったのですが解決されたようで何よりです。
guest

あなたの回答

tips

太字

斜体

打ち消し線

見出し

引用テキストの挿入

コードの挿入

リンクの挿入

リストの挿入

番号リストの挿入

表の挿入

水平線の挿入

プレビュー

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

ただいまの回答率
85.48%

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

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

質問する

関連した質問