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

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

Q&A

解決済

1回答

337閲覧

Unity 画像Aを押している間、画像Bを表示させる、というのを画像Aが「Prefab」だった時のやり方

Tora_ou

総合スコア16

Unity

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

0グッド

1クリップ

投稿2025/06/27 07:14

編集2025/06/27 19:44

0

1

実現したいこと

画像Aを押している間だけ、別の画像Bを大きく表示させる、という事を
「Event Trigger」の PointerDown と PointerUp を使って実現できたのですが
画像Aも画像Bも、両方ともがヒエラルキー上に最初から存在する場合、は簡単でした。
画像Aが最初から存在しているので[SerializeField] で押している間に表示させたい画像Bを予め選んでおけるからです。

これが画像Aが「prefab」後から生成される画像で
最初はヒエラルキー上に存在しない場合、途端にどうすれば良いのかがもうわからないのです。

少しでも簡単になればと思って画像Bに関してはヒエラルキー上に用意してSetActive(false);で待機させてあります。
※画像Bも本来は「prefab」後から生成される画像だったけど画像Aも画像Bも
両方ともが「prefab」で生成されるとなるともう本当にわけがわからなくなるので・・・

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

「prefab」については本当に悩みの種で、いつも「prefab」が出てくるだけでヒエラルキー上にある物だったら出来ていた事が途端に出来なくなってしまいます。
ちなみに先に質問した内容の続きになっています
https://teratail.com/questions/twk0oiyg3lztpx#reply-rnuh8uqb2imsm8

アイテムスロットの枠に画像が表示されるようになった、所まではおかげ様で出来たのですが
そのスロットに表示されているアイテムの画像を押している間、別の画像が大きく表示される、といった事がやりたい事です

該当のソースコード

最初からヒエラルキー上に画像が有る場合はこれを画像に貼って 「Event Trigger」の PointerDown と PointerUp で設定するだけなので簡単でした public class clickOnAction : MonoBehaviour { [SerializeField] GameObject GatyaImageBig; //←画像を押している間だけ表示させたい画像を先に選択しておけるので簡単 public void PointerDown() { GatyaImageBig.SetActive(true); } public void PointerUp() { GatyaImageBig.SetActive(false); } }

試したこと・調べたこと

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

この数週間で完全に「prefab」に苦手意識を持ってしまいました。
これが出てくるだけで数時間、時には数十時間、何も進まない、という体験を連続で食らってしまっています。
「prefab」だと [SerializeField] が全部外れてしまうのは色々な解説を読んで理由もわかりましたが、結果、とても使いにくくてわかりにくくて便利ではないです。

補足

Itemの情報として
[Serializable]
public class Item
{
public enum Type
{
A_Item,
B_Item,
C_Item,
D_Item,
E_Item,
F_Item,
G_Item, 
H_Item,
}
public Type type; //種類
public Sprite sprite; //アイテムスロットに表示する画像 これは正しく表示出来ている
public Sprite BigSprite; //大きく出す画像
}

種類、スロットに表示する画像(これは正しくアイテムスロットに表示が出来ている)
そして public Sprite BigSprite; //スロットの画像を押した際に大きく出したい画像
と↑の3つの情報があって設定が出来ているのですが
先の質問で
https://teratail.com/questions/twk0oiyg3lztpx#reply-rnuh8uqb2imsm8

image = GetComponentsInChildren<Image>().Where(c => gameObject != c.gameObject).Single();
と書いて子オブジェクトを指定する方法を教えてもらって
子オブジェクトからスロットの画像を取得できて、アイテムスロットに画像を入れれたものの
コードの意味が何も分かっていないままコピーしただけなのでなぜこれで
子オブジェクトの画像が入れれているのかわかっていません、つまり
public Sprite BigSprite;の中に入っている「スロットの画像を押した際に大きく出したい画像」も
もちろん指定できない、という状態です
public Type type;(種類)も取得する方法がわかっていないです
これがわかればこのtypeの場合、画像を押したらこの画像をこの部分に大きく表示、といったような
条件式も書けると思うのですが
ここまでわかっていなくて今、アイテムスロットに画像が表示されてるはどうしてなのか、自分でも不思議です

先の質問での
https://teratail.com/questions/twk0oiyg3lztpx#reply-rnuh8uqb2imsm8
コードを何度も見直していて気付いた事が有って
private void Awake()
{
image = GetComponentsInChildren<Image>().Where(c => gameObject != c.gameObject).Single();  //こう書くことで子の画像を指定できている、コードの意味はわからない
}
public void SetItem(Item item)
{
this.item = item;
UpdateImage(item); //←今まではこれしか無かった、画像しか更新されていなかった
UpdateType(item); //←なのでこれを追加してtypeを更新すれば区別できるのでは??
}

void UpdateImage(Item item) //これは先の質問の時にも有った関数、slotの画像情報を書き換え
{
image.sprite = item.sprite; //Slotのimageにアイテムのspriteを入れる
}

//public Item.Type ItemType; アイテム用の変数を宣言しておいて
void UpdateType(Item item) //タイプを書き換える関数が無かったので追加してみた
{
ItemType = item.type; //これでSlotのTypeにアイテムのTypeが入った。。。のではないか?
}
画像は void UpdateImage(Item item) を使って書き換えることが出来ているので
それと同じタイミングでtypeの情報を書き換えれば、と思い試してみたところ、
これでタイプ情報が入っているようです。
大きな画像もこれと同じ要領で書き換えればついに目的達成できる・・・??

イメージ説明↑Typeが書き換えれてスロットに情報としてちゃんと入っています・・・
(画像の C_charm4 というのが4時間もかけてようやく入れる事の出来たItemType
アイテムが違うとこの部分もちゃんと変わるようになってくれた)
・・・が、しかしその画像を押した時、そのスロットに設定されている
タイプが A_Item,ならこの画像を表示、B_Item,ならこの画像を表示、
という事が出来ると思っていたのですが今度はその条件式の書き方がわからないです。。。
public void PointerDown()
{ Debug.Log("画像が押されてます");
switch (ItemType)
{
case Item.Type.A_Item: //アイテムタイプがA_Item の時  
ItemImage01Big.SetActive(true); //アイテムAの拡大画像を表示
break;
case Item.Type.B_Item: //アイテムタイプがB_Item の時
ItemImage02Big.SetActive(true);  //アイテムBの拡大画像を表示
break;
}
}
これでスロットに入っている画像のタイプを見てくれて条件式分けが出来ると思っていたのですが
この書き方では押した画像のスロットのタイプを全く参照してないようでどっちのcaseも通らないようです
※switchの外に書いた Debug.Log("画像が押されてます"); は動いているのでcaseの中だけ通ってない
押した画像のItemTypeを参照させてそれを条件式に書く場合はどのよう書けば良いのでしょうか

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

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

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

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

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

Tora_ou

2025/06/27 08:27

「prefab」を使っていてもそれをコピーするなどして最初からヒエラルキー上に存在させていた場合は出来る事が変わらなくて [SerializeField]でオブジェクトを予め指定しておけるし全く問題無いです。 問題なのは「スクリプトでPrefabを呼び出し、生成した場合」です。 ゲーム開始時には無かったものを後から指定する方法、というのが初心者にとっては非常に難解、困難です。
Tora_ou

2025/06/27 09:15

GameObject target1 = GameObject.Find("ItemimageBig00"); でアクティブの親オブジェクトを探し出しその後、 その探し出した親オブジェクトの子オブジェクト(非アクティブ)を探す Transform target2 = target1.transform.Find("ItemImage01Big");  Debug.Log("target2(transform) = " + target2); Debug.Log("target2(gameObject) = " + target2.gameObject); ItemImageBig = target2.gameObject; ↑最後に探し出した非アクティブだった子オブジェクトを変数に入れる。 調べてここまで出来ました。Debug.Logを見ると中身もちゃんと入ってます。 しかし今度はアイテムが8種類あるので8種類を振り分ける方法がわからないです。 上のコードだとどのアイテムがスロットに表示されていようが ItemImage01Big の情報しか表示させられない。 これを アイテム1番なら ItemImage01Big を アイテム2番なら ItemImage02Big を・・・というやり方をこれから模索していきます。 アイテムslotの画像はprefabで後から生成されたものなので 強引に8種類全部を用意する、っていう強引な手段は使えないのです。
Tora_ou

2025/06/27 09:42 編集

アイテム8種類はアイテムスロットに表示する際に、enumで定義してあるのでこれを使ってswitch文で8つに分岐させれば出来そうなのでは?という所まで来ました。 しかし具体的にはどのように書けば良いのかわからないのでまだまだこれからです。 [Serializable] public class Item { public enum Type { A_Item, B_Item, C_Item, D_Item, E_Item, F_Item, G_Item, H_Item, } public Type type; //種類 public Sprite sprite; //スロットに表示する画像 これは正しく表示出来ている public Sprite BigSprite; //大きく出す画像 }
Tora_ou

2025/06/27 10:02

徐々に見えてきました。↓のコードのように書いてアイテム8種類別に取得するオブジェクトも8通り作れば行けるのではないか、と思います。まだやってないのでこれから試してみます。 public Item.Type ItemType; //enum変数の宣言 private void Awake() { switch (ItemType) { case Item.Type.A_Item,: //アイテムタイプがAの時の処理         //アイテムタイプがAの時の処理 を書く break; ・・・・・×アイテム別に8種類のcase文を作る } }
YAmaGNZ

2025/06/27 13:26

例えば class Item {   public ItemType Type;   public GameObject ItemImage;   public GameObject PushItemImage;   // その他必要な情報など } みたいなアイテム情報を格納するクラスを作って、ItemManagerみたいなスクリプトでList<Item>なものをインスペクタで設定できるようにして prefab側ではSetItem(Item item)とアイテム情報をセットして使用すればいけたりしませんかね? こういった方法であればアイテムが増えたときなどでもenumよりは拡張しやすいんじゃないでしょうか。
Tora_ou

2025/06/27 15:49

先に質問した内容で https://teratail.com/questions/twk0oiyg3lztpx#reply-rnuh8uqb2imsm8 アイテムスロットに格納することに成功したprefabの画像が有るのでのおそらくどこかにその情報を持っていると思われます。 [Serializable] public class Item { public enum Type { A_Item, B_Item, C_Item, D_Item, E_Item, F_Item, G_Item, H_Item, } public Type type; //種類 public Sprite sprite; //スロットに表示する画像 これは正しく表示出来ている public Sprite BigSprite; //大きく出す画像 } ↑のようにItemは3つの情報を持っていて public Sprite sprite の画像が先の質問でアイテムスロットに格納する事に成功した部分です public Sprite BigSprite; //大きく出す画像 も同じスロットが情報として持っているので、、、「わかっている人」ならば造作もない事だと思うのですが 私は毎度prefabになるとその部分の情報を取り出す為、指定する書き方が難しくて 色々と解説してくれているページをいくつも調べて多くの時間をかけないとまだまだ出来ないようです。 今回はなんかこう、もうちょっとの事に気が付けば出来るんじゃないか、という近くまで来ている手ごたえは感じています。まだ出来てないけど・・・
Tora_ou

2025/06/27 18:17

あれから3時間ほど自分なりに調べて試行錯誤してみますがやはりダメです しかし全く進まなかったわけではなくて、3時間かけてようやく気が付いた事があります スロットの画像はちゃんと書き換えられているのにtypeを書き換えていなかった事にようやく気が付きました ※長くなったので補足で追加しました
guest

回答1

0

ベストアンサー

ItemInfomation.csというスクリプトを作成し、アイテムの情報を格納するクラスを下記のようにし

C#

1[System.Serializable] 2public class ItemInfomation 3{ 4 public enum ItemType 5 { 6 TypeA, 7 TypeB, 8 TypeC 9 } 10 11 public int ItemNumber; // アイテムを識別する番号 12 public string ItemName; // アイテムの名称 13 public ItemType Type; // アイテムの種類(例えば武器・防具・消費アイテム等の区別とか) 14 public Sprite ItemImage; // アイテムの画像 15 public Sprite BigItemImage; // アイテムのクリック時の画像 16}

ItemManagerを作る

C#

1using UnityEngine; 2 3public class ItemManager : MonoBehaviour 4{ 5 List<ItemInfomation> itemlist = new List<ItemInfomation>(); 6 7 public Item GetItemInfomation(int itemNumber) 8 { 9 // itemlistから指定されたアイテム番号の情報を返す 10 return itemlist.Find(i => i.ItemNumber == itemNumber); 11 } 12}

これでItemManagerのほうでインスペクタからItemのリストの内容を設定できるようになるかと思います。

そしてprefab側で

C#

1private ItemInfomation item; 2private Image image ; 3 4private void Awake() 5{ 6 image = GetComponentsInChildren<Image>().Where(c => gameObject != c.gameObject).Single(); 7} 8 9public void SetItem(ItemInfomation item) 10{ 11 this.item = item; 12 UpdateImage(); 13} 14 15void UpdateImage() 16{ 17 // アイテムが空の場合は処理しない 18 if (item != null) 19 { 20 image.sprite = item.ItemImage; // アイテムの画像を表示 21 } 22} 23 24public void PointerDown() 25{ 26 // アイテムが空の場合は処理しない 27 if (item != null) 28 { 29 // 画像が押された時の処理 30 image.sprite = item.BigItemImage; // クリック時の画像に差し替え 31 } 32} 33 34public void PointerUp() 35{ 36 // アイテムが空の場合は処理しない 37 if (item != null) 38 { 39 image.sprite = item.ItemImage; // アイテムの画像を表示 40 } 41} 42

といった感じで処理をすればいいのではないかと思います。

このprefabに対してアイテムをセットする側は
ItemManagerから値を取得するといった形にするといいのではないかと思います。

C#

1 private ItemManager itemManager; 2 Slot[] slot = new Slot[10]; 3 4 void Start() 5 { 6 itemManager = GameObject.Find("ItemManager"); 7 // アイテムスロットをfrefabを使って自動で作る機能 8 for (int i=0; i < slotNumber; i++) 9 { 10 GameObject slotObj = Instantiate(slotPrefab,this.transform); 11 slot[i] = slotObj.GetComponent<Slot>(); 12 slot[i].SetItem(null); 13 } 14 } 15

アイテムをセットする場合は
slot[1].SetItem(itemManager.GetItemInfomation(3));
といった感じでセットすればいいでしょう。

上記のようにアイテム番号で管理するようにすればアイテムの増減に対しても柔軟に対応できるでしょうしいいのではないかと思います。

ただし、上記に書いたコードはUnityも使わずここで手で書いたので文法上おかしかったり動作しなかったりする可能性がありますが考え方のイメージにはなるのではないでしょうか。


image = GetComponentsInChildren<Image>().Where(c => gameObject != c.gameObject).Single();

この文ですが
分解すると以下のようになります。

C#

1Component[] images1 = GetComponentsInChildren<Image>(); 2IEnumerable<Component> images2 = images1.Where(c => gameObject != c.gameObject); 3image = images2.Single();

まずGetComponentsInChildren<Image>というのは自分以下のゲームオブジェクトから指定されたtypeのオブジェクトを全て取得するといったものになります。
自分以下のゲームオブジェクトから型がImageのものを抽出して配列に纏めてくれます。

次にWhereを使った記述ですがこの書き方はLINQと呼ばれる書き方となります。
上記の例で行くとimages1に含まれる要素が順番にcに格納されてgameObject != c.gameObjectの比較が行われます。そしてこの条件にマッチしたものがimages2にどんどん格納されていきます。

次にSingleですがこれはIEnumerableから1つの要素を取り出すものとなります。
なので1つのImageが返ってきます。

投稿2025/06/27 23:34

YAmaGNZ

総合スコア10663

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

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

Tora_ou

2025/06/28 05:45

もちろんすべてを理解出来たわけではないですがなんとなくわかってきました。 ItemNumberを設定しておいてそれを参照して、if文やswich文で区別する方法もわかりました。 丁寧に教えていただきありがとうございましす。
guest

あなたの回答

tips

太字

斜体

打ち消し線

見出し

引用テキストの挿入

コードの挿入

リンクの挿入

リストの挿入

番号リストの挿入

表の挿入

水平線の挿入

プレビュー

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

ただいまの回答率
85.30%

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

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

質問する

関連した質問