teratail header banner
teratail header banner
質問するログイン新規登録
Unity

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

Q&A

解決済

2回答

235閲覧

Unity シーン読み込み時にPrefabで自動的に10個のアイテムスロットを作った場合の個別スロットの指定方法

Tora_ou

総合スコア16

Unity

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

0グッド

0クリップ

投稿2025/06/26 19:31

編集2025/06/26 22:39

0

0

実現したいこと

動画を参考にしてアイテムスロットをPrefabを使ってシーン読み込み時に自動的に作ってくれるように作ったのですが
(スロット数は10個)
実際にアイテムの情報を取得してこのPrefabで自動的に作られたアイテムスロットに
いざ、アイテムを表示させよう・・・とした場合にPrefabで自動的に作られたスロットの指定方法がわからない事に気が付きました。

発生している問題・分からないこと

アイテムスロットについて解説している動画は色々あるのですがどれもアイテムスロットをPrefabを使って自動的に作ってはいなくて
スロット、一つ一つを手動で作ったやつ(最初からヒエラルキー上に存在させている)を使っていてそれだとスロットの指定方法はわかるのですけど・・・・

私が動画を参考に作ったアイテムスロットはシーン読み込み時に作られるアイテムスロットなので
ゲームが始まる前はヒエラルキー上には存在していません。
そういった場合、後からPrefabを使ってシーン読み込み時に自動的に作成されたアイテムスロットは
どのように書けば指定できるのでしょうか。

該当のソースコード

[SerializeField] private GameObject slotPrefab; private int slotNumber = 10; void Start() { // アイテムスロットをfrefabを使って自動で作る機能 for (int i=0; i < slotNumber; i++) { GameObject slotObj = Instantiate(slotPrefab,this.transform); Slot slot = slotObj.GetComponent<Slot>(); slot.SetItem(null); } } ↑でこれでシーン読み込み時に自動的に10個のスロットが作成はされますが・・・・  Prefabで作ったスロット(cloneが10個作られる)の指定方法、コードの書き方がわかりません

試したこと・調べたこと

  • teratailやGoogle等で検索した
  • ソースコードを自分なりに変更した
  • 知人に聞いた
  • その他
上記の詳細・結果

アイテムスロット10個ぐらいならPrefabで自動的に生成せずに
一つ一つ、スロットをヒエラルキー上に10個作れば解決はすると思うのですが
Prefabを使う練習、勉強をしてみたいのです。

Prefab、便利だけど使うのはとても難しくて・・・でも逃げて使わずにいても向上しないと思うので。
一日ずっと進まない状態が続くようなら諦めて一つ一つ、スロットをヒエラルキー上に10個作ります。

補足

イメージ説明↑スロットのprefabは2重構造になっていて・・・

イメージ説明↑上のほう(枠の画像、名前がslot)には「slot」というスクリプトが付いています
「slot」というスクリプトの中身は

private Item item; 
[SerializeField]Image image; 

private void Awake()
{
image = GetComponent<Image>();  //imageにImageコンポーネントを入れる
}

public void SetItem(Item item)
{
UpdateImage(item);   //すぐ下の関数を呼び出してる
}

void UpdateImage(Item item)
{
image.sprite = item.sprite;  //Slotのimageにクリックしたアイテムのspriteを入れる
}

イメージ説明↑これで最初この状態(全部空っぽ)だった枠が

イメージ説明
↑アイテムがちゃんと入ってはくれるのだがこのように枠の部分の画像に入ってしまう
(上段の3番目のスロットに画像が入ってる、枠の部分なので隠れてあんまり見えてない)

枠の部分では無くて、アイテムの部分に入って欲しいが指定方法がわからない。
slotというスクリプトを、prefabの枠の部分(名前がslot)から外して
中のアイテム(名前がItemImage)の部分へと貼り替えてみましたが
それだとエラー
NullReferenceException: Object reference not set to an instance of an object
で止まってしまう。

イメージ説明↑slot(枠部分)のimageを子オブジェクト(ItemImage)にすれば良さそう、、と思ったのでそれもやってみたのですが、それをしても何も変化が無くて枠の部分を書き換えてしまう症状は何も変わらなかったです。

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

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

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

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

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

guest

回答2

0

ベストアンサー

私はUnityをほぼ触ってないのでUnity特有の書き方があるのかもしれませんが

C#

1// スコープを考えて適切な場所で配列を定義 2//Slot[] slot = new Slot[10]; 3 4 // アイテムスロットをfrefabを使って自動で作る機能 5 for (int i=0; i < slotNumber; i++) 6 { 7 GameObject slotObj = Instantiate(slotPrefab,this.transform); 8 9 // 配列に格納、定義場所によってはそのオブジェクトを取得するなど必要でしょう。 10 slot[i] = slotObj.GetComponent<Slot>(); 11 12 slot[i].SetItem(null); 13 } 14 15 // 他で使うならslot[1].SetItem(item); 16 // とかでアクセスできるのでは?

といった感じで配列に格納するのはダメですかね?

もしくは

C#

1 // アイテムスロットをfrefabを使って自動で作る機能 2 for (int i=0; i < slotNumber; i++) 3 { 4 GameObject slotObj = Instantiate(slotPrefab,this.transform); 5 slotObj.name = $"slot{i:00}"; 6 }

とインスタンス化したオブジェクトの名前を設定して他からはGameObject.Findで取得するとかも出来るんじゃないですかね?
他にも方法はありそうです。

投稿2025/06/26 20:07

YAmaGNZ

総合スコア10663

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

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

Tora_ou

2025/06/26 21:40 編集

回答ありがとうございます。スロットの指定方法についてはその通りの方法で出来ました。 しかし新たな問題が。 今回、自動的に作られるprefabスロットの構造が2重構造になっていて (枠の部分 と アイテムが表示される中身 の2重構造) 回答いただいた方法で指定出来たのは枠の部分の画像になりました。 指定されたprefabに画像が表示されてはいるのですが枠のほうが書き換わってしまいます。 枠ではなく、アイテムが表示される部分を指定したいのですがどうも上手くいかないです。 「slotのスクリプト」は「枠の部分」に貼られていたのですが それを単純に「中身の部分」に貼り替えてみたけど、それではダメでした(エラーで止まる) 画像で説明したいので質問内容の「補足」の部分を追加、編集しました。 (コメントへの返答だと画像が使えない為&補足部分に追加しましたが元々の質問については一語も変更してません)
YAmaGNZ

2025/06/27 00:26

SlotのImageじゃなくてSlotの子のItemImageのImageに反映しなくてはいけないのではないですか?
Tora_ou

2025/06/27 04:11

>>SlotのImageじゃなくてSlotの子のItemImageのImageに反映しなくてはいけないのではないですか? その通りなのですが「Slotの子のItemImageのImageに反映させる」やり方がわからないのです コメントいただいたのでこれからそちらを早速試してみたいと思います。なんだか難しそうです・・・ ※GetComponentsInChildren<Image>().Where(c => gameObject != c.gameObject).Single() ・・・!?
guest

0

↑slot(枠部分)のimageを子オブジェクト(ItemImage)にすれば良さそう、、と思ったのでそれもやってみたのですが、それをしても何も変化が無くて枠の部分を書き換えてしまう症状は何も変わらなかったです。

この点についてですが、

C#

1private void Awake() 2{ 3 image = GetComponent<Image>(); //imageにImageコンポーネントを入れる 4}

すでにItemImageを設定しているのだから、上記は不要です。
むしろ、GetComponent<Image>()で(ItemImageではなく)SlotのImageを上書きしてしまっているので、おかしくなります。

投稿2025/06/27 00:29

fiveHundred

総合スコア10450

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

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

fiveHundred

2025/06/27 00:47

なお、(今回は不要そうですが)子オブジェクトのImageを取得する処理は以下で行います。 GetComponentsInChildren<Image>().Where(c => gameObject != c.gameObject).Single() 参考: https://tomi-no-tubuyaki.com/game-develop/unity/how_to_use_getcomponentsinchildren/#toc6 https://qiita.com/baba_s/items/a0490ea36f6a5bcf8b07#getcomponentsinchildrenwithoutself 自身にImageが無い場合は、GetComponentInChildren<Image>()(sが無いので注意)でも大丈夫です。
Tora_ou

2025/06/27 04:12

ありがとうございます。早速試してみたいと思います。出来たらまたコメントいたします。
Tora_ou

2025/06/27 04:23 編集

image = GetComponent<Image>(); と書いていた部分を教えていただいた通り、 image = GetComponentsInChildren<Image>().Where(c => gameObject != c.gameObject).Single(); と書き直す事で枠部分(slot)ではなくて子オブジェクトの中身(ItemImage)を指定して書き換える事に成功しました。 「 Where(c 」といった初めて見る書き方も有ってどういう理屈でこれで子を指定出来ているのかは正直わからないですがこの書き方は覚えておきたいと思います。 ありがとうございました。
guest

あなたの回答

tips

太字

斜体

打ち消し線

見出し

引用テキストの挿入

コードの挿入

リンクの挿入

リストの挿入

番号リストの挿入

表の挿入

水平線の挿入

プレビュー

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

ただいまの回答率
85.30%

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

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

質問する

関連した質問