Skip to content

Instantly share code, notes, and snippets.

@umiyuki
Last active March 27, 2020 12:14
Show Gist options
  • Save umiyuki/07eef082d1fa6cc5e1e1a1745b748b3f to your computer and use it in GitHub Desktop.
Save umiyuki/07eef082d1fa6cc5e1e1a1745b748b3f to your computer and use it in GitHub Desktop.
キャラクターモデル差し替えする時にモデルの中の階層についてるコンポーネントとかを新しいモデルに貼り直すヤツ
using System.Collections;
using System.Collections.Generic;
using UnityEngine;
using UnityEditor;
using UnityEditorInternal;
using System.Linq;
using System.Reflection;
//オブジェクトのコンポーネントを別の奴にコピーする
public class CopyTransformComponents : ScriptableWizard
{
public Transform fromTransform;
public Transform toTransform;
[MenuItem("Utils/CopyTransformComponents")]
static void Open()
{
DisplayWizard<CopyTransformComponents>("CopyTransformComponents");
}
//実行
void OnWizardCreate()
{
if (fromTransform != null && toTransform != null)
{
Execute();
}
else
{
if (fromTransform == null)
{
Debug.Log("fromTransform == null");
}
if (toTransform == null)
{
Debug.Log("toTransform == null");
}
}
}
void Execute()
{
//to側に無いオブジェクトはfromからコピーしてくる。あればコンポーネントのコピー
ProcessTransform(fromTransform, toTransform);
}
static void CopyComponents(GameObject from, GameObject to)
{
//var currentGameObject = Selection.activeGameObject;
var components = from.GetComponents<Component>();
var targetComponents = to.GetComponents<Component>();
Dictionary<System.Type, int> currentComponentCount = new Dictionary<System.Type, int>();
foreach (var component in components)
{
if (component is SkinnedMeshRenderer)//skinnedMeshRendererはスキップ
{ continue;}
var componentCount = targetComponents.Count(c => c.GetType() == component.GetType());
ComponentUtility.CopyComponent(component);
if (componentCount == 0)
{
ComponentUtility.PasteComponentAsNew(to);
}
else if (componentCount == 1)
{
var targetComponent = targetComponents.First(c => c.GetType() == component.GetType());
ComponentUtility.PasteComponentValues(targetComponent);
}
else
{
if (currentComponentCount.ContainsKey(component.GetType()) == false)
{
currentComponentCount.Add(component.GetType(), 0);
}
var count = currentComponentCount[component.GetType()];
var targetComponentsWithType = targetComponents.Where(c => c.GetType() == component.GetType());
if (count < targetComponentsWithType.Count())
{
var targetComponent = targetComponents.Where(c => c.GetType() == component.GetType()).ElementAt(count);
currentComponentCount[component.GetType()] += 1;
ComponentUtility.PasteComponentValues(targetComponent);
}
else
{
ComponentUtility.PasteComponentAsNew(to);
}
}
}
}
void ProcessTransform(Transform from, Transform to)
{
//コンポーネント全部コピー(上書き)
CopyComponents(from.gameObject, to.gameObject);
//Transform、GameObjectの参照を差し替える
ProcessReflection(from, to);
//子供に対して同様の処理
for (int i = 0; i < from.childCount; i++)
{
var fromObject = from.GetChild(i);
var fromName = fromObject.name;
//toの子供に同じ名前のtransformあるか?
bool findFlag = false;
for (int j = 0; j < to.childCount; j++)
{
var toObject = to.GetChild(j);
if (toObject.name == fromName)
{
ProcessTransform(fromObject, toObject);
findFlag = true;
break;//次へ
}
}
if (!findFlag)//見つからなかったらオブジェクトごとコピー
{
var newObj = GameObject.Instantiate(fromObject.gameObject, to);
newObj.name = fromObject.name;
ProcessTransform(fromObject, newObj.transform);
}
}
}
//Breadth-first search
public Transform FindDeepChild(Transform aParent, string aName)
{
var result = aParent.Find(aName);
if (result != null)
return result;
foreach (Transform child in aParent)
{
result = FindDeepChild(child,aName);
if (result != null)
return result;
}
return null;
}
void ProcessReflection(Transform from, Transform to)
{
var fromComponents = from.GetComponents<Component>();
for (int i = 0; i < fromComponents.Length; i++) //全コンポーネントについて
{
var fromType = fromComponents[i].GetType();
//Debug.Log(fromType);
var toComponent = to.GetComponent(fromType);
if (toComponent == null)
{
//Debug.Log(toComponent + "==null");
continue;
}
//フィールドを取得する
MemberInfo[] members = fromType.GetMembers(
BindingFlags.Public | BindingFlags.NonPublic |
BindingFlags.Instance );
//Debug.Log(members);
foreach (var m in members)
{
if (m.MemberType != MemberTypes.Field)
{
continue;
}
System.Type fieldType = ((FieldInfo)m).FieldType;
//transformとgameobjectを差し替える
if (fieldType == typeof(Transform) || fieldType == typeof(GameObject))
{
string targetName;//差し替えるtransformの名前
FieldInfo field = fromType.GetField(m.Name, BindingFlags.Public | BindingFlags.Instance | BindingFlags.NonPublic);
if (fieldType == typeof(Transform))
{
Transform t = (Transform)field.GetValue(fromComponents[i]);
if (t == null)
{
continue;
}
targetName = t.name;
}
else if (fieldType == typeof(GameObject))
{
GameObject obj = (GameObject)field.GetValue(fromComponents[i]);
if (obj == null)
{
continue;
}
targetName = obj.name;
}
else
{
continue;
}
//toObjectから同名オブジェクトサーチ
var targetTransform = FindDeepChild(toTransform, targetName);
if (targetTransform != null)
{
FieldInfo setField = fromType.GetField(m.Name, BindingFlags.Public | BindingFlags.Instance | BindingFlags.NonPublic);
if (setField == null)
{
Debug.Log("setField == null:" + m.Name);
}
else
{
if (fieldType == typeof(Transform))
{
setField.SetValue(toComponent, targetTransform);//セット
}
else if (fieldType == typeof(GameObject))
{
setField.SetValue(toComponent, targetTransform.gameObject);//セット
}
}
}
}
else if (fieldType == typeof(Transform[]))
{
string[] targetNames;//差し替えるtransformの名前
FieldInfo field = fromType.GetField(m.Name, BindingFlags.Public | BindingFlags.Instance | BindingFlags.NonPublic);
Transform[] t = (Transform[])field.GetValue(fromComponents[i]);
if (t == null)
{
continue;
}
targetNames = new string[t.Length];
for (int j = 0; j < t.Length; j++)
{
if (t[j] == null)
{
targetNames[j] = null;
}
else
{
targetNames[j] = t[j].name;
}
}
Transform[] newTransformArray = new Transform[t.Length];
for (int j = 0; j < t.Length; j++)
{
if (targetNames[j] == null)
{
continue;
}
//toObjectから同名オブジェクトサーチ
var targetTransform = FindDeepChild(toTransform, targetNames[j]);
if (targetTransform != null)
{
newTransformArray[j] = targetTransform;
}
}
FieldInfo setField = fromType.GetField(m.Name, BindingFlags.Public | BindingFlags.Instance | BindingFlags.NonPublic);
if (setField == null)
{
Debug.Log("setField == null:" + m.Name);
}
else
{
setField.SetValue(toComponent, newTransformArray);//セット
}
}
else if (fieldType == typeof(GameObject[]))
{
string[] targetNames;//差し替えるtransformの名前
FieldInfo field = fromType.GetField(m.Name, BindingFlags.Public | BindingFlags.Instance | BindingFlags.NonPublic);
GameObject[] t = (GameObject[])field.GetValue(fromComponents[i]);
if (t == null)
{
continue;
}
targetNames = new string[t.Length];
for (int j = 0; j < t.Length; j++)
{
if (t[j] == null)
{
targetNames[j] = null;
}
else
{
targetNames[j] = t[j].name;
}
}
GameObject[] newArray = new GameObject[t.Length];
for (int j = 0; j < t.Length; j++)
{
if (targetNames[j] == null)
{
continue;
}
//toObjectから同名オブジェクトサーチ
var targetTransform = FindDeepChild(toTransform, targetNames[j]);
if (targetTransform != null)
{
newArray[j] = targetTransform.gameObject;
}
}
FieldInfo setField = fromType.GetField(m.Name, BindingFlags.Public | BindingFlags.Instance | BindingFlags.NonPublic);
if (setField == null)
{
Debug.Log("setField == null:" + m.Name);
}
else
{
setField.SetValue(toComponent, newArray);//セット
}
}
}
}
}
}
Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment