Search Unity

  1. We are migrating the Unity Forums to Unity Discussions. On July 12, the Unity Forums will become read-only.

    Please, do not make any changes to your username or email addresses at id.unity.com during this transition time.

    It's still possible to reply to existing private message conversations during the migration, but any new replies you post will be missing after the main migration is complete. We'll do our best to migrate these messages in a follow-up step.

    On July 15, Unity Discussions will become read-only until July 18, when the new design and the migrated forum contents will go live.


    Read our full announcement for more information and let us know if you have any questions.

copy components in hierarcy - editor script

Discussion in 'Made With Unity' started by vlk2, Aug 15, 2010.

  1. vlk2

    vlk2

    Joined:
    Nov 4, 2009
    Posts:
    43
    This script copies colliders, rigidbodies, scripts, animations, and character joints from an object hierarcy to an other hierarchy.

    The child object names in the 2 hierarcy must be the same to copy. If the two hierarcy are not the same, it tries it anyway, but it will copy stuff only into objects that are the same name. The root object names can be different. It removes the components if copying of component type is allowed.

    This script can be useful if you have a character with a script and character controller, and you upload a new model, and you just copy everything from old model to the new one.
    Or if you have a fine-tuned rigidbody for one model, then you want to copy the rigidbody angles and joints and colliders into an other model.

    It recognises relative transform/object/rigidbody in scripts and joints, so the connected body of the copy will be on the copy hierarcy, not at the original. (the copy neck connected body will point at the copy spine, not the original spine)

    It doesn't supports light, particles, hinge joint, mesh renderers etc... but you can build these in, i needed only at the state as it is now. Maybe i'll update it later.

    To setup: create an "Editor" folder in the project tab, make a new javascript, named "CopyComponents", and put this code in it.

    It is under the component/custom/copy components

    I looked around and found no public script like this, i hope it will help others too :) everybody can use it, and modify it, no permission needed.

    Code (csharp):
    1. import System.Reflection;
    2.  
    3. class CopyComponents extends EditorWindow {
    4. private var fromTrans:Transform;
    5. private var toTrans:Transform;
    6. var anims = false;
    7. var physics = true;
    8. var scripts = true;
    9.  
    10. private var errorMsg:String;
    11.  
    12. @MenuItem ("Component/Custom/Copy components")
    13. static function Init () {
    14.     var window : CopyComponents = EditorWindow.GetWindow (CopyComponents);
    15.     window.Show ();
    16. }
    17.  
    18. function OnGUI () {
    19.     EditorGUILayout.Space();
    20.     EditorGUILayout.Space();
    21.     fromTrans = EditorGUILayout.ObjectField("From: ",fromTrans,Transform);
    22.     toTrans = EditorGUILayout.ObjectField("To: ",toTrans,Transform);
    23.     EditorGUILayout.Space();
    24.     EditorGUILayout.BeginHorizontal ();
    25.     GUILayout.Label ("With animations");
    26.     anims = EditorGUILayout.Toggle (anims);
    27.     EditorGUILayout.EndHorizontal ();
    28.     EditorGUILayout.BeginHorizontal ();
    29.     GUILayout.Label ("With physics+joints");
    30.     physics = EditorGUILayout.Toggle (physics);
    31.     EditorGUILayout.EndHorizontal ();
    32.     EditorGUILayout.BeginHorizontal ();
    33.     GUILayout.Label ("With scripts+controller");
    34.     scripts = EditorGUILayout.Toggle (scripts);
    35.     EditorGUILayout.EndHorizontal ();
    36.     EditorGUILayout.Space();
    37.     EditorGUILayout.Space();
    38.     errorMsg="";
    39.     if (!fromTrans)
    40.         errorMsg+="\"From\" not yet set!";
    41.     if (!toTrans)
    42.         errorMsg+=" \n\"To\" not yet set!";
    43.     if (fromTrans&toTrans){
    44.         if (!checkChildrenRecurse(fromTrans,toTrans,"")){
    45.             GUILayout.Label ("Warning: ", EditorStyles.boldLabel);
    46.         }
    47.         if (errorMsg!=""){
    48.             GUILayout.Label(errorMsg);
    49.         }
    50.         EditorGUILayout.BeginHorizontal ();
    51.         EditorGUILayout.Space();
    52.         if (GUILayout.Button ("Copy!")){
    53.             copyComponentsRecurse(fromTrans,toTrans,fromTrans,toTrans);
    54.         }
    55.         EditorGUILayout.Space();
    56.         EditorGUILayout.EndHorizontal ();
    57.     }
    58.     else
    59.     {
    60.         if (errorMsg!=""){
    61.             GUILayout.Label ("Warning: ", EditorStyles.boldLabel);
    62.             GUILayout.Label(errorMsg);
    63.         }
    64.     }
    65. }
    66. }
    67.  
    68. function copyComponentsRecurse (src : Transform,  dst : Transform, originalSrc : Transform,  originalDst : Transform)
    69. {
    70.     //Delete stuff from destination
    71.    
    72.     dst.tag=src.tag;
    73.     dst.gameObject.layer=src.gameObject.layer;
    74.    
    75.     var toComps:Component[] = dst.GetComponents(Component);
    76.     for (var dstComponent:Component in toComps){
    77.         if (dstComponent.GetType()==Animation&anims)
    78.             DestroyImmediate(dstComponent);
    79.         else if (dstComponent.GetType()==Rigidbody&physics){
    80.             if (!dst.GetComponent(CharacterJoint))
    81.                 DestroyImmediate(dstComponent);
    82.         }
    83.         else if (dstComponent.GetType()==BoxCollider&physics)
    84.             DestroyImmediate(dstComponent);
    85.         else if (dstComponent.GetType()==SphereCollider&physics)
    86.             DestroyImmediate(dstComponent);
    87.         else if (dstComponent.GetType()==CapsuleCollider&physics)
    88.             DestroyImmediate(dstComponent);
    89.         else if (dstComponent.GetType()==MeshCollider&physics)
    90.             DestroyImmediate(dstComponent);
    91.         else if (dstComponent.GetType()==CharacterController&scripts)
    92.             DestroyImmediate(dstComponent);
    93.         else if (dstComponent.GetType()==CharacterJoint&physics)
    94.             DestroyImmediate(dstComponent);
    95.         else if (dstComponent.GetType().BaseType==MonoBehaviour&scripts)
    96.             DestroyImmediate(dstComponent);
    97.     }
    98.    
    99.     //Copy stuff from source to destination
    100.     var copyComps:Component[] = src.GetComponents(Component);
    101.     for (var srcComponent:Component in copyComps){
    102.         if (srcComponent.GetType()==Animation&anims){
    103.             var new_animation:Animation= dst.gameObject.AddComponent(Animation);
    104.             var helpsource:Animation=srcComponent;
    105.             for (var state : AnimationState in helpsource)
    106.             {
    107.                 new_animation.AddClip(helpsource[state.name].clip, state.name);
    108.             }
    109.             new_animation.clip=helpsource.clip;
    110.             new_animation.playAutomatically = helpsource.playAutomatically;
    111.             new_animation.animatePhysics = helpsource.animatePhysics;
    112.             new_animation.animateOnlyIfVisible = helpsource.animateOnlyIfVisible;
    113.         }
    114.         else if (srcComponent.GetType()==Rigidbody&physics){
    115.             //var ialreadyhavethis:Rigidbody=dst.GetComponent(Rigidbody);
    116.             var new_rigid:Rigidbody=dst.GetComponent(Rigidbody);
    117.             if (!new_rigid)
    118.                 new_rigid= dst.gameObject.AddComponent(Rigidbody);
    119.             var helpsource2:Rigidbody=srcComponent;
    120.             new_rigid.mass=helpsource2.mass;
    121.             new_rigid.drag=helpsource2.drag;
    122.             new_rigid.angularDrag=helpsource2.angularDrag;
    123.             new_rigid.useGravity=helpsource2.useGravity;
    124.             new_rigid.isKinematic=helpsource2.isKinematic;
    125.             new_rigid.interpolation=helpsource2.interpolation;
    126.             new_rigid.freezeRotation=helpsource2.freezeRotation;
    127.         }
    128.         else if (srcComponent.GetType()==BoxCollider&physics){
    129.             var new_box:BoxCollider= dst.gameObject.AddComponent(BoxCollider);
    130.             var helpsource3:BoxCollider=srcComponent;
    131.             new_box.material=helpsource3.material;
    132.             new_box.isTrigger=helpsource3.isTrigger;
    133.             new_box.size=helpsource3.size;
    134.             new_box.center=helpsource3.center;
    135.         }
    136.         else if (srcComponent.GetType()==SphereCollider&physics){
    137.             var new_sphere:SphereCollider= dst.gameObject.AddComponent(SphereCollider);
    138.             var helpsource4:SphereCollider=srcComponent;
    139.             new_sphere.material=helpsource4.material;
    140.             new_sphere.isTrigger=helpsource4.isTrigger;
    141.             new_sphere.radius=helpsource4.radius;
    142.             new_sphere.center=helpsource4.center;
    143.         }
    144.         else if (srcComponent.GetType()==CapsuleCollider&physics){
    145.             var new_capsule:CapsuleCollider= dst.gameObject.AddComponent(CapsuleCollider);
    146.             var helpsource5:CapsuleCollider=srcComponent;
    147.             new_capsule.material=helpsource5.material;
    148.             new_capsule.isTrigger=helpsource5.isTrigger;
    149.             new_capsule.radius=helpsource5.radius;
    150.             new_capsule.height=helpsource5.height;
    151.             new_capsule.direction=helpsource5.direction;
    152.             new_capsule.center=helpsource5.center;
    153.         }
    154.         else if (srcComponent.GetType()==CharacterController&scripts){
    155.             var new_characterC:CharacterController= dst.GetComponent(CharacterController);
    156.             if (!new_characterC)
    157.                 new_characterC=dst.gameObject.AddComponent(CharacterController);
    158.             var helpsource6:CharacterController=srcComponent;
    159.             new_characterC.height=helpsource6.height;
    160.             new_characterC.radius=helpsource6.radius;
    161.             new_characterC.slopeLimit=helpsource6.slopeLimit;
    162.             new_characterC.stepOffset=helpsource6.stepOffset;
    163.             new_characterC.center=helpsource6.center;
    164.         }
    165.         else if (srcComponent.GetType()==CharacterJoint&physics){
    166.             var new_joint:CharacterJoint= dst.gameObject.AddComponent(CharacterJoint);
    167.             var helpsource7:CharacterJoint=srcComponent;
    168.             if (helpsource7.connectedBody!=null){
    169.                 if (helpsource7.connectedBody.transform.IsChildOf(originalSrc))
    170.                 {
    171.                     var myPath4:String="";
    172.                     var thisIsMe4:Transform=helpsource7.connectedBody.transform;
    173.                     while(thisIsMe4.rigidbody!=originalSrc.rigidbody) {
    174.                         if (myPath4=="") myPath4=thisIsMe4.name;
    175.                         else myPath4=thisIsMe4.name+"/"+myPath4;
    176.                         thisIsMe4=thisIsMe4.parent;
    177.                     }
    178.                     var relativeValue4:Transform=originalDst.Find(myPath4);
    179.                     if (relativeValue4)
    180.                         new_joint.connectedBody=relativeValue4.rigidbody;
    181.                     else if (helpsource7.connectedBody==originalSrc.rigidbody){
    182.                         new_joint.connectedBody=originalDst.rigidbody;
    183.                     }
    184.                     else{
    185.                         new_joint.connectedBody=helpsource7.connectedBody;
    186.                     }
    187.                 }
    188.                 else
    189.                     new_joint.connectedBody=helpsource7.connectedBody;
    190.             }
    191.             else
    192.                 new_joint.connectedBody=helpsource7.connectedBody;
    193.                
    194.             new_joint.anchor=helpsource7.anchor;
    195.             new_joint.axis=helpsource7.axis;
    196.             new_joint.swingAxis=helpsource7.swingAxis;
    197.             new_joint.lowTwistLimit=helpsource7.lowTwistLimit;
    198.             new_joint.highTwistLimit=helpsource7.highTwistLimit;
    199.             new_joint.swing1Limit=helpsource7.swing1Limit;
    200.             new_joint.swing2Limit=helpsource7.swing2Limit;
    201.             new_joint.breakForce=helpsource7.breakForce;
    202.             new_joint.breakTorque=helpsource7.breakTorque;
    203.         }
    204.         //if its a script
    205.         else if (srcComponent.GetType().BaseType==MonoBehaviour&scripts){
    206.             var new_script = dst.gameObject.AddComponent(srcComponent.GetType());
    207.             for(var f: FieldInfo in srcComponent.GetType().GetFields())
    208.             {
    209.                 //if the value in the script is a gameObject, and something is assigned to it...
    210.                 if (f.GetValue(srcComponent)!=null){
    211.                     if (f.GetValue(srcComponent).GetType()==GameObject){
    212.                         //if the value is a child of the original source, so in the same hierarcy,
    213.                         //then we should find the same object in the destination, and set that one
    214.                         //because if the value points to my head, i dont want my clone's value to point to my head too
    215.                         //i want it to point to its own head.
    216.                         if (f.GetValue(srcComponent).transform.IsChildOf(originalSrc))
    217.                         {
    218.                             var myPath:String="";
    219.                             var thisIsMe:GameObject=f.GetValue(srcComponent);
    220.                             while(thisIsMe!=originalSrc.gameObject) {
    221.                                 if (myPath=="") myPath=thisIsMe.name;
    222.                                 else myPath=thisIsMe.name+"/"+myPath;
    223.                                 thisIsMe=thisIsMe.transform.parent.gameObject;
    224.                             }
    225.                             var relativeValue:Transform=originalDst.Find(myPath);
    226.                             if (relativeValue)
    227.                                 f.SetValue(new_script, relativeValue.gameObject);
    228.                             else if (f.GetValue(srcComponent)==originalSrc.gameObject){
    229.                                 f.SetValue(new_script, originalDst.gameObject);
    230.                             }
    231.                             else{
    232.                                 f.SetValue(new_script, f.GetValue(srcComponent));
    233.                             }
    234.                         }
    235.                         else
    236.                             f.SetValue(new_script, f.GetValue(srcComponent));
    237.                     }
    238.                     else if (f.GetValue(srcComponent).GetType()==Transform){
    239.                         //same as at the gameobject
    240.                         if (f.GetValue(srcComponent).IsChildOf(originalSrc))
    241.                         {
    242.                             var myPath2:String="";
    243.                             var thisIsMe2:Transform=f.GetValue(srcComponent);
    244.                             while(thisIsMe2!=originalSrc) {
    245.                                 if (myPath2=="") myPath2=thisIsMe2.name;
    246.                                 else myPath2=thisIsMe2.name+"/"+myPath2;
    247.                                 thisIsMe2=thisIsMe2.parent;
    248.                             }
    249.                             var relativeValue2:Transform=originalDst.Find(myPath2);
    250.                             if (relativeValue2)
    251.                                 f.SetValue(new_script, relativeValue2);
    252.                             else if (f.GetValue(srcComponent)==originalSrc){
    253.                                 f.SetValue(new_script, originalDst);
    254.                             }
    255.                             else{
    256.                                 f.SetValue(new_script, f.GetValue(srcComponent));
    257.                             }
    258.                         }
    259.                         else
    260.                             f.SetValue(new_script, f.GetValue(srcComponent));
    261.                     }
    262.                     else if (f.GetValue(srcComponent).GetType()==Rigidbody){
    263.                         //if the value is a child of the original source, so in the same hierarcy,
    264.                         //then we should find the same object in the destination, and set that one
    265.                         //because if the value points to my head, i dont want my clone's value to point to my head too
    266.                         //i want it to point to its own head.
    267.                         if (f.GetValue(srcComponent).transform.IsChildOf(originalSrc))
    268.                         {
    269.                             var myPath3:String="";
    270.                             var thisIsMe3:Transform=f.GetValue(srcComponent).transform;
    271.                             while(thisIsMe3.rigidbody!=originalSrc.rigidbody) {
    272.                                 if (myPath3=="") myPath3=thisIsMe3.name;
    273.                                 else myPath3=thisIsMe3.name+"/"+myPath3;
    274.                                 thisIsMe3=thisIsMe3.parent;
    275.                             }
    276.                             var relativeValue3:Transform=originalDst.Find(myPath3);
    277.                             if (relativeValue3)
    278.                                 f.SetValue(new_script, relativeValue3.rigidbody);
    279.                             else if (f.GetValue(srcComponent)==originalSrc.rigidbody){
    280.                                 f.SetValue(new_script, originalDst.rigidbody);
    281.                             }
    282.                             else{
    283.                                 f.SetValue(new_script, f.GetValue(srcComponent));
    284.                             }
    285.                         }
    286.                         else
    287.                             f.SetValue(new_script, f.GetValue(srcComponent));
    288.                     }
    289.                     else {
    290.                         f.SetValue(new_script, f.GetValue(srcComponent));
    291.                     }
    292.                 }
    293.                 else {
    294.                     f.SetValue(new_script, f.GetValue(srcComponent));
    295.                 }
    296.             }
    297.         }
    298.     }
    299.    
    300.     //make the recurse thingy
    301.     for (var child : Transform in src) {
    302.         var curDst : Transform = dst.Find(child.name);
    303.         if (curDst){
    304.             copyComponentsRecurse(child, curDst, originalSrc, originalDst);
    305.         }
    306.     }
    307. }
    308.  
    309. function checkChildrenRecurse (src : Transform,  dst : Transform, srcPath:String) : boolean
    310. {
    311.     if (src.childCount!=dst.childCount){
    312.         errorMsg="Child count of "+srcPath+src.gameObject.name+" in \"From\" is not equal to "+dst.gameObject.name+" in \"To\".\n";
    313.         return false;
    314.     }
    315.     else if (src.childCount>0)
    316.     {
    317.         var okay:boolean=true;
    318.         for (var child : Transform in src) {
    319.             var curDst : Transform = dst.Find(child.name);
    320.             if (curDst){
    321.                 if (!checkChildrenRecurse(child, curDst, srcPath+child.gameObject.name+"\\"))
    322.                 {
    323.                     okay=false;
    324.                 }
    325.             }
    326.             else{
    327.                 errorMsg="Can't find "+src.gameObject.name+"\\"+srcPath+child.gameObject.name+" in \"To\"\n";
    328.                 return false;
    329.             }
    330.         }
    331.         return okay;
    332.     }
    333.     else{
    334.         return true;
    335.     }
    336. }
     

    Attached Files:

    alaskanpreston likes this.
  2. Ony

    Ony

    Joined:
    Apr 26, 2009
    Posts:
    1,978
    Nice. Definitely something that will come in handy, thanks!
     
  3. sirdavid23

    sirdavid23

    Joined:
    Jan 26, 2011
    Posts:
    22
    This is an awesome script, @vlk2
    Does it still work in unity 2019.4?