FC2ブログ
    05 «1.2.3.4.5.6.7.8.9.10.11.12.13.14.15.16.17.18.19.20.21.22.23.24.25.26.27.28.29.30.» 07

    ハルシオンシステムの気ままBlog

    株式会社ハルシオンシステムのメンバーが送る、UnityやらJavaやらの技術的話題から、自社開発のアプリの宣伝とかとかのブログです。ほんと気ままにいきたいと思います。更新日は毎週 月 木でっす!

     

    【ハルシオンブログ】Prefabから複数Instantiateしてできたオブジェクトに●●したい時のやり方。とりあえず2パターンかいてみたけど、他にもいい方法ありますか? 

    こんにちは。坂内っす。

    Prefabを使ってInstantiateしたオブジェクトの管理について。

    1つのPrefabを使って複数のオブジェクトを作った際に、指定番号(生成した順)のオブジェクトに対してアクション(消したり、処理を行ったり)をする場合のやり方。

    デジゲーでお会いした杉田さんがこんなことをつぶやいていたので、ちょっと説明。


    もう解決はしているようだけども。

    いくつかやり方があると思うのですが、僕のやりかたを2つほど紹介。

    まずは、ただ単にImageのプレハブを5個Instantiateして並べるだけのプログラム。



    [Script20181126.cs]
    using UnityEngine;

    public class Script20181126 : MonoBehaviour {

    [SerializeField, HeaderAttribute("アイテムをおくところ")]
    private Transform itemsPlace;
    [SerializeField, HeaderAttribute("アイテムプレハブ")]
    private GameObject itemPref;

    float[] itemPosiX = {-300f,-150f,0f,150f,300f };

    private void Start() {
    for(int i = 0; i < itemPosiX.Length; i++) {
    GameObject item = Instantiate(itemPref, itemsPlace, false);
    item.transform.localPosition = new Vector2(itemPosiX[i], 0f);
    }
    }
    }


    これをベースにボタンを押したら、「1番目のオブジェクトを消す」「5番目のオブジェクトの色を変える」をやってみましょう。


    【オブジェクト名での管理】
    オブジェクトに名前(番号付き)を付けて大元から色々いじったりする。

    using UnityEngine;
    using UnityEngine.UI;

    public class Script20181126 : MonoBehaviour {

    [SerializeField, HeaderAttribute("アイテムをおくところ")]
    private Transform itemsPlace;
    [SerializeField, HeaderAttribute("アイテムプレハブ")]
    private GameObject itemPref;

    float[] itemPosiX = {-300f,-150f,0f,150f,300f };

    private void Start() {
    for(int i = 0; i < itemPosiX.Length; i++) {
    GameObject item = Instantiate(itemPref, itemsPlace, false);
    item.name = "item_" + i;
    item.transform.localPosition = new Vector2(itemPosiX[i], 0f);
    }
    }

    public void OnClickButton() {
    foreach(Transform itemTran in itemsPlace) {
    if(itemTran.gameObject.name == "item_0") {
    Destroy(itemTran.gameObject);
    }
    if(itemTran.gameObject.name == "item_4") {
    itemTran.gameObject.GetComponent<Image>().color = new Color(1f,1f,0f,1f);
    }

    }
    }
    }


    あ、もちろん次にやるようにオブジェクトの方で処理とかもできますが、なんか名前等の「Stringでの判定」ってあんまりやりたくないですよね。


    【オブジェクトにもスクリプトを用意する方法】
    番号で判定させるなら、文字列よりintとかで判断したい。(大文字小文字とかで合わなかったりをなくすため)
    そして、オブジェクトがあるならそれ用のスクリプトで処理とかしたい。
    そんなあなたへ。

    Item側を触るスクリプトを1つ追加します。


    [ScriptItem.cs]
    using UnityEngine;
    using UnityEngine.UI;

    public class ScriptItem : MonoBehaviour {
    private int itemNo;
    public int ItemNo
    {
    get{ return itemNo; }
    set{ itemNo = value; }
    }

    public void InitItem(int itemNo,float posiX) {
    this.itemNo = itemNo;
    transform.localPosition = new Vector2(posiX,0f);
    }

    public void DestroyItem() {
    Destroy(gameObject);
    }

    public void ChangeColor() {
    GetComponent<Image>().color = new Color(1f,1f,0f,1f);
    }
    }


    [Script20181126.cs]
    using UnityEngine;
    using UnityEngine.UI;

    public class Script20181126 : MonoBehaviour {

    [SerializeField, HeaderAttribute("アイテムをおくところ")]
    private Transform itemsPlace;
    [SerializeField, HeaderAttribute("アイテムプレハブ")]
    private GameObject itemPref;

    float[] itemPosiX = {-300f,-150f,0f,150f,300f };

    private void Start() {
    for(int i = 0; i < itemPosiX.Length; i++) {
    GameObject itemObject = Instantiate(itemPref, itemsPlace, false);
    ScriptItem item = itemObject.GetComponent<ScriptItem>();
    item.InitItem(i, itemPosiX[i]);

    }
    }

    public void OnClickButton() {
    foreach(Transform itemTran in itemsPlace) {
    ScriptItem item = itemTran.gameObject.GetComponent<ScriptItem>();
    if(item.ItemNo == 0) {
    item.DestroyItem();
    }
    if(item.ItemNo == 4) {
    item.ChangeColor();
    }

    }
    }
    }

    こっちの方がスッキリしますよね?

    ってことで、作ったオブジェクトへのアクションについてでした。あでゅ~ノシ

    ーーーーーーーーーーーーーーーーーーーーーーーーーーーーーーーーーーーーーーーーーー
    2018/11/28 追記 コメントにより、最適解?

    [Script20181126.cs]
    using System.Collections.Generic;
    using UnityEngine;
    using UnityEngine.UI;

    public class Script20181126 : MonoBehaviour {

    [SerializeField, HeaderAttribute("アイテムをおくところ")]
    private Transform itemsPlace;
    [SerializeField, HeaderAttribute("アイテムプレハブ")]
    private GameObject itemPref;

    private List<ScriptItem> itemList = new List<ScriptItem>();

    float[] itemPosiX = {-300f,-150f,0f,150f,300f };

    private void Start() {
    for(int i = 0; i < itemPosiX.Length; i++) {
    GameObject itemObject = Instantiate(itemPref, itemsPlace, false);
    ScriptItem item = itemObject.GetComponent<ScriptItem>();
    item.InitItem(i, itemPosiX[i]);
    itemList.Add(item);
    }
    }

    public void OnClickButton() {
    itemList[0].DestroyItem();
    itemList[4].ChangeColor();

    }
    }


    あ。たしかにいつもこうやってるわ。

    Category: 開発日記(Unity)

    tb 0 : cm 2   

    コメント

    きちんとやるなら、生成側にList作って、そちらに詰め込んだほうが良いです。
    GetComponentはコストが高いですし、Transformの子要素を順に見ていくのは
    別の場所からTransformいじられてたら破綻します。

    Transformがいじられてない保証があるならtransform.GetChild(index)で取得するのが簡単です。
    子要素がHierachy上で上にあるものから順に0,1,2と降られていきます。(Instantiateの生成順と同じ)

    後、Object名での管理はUnityEngine.Object.nameにアクセスするだけでGC発生させちゃうらしいので、基本的にはやらないほうが良いです。

    しろくろ #- | URL | 2018/11/27 20:13 [edit]

    Re: タイトルなし

    しろくろさん
    コメントありがとー!
    さすがしろくろさんや!

    もちろん別場所からのTransform触れるのはない体ですね!

    「UnityEngine.Object.nameにアクセスするだけでGC発生させちゃうらしいので」
    これは知らなかった!
    まぁ名前でアクセスの方は、むかーしやったことがある方法で、今はやってないので、大丈夫ですけどね!(じゃぁ書くなと)


    > きちんとやるなら、生成側にList作って、そちらに詰め込んだほうが良いです。
    > GetComponentはコストが高いですし、Transformの子要素を順に見ていくのは
    > 別の場所からTransformいじられてたら破綻します。
    >
    > Transformがいじられてない保証があるならtransform.GetChild(index)で取得するのが簡単です。
    > 子要素がHierachy上で上にあるものから順に0,1,2と降られていきます。(Instantiateの生成順と同じ)
    >
    > 後、Object名での管理はUnityEngine.Object.nameにアクセスするだけでGC発生させちゃうらしいので、基本的にはやらないほうが良いです。

    株式会社ハルシオンシステム #- | URL | 2018/11/28 09:59 [edit]

    コメントの投稿

    Secret

    トラックバック

    トラックバックURL
    →http://halcyonsystemblog.jp/tb.php/557-5d6353dd
    この記事にトラックバックする(FC2ブログユーザー)