Unity - 動態Copy GameObject上的Component以及Component上面設定的value到另一個物件上

  使用Unity內建的MonoBehaviour來製作script很方便,建立一個新的繼承MonoBehaviour的class,這個物件就可以做為component放到場景的物件上,除了配置到物件上之外,這個類別裡面的public參數也會顯示在Unity的inspector中調整,在調整一些參數上很方便不需要動到code。



  什麼情況下會用到動態Copy component value,因為如果在Unity編輯下,不同物件上有相同的Component可以用Multi-select物件的方式來一齊設定數值,但如果是在遊戲運行中,動態建立一個有這個Component物件的時候就有可能需要重新設定Component上的數值,尤其動態建立的物件不是從預先製作好的prefab來產生的時候,Component上的數值都會是預設的原始數值。

  增加一個Component到物件上是使用AddComponent()的方法,如果想要複製一個物件上已經有的Component到新物件上,一般來說複製一個Component可以這樣
//先取得目標物件上的Component並取得此Component的type,這邊測試直接使用已知的type
Component source = sourceObj.GetComponent(typeof(MyClass));
System.Type type = source.GetType();
targetGameObject.AddComponent(type);



  不過如果只是這樣AddComponent的話會發現,雖然是有把Component複製到這個物件上,但是原本物件上Component設定的數值並沒有一起複製過來,這個新加到物件上的Component數值都是初始化的狀態,這個不是我想要的狀態。

  當然可以一個field一個field複製數值,但是如果field數量很多,或是後來有增減一些field,那這個一個一個field複製的方法就要同時修改,這就有點浪費時間了。

  所以這邊可以考慮的作法就是使用Reflection把所有的field數值複製過去,但是因為是用Reflection所以同時必須要考慮效率的問題,Reflection有些耗效能,這樣的方式最好不要每個frame一直呼叫
Component source = sourceObj.GetComponent(typeof(MyClass));
System.Type type = source .GetType(); //同樣先取得Component的type
Component target = targetGameObject.AddComponent(type); //先把這個類型的初始Component加到物件上
System.Reflection.FieldInfo[] fields = type.GetFields(); //使用Reflection取得此type上的所有fields
foreach(System.Reflection.FieldInfo field in fields)
{
    field.SetValue(target, field.GetValue(source)); //把來源Component上的所有field數值設定到目標Component上
}



  把這個功能做成方法,當然使用上還是有些限制,但是一般自己做的Script上面public的field應該都可以正常的複製加上去。
public void AddCopyComponent(GameObject target, Component source)
{
    System.Type type = source.GetType();
    Component copy = target.AddComponent(type);

    System.Reflection.FieldInfo[] fields = type.GetFields();
    foreach(System.Reflection.FieldInfo field in fields)
    {
        field.SetValue(target, field.GetValue(source));
    }
}


No comments:

Post a Comment