SHARE
TWEET

Editor/CustomTransformComponent.cs

napland Aug 19th, 2016 (edited) 60 Never
Not a member of Pastebin yet? Sign Up, it unlocks many cool features!
  1. using UnityEngine;
  2. using UnityEditor;
  3. using UnityEditor.AnimatedValues; //used for "Special Operations" fade group
  4.  
  5. [CustomEditor(typeof(Transform))]
  6. [CanEditMultipleObjects]
  7. public class CustomTransformComponent : Editor
  8. {
  9.     private Transform _transform;
  10.     private GUILayoutOption layoutMaxWidth = null;
  11.     public override void OnInspectorGUI()
  12.     {
  13.         if (layoutMaxWidth == null)
  14.             layoutMaxWidth = GUILayout.MaxWidth(600);
  15.            
  16.         //We need this for all OnInspectorGUI sub methods
  17.         _transform = (Transform)target;
  18.  
  19.         StandardTransformInspector();
  20.  
  21.         QuaternionInspector();
  22.        
  23.         ShowLocalAxisComponentToggle();
  24.  
  25.         SpecialOperations();
  26.     }
  27.  
  28.  
  29.     private void StandardTransformInspector()
  30.     {
  31.         bool didPositionChange = false;
  32.         bool didRotationChange = false;
  33.         bool didScaleChange = false;
  34.  
  35.         // Watch for changes.
  36.         //  1)  Float values are imprecise, so floating point error may cause changes
  37.         //      when you've not actually made a change.
  38.         //  2)  This allows us to also record an undo point properly since we're only
  39.         //      recording when something has changed.
  40.  
  41.         // Store current values for checking later
  42.         Vector3 initialLocalPosition = _transform.localPosition;
  43.         Vector3 initialLocalEuler = _transform.localEulerAngles;
  44.         Vector3 initialLocalScale = _transform.localScale;
  45.  
  46.         EditorGUI.BeginChangeCheck();
  47.         Vector3 localPosition = EditorGUILayout.Vector3Field("Position", _transform.localPosition, layoutMaxWidth);
  48.         if (EditorGUI.EndChangeCheck())
  49.             didPositionChange = true;
  50.  
  51.         EditorGUI.BeginChangeCheck();
  52.         Vector3 localEulerAngles = EditorGUILayout.Vector3Field(
  53.             "Euler Rotation",
  54.             _transform.localEulerAngles,
  55.             layoutMaxWidth);
  56.  
  57.         if (EditorGUI.EndChangeCheck())
  58.             didRotationChange = true;
  59.  
  60.         EditorGUI.BeginChangeCheck();
  61.         Vector3 localScale = EditorGUILayout.Vector3Field("Scale", _transform.localScale, layoutMaxWidth);
  62.         if (EditorGUI.EndChangeCheck())
  63.             didScaleChange = true;
  64.  
  65.         // Apply changes with record undo
  66.         if (didPositionChange || didRotationChange || didScaleChange)
  67.         {
  68.             Undo.RecordObject(_transform, _transform.name);
  69.  
  70.             if (didPositionChange)
  71.                 _transform.localPosition = localPosition;
  72.  
  73.             if (didRotationChange)
  74.                 _transform.localEulerAngles = localEulerAngles;
  75.  
  76.             if (didScaleChange)
  77.                 _transform.localScale = localScale;
  78.  
  79.         }
  80.  
  81.         // Since BeginChangeCheck only works on the selected object
  82.         // we need to manually apply transform changes to all selected objects.
  83.         Transform[] selectedTransforms = Selection.transforms;
  84.         if (selectedTransforms.Length > 1)
  85.         {
  86.             foreach (var item in selectedTransforms)
  87.             {
  88.                 if (didPositionChange || didRotationChange || didScaleChange)
  89.                     Undo.RecordObject(item, item.name);
  90.  
  91.                 if (didPositionChange)
  92.                 {
  93.                     item.localPosition = ApplyChangesOnly(
  94.                         item.localPosition, initialLocalPosition, _transform.localPosition);
  95.                 }
  96.  
  97.                 if (didRotationChange)
  98.                 {
  99.                     item.localEulerAngles = ApplyChangesOnly(
  100.                         item.localEulerAngles, initialLocalEuler, _transform.localEulerAngles);
  101.                 }
  102.  
  103.                 if (didScaleChange)
  104.                 {
  105.                     item.localScale = ApplyChangesOnly(
  106.                         item.localScale, initialLocalScale, _transform.localScale);
  107.                 }
  108.                
  109.             }
  110.         }
  111.     }
  112.  
  113.     private Vector3 ApplyChangesOnly(Vector3 toApply, Vector3 initial, Vector3 changed)
  114.     {
  115.         if (!Mathf.Approximately(initial.x, changed.x))
  116.             toApply.x = _transform.localPosition.x;
  117.  
  118.         if (!Mathf.Approximately(initial.y, changed.y))
  119.             toApply.y = _transform.localPosition.y;
  120.  
  121.         if (!Mathf.Approximately(initial.z, changed.z))
  122.             toApply.z = _transform.localPosition.z;
  123.  
  124.         return toApply;
  125.     }
  126.    
  127.  
  128.  
  129.     private static bool quaternionFoldout = false;
  130.     private void QuaternionInspector()
  131.     {
  132.        
  133.         //Additional element to also view the Quaternion rotation values
  134.         quaternionFoldout = EditorGUILayout.Foldout(quaternionFoldout, "Quaternion Rotation:    " + _transform.localRotation.ToString("F3"));
  135.         if (quaternionFoldout)
  136.         {
  137.             Vector4 q = QuaternionToVector4(_transform.localRotation);
  138.             EditorGUI.BeginChangeCheck();
  139.             //EditorGUILayout.Vector3Field("Be careful!", Vector3.one);
  140.             GUILayout.Label("Be careful!");
  141.             EditorGUILayout.BeginHorizontal(layoutMaxWidth);
  142.             GUILayout.Label("X");
  143.             q.x = EditorGUILayout.FloatField(q.x);
  144.             GUILayout.Label("Y");
  145.             q.y = EditorGUILayout.FloatField(q.y);
  146.             GUILayout.Label("Z");
  147.             q.z = EditorGUILayout.FloatField(q.z);
  148.             GUILayout.Label("W");
  149.             q.w = EditorGUILayout.FloatField(q.w);
  150.             EditorGUILayout.EndHorizontal();
  151.  
  152.             if (EditorGUI.EndChangeCheck())
  153.             {
  154.                 Undo.RecordObject(_transform, "modify quaternion rotation on " + _transform.name);
  155.                 _transform.localRotation = ConvertToQuaternion(q);
  156.             }
  157.         }
  158.     }
  159.  
  160.  
  161.     private Quaternion ConvertToQuaternion(Vector4 v4)
  162.     {
  163.         return new Quaternion(v4.x, v4.y, v4.z, v4.w);
  164.     }
  165.  
  166.  
  167.     private Vector4 QuaternionToVector4(Quaternion q)
  168.     {
  169.         return new Vector4(q.x, q.y, q.z, q.w);
  170.     }
  171.  
  172.  
  173.     private bool showLocalAxisToggle = false;
  174.     private void ShowLocalAxisComponentToggle()
  175.     {
  176.         GUILayout.Space(10);
  177.         ShowLocalAxis showLocalAxis = _transform.gameObject.GetComponent<ShowLocalAxis>();
  178.  
  179.        
  180.         if (showLocalAxis == null)
  181.             showLocalAxisToggle = false;
  182.         else
  183.             showLocalAxisToggle = true;
  184.         GUILayout.BeginHorizontal();
  185.         EditorGUILayout.LabelField("Show local rotation handles", EditorStyles.boldLabel);
  186.         EditorGUI.BeginChangeCheck();
  187.         showLocalAxisToggle = GUILayout.Toggle(showLocalAxisToggle, (showLocalAxisToggle ? "on" : "off" ));
  188.         GUILayout.FlexibleSpace();
  189.         if (EditorGUI.EndChangeCheck())
  190.         {
  191.             if (showLocalAxisToggle == true)
  192.             {
  193.                 showLocalAxis = _transform.gameObject.AddComponent<ShowLocalAxis>();
  194.                 int componentCount = _transform.GetComponents<Component>().Length;
  195.                 for (int i = 1; i < componentCount; i++)
  196.                 {
  197.                     UnityEditorInternal.ComponentUtility.MoveComponentUp(showLocalAxis);
  198.                 }
  199.             }
  200.             else
  201.             {
  202.                 showLocalAxis.destroyWhenSafe = true;
  203.             }
  204.         }
  205.         GUILayout.EndHorizontal();
  206.     }
  207.  
  208.  
  209.     private AnimBool m_showExtraFields;
  210.     private static bool _showExtraFields;
  211.  
  212.     void OnEnable()
  213.     {
  214.         m_showExtraFields = new AnimBool(_showExtraFields);
  215.         m_showExtraFields.valueChanged.AddListener(Repaint);
  216.     }
  217.  
  218.     private void SpecialOperations()
  219.     {
  220.         EditorGUILayout.Space();
  221.         EditorGUILayout.Space();
  222.  
  223.         m_showExtraFields.target = EditorGUILayout.ToggleLeft("Special operations", m_showExtraFields.target);
  224.         if (EditorGUILayout.BeginFadeGroup(m_showExtraFields.faded))
  225.         {
  226.             AlignmentInspector();
  227.  
  228.             EditorGUILayout.Space();
  229.             EditorGUILayout.Space();
  230.  
  231.             RandomRotatationInspector();
  232.  
  233.             EditorGUILayout.Space();
  234.             EditorGUILayout.Space();
  235.  
  236.             RandomScaleInspector();
  237.  
  238.             EditorGUILayout.Space();
  239.             EditorGUILayout.Space();
  240.             RandomPositionInspector();
  241.         }
  242.         _showExtraFields = m_showExtraFields.value;
  243.         EditorGUILayout.EndFadeGroup();
  244.     }
  245.  
  246.    
  247.     private GUILayoutOption[] buttonOptions = new GUILayoutOption[1] { GUILayout.Width(200f) };
  248.     private bool Button(string label)
  249.     {
  250.         GUILayout.BeginHorizontal();
  251.         GUILayout.FlexibleSpace();
  252.         bool value = GUILayout.Button(label, buttonOptions);
  253.         GUILayout.FlexibleSpace();
  254.         GUILayout.EndHorizontal();
  255.         return value;
  256.     }
  257.  
  258.     public enum AlignToType { lastSelected, firstSelected }
  259.     public enum AxisFlag { X = 1, Y = 2, Z = 4 }
  260.  
  261.     public AlignToType alignTo = AlignToType.lastSelected;
  262.     public AxisFlag alignmentAxis = AxisFlag.X;
  263.     private void AlignmentInspector()
  264.     {
  265.         EditorGUILayout.LabelField("Alignment", EditorStyles.boldLabel, layoutMaxWidth);
  266.         alignTo = (AlignToType)EditorGUILayout.EnumPopup("Align to", alignTo, layoutMaxWidth);
  267.         alignmentAxis = (AxisFlag)EditorGUILayout.EnumMaskField("Axis", alignmentAxis, layoutMaxWidth);
  268.  
  269.         string buttonLabel = "Select another object to align to";
  270.         bool enableButton = false;
  271.         Transform[] selectedTransforms = Selection.transforms;
  272.         if (selectedTransforms.Length > 1)
  273.         {
  274.             if (alignTo == AlignToType.lastSelected)
  275.             {
  276.                 buttonLabel = "Align to " + selectedTransforms[selectedTransforms.Length - 1].name;
  277.             }
  278.             else
  279.             {
  280.                 buttonLabel = "Align to " + selectedTransforms[0].name;
  281.             }
  282.             enableButton = true;
  283.         }
  284.  
  285.         GUI.enabled = enableButton;
  286.         if (Button(buttonLabel))
  287.         {
  288.             AlignTo(alignTo, alignmentAxis);
  289.         }
  290.         GUI.enabled = true;
  291.     }
  292.  
  293.  
  294.     private void AlignTo(AlignToType to , AxisFlag axis)
  295.     {
  296.         Transform[] selectedTransforms = Selection.transforms;
  297.  
  298.         int targetIndex = 0;
  299.         if (to == AlignToType.lastSelected)
  300.             targetIndex = selectedTransforms.Length - 1;
  301.  
  302.         for (int i = 0; i < selectedTransforms.Length; i++)
  303.         {
  304.             if (i == targetIndex)
  305.                 continue;
  306.  
  307.             Vector3 temp = selectedTransforms[i].position;
  308.  
  309.             if ((axis & AxisFlag.X) == AxisFlag.X)
  310.                 temp.x = selectedTransforms[targetIndex].position.x;
  311.  
  312.             if ((axis & AxisFlag.Y) == AxisFlag.Y)
  313.                 temp.y = selectedTransforms[targetIndex].position.y;
  314.  
  315.             if ((axis & AxisFlag.Z) == AxisFlag.Z)
  316.                 temp.z = selectedTransforms[targetIndex].position.z;
  317.  
  318.             Undo.RecordObject(selectedTransforms[i], selectedTransforms[i].name +  " aligned to " + selectedTransforms[targetIndex].name);
  319.             selectedTransforms[i].position = temp;
  320.         }
  321.     }
  322.  
  323.  
  324.  
  325.     public AxisFlag rotationAxisFlag;
  326.     private void RandomRotatationInspector()
  327.     {
  328.         EditorGUILayout.LabelField("Random Rotation", EditorStyles.boldLabel, layoutMaxWidth);
  329.         rotationAxisFlag = (AxisFlag)EditorGUILayout.EnumMaskField("Rotation Axis", rotationAxisFlag, layoutMaxWidth);
  330.  
  331.         Transform[] selectedTransforms = Selection.transforms;
  332.  
  333.         string label = "Rotate " + _transform.name;
  334.         if (selectedTransforms.Length > 1)
  335.             label = "Rotate selected";
  336.  
  337.         if (Button(label))
  338.         {
  339.             RandomRotate(rotationAxisFlag , selectedTransforms);
  340.         }
  341.     }
  342.  
  343.     private void RandomRotate(AxisFlag axis , Transform[] selected)
  344.     {
  345.         for (int i = 0; i < selected.Length; i++)
  346.         {
  347.             Vector3 temp = selected[i].localEulerAngles;
  348.  
  349.             if ((axis & AxisFlag.X) == AxisFlag.X)
  350.                 temp.x = RdmDeg();
  351.  
  352.             if ((axis & AxisFlag.Y) == AxisFlag.Y)
  353.                 temp.y = RdmDeg();
  354.  
  355.             if ((axis & AxisFlag.Z) == AxisFlag.Z)
  356.                 temp.z = RdmDeg();
  357.  
  358.             Undo.RecordObject(_transform, "random rotate " + selected[i].name);
  359.             selected[i].localEulerAngles = temp;
  360.         }
  361.     }
  362.  
  363.     private float RdmDeg()
  364.     {
  365.         return Random.Range(0f, 360f);
  366.     }
  367.  
  368.  
  369.     private AxisFlag scaleAxisFlag;
  370.     private float minScale, maxScale;
  371.     private bool scaleSame = true;
  372.     private void RandomScaleInspector()
  373.     {
  374.         EditorGUILayout.LabelField("Random Scale (local)", EditorStyles.boldLabel, layoutMaxWidth);
  375.  
  376.         scaleAxisFlag = (AxisFlag)EditorGUILayout.EnumMaskField("Scale Axis", scaleAxisFlag, layoutMaxWidth);
  377.         scaleSame = EditorGUILayout.ToggleLeft("Scale same", scaleSame, layoutMaxWidth);
  378.  
  379.         minScale = EditorGUILayout.FloatField("Min:", minScale, layoutMaxWidth);
  380.         maxScale = EditorGUILayout.FloatField("Max", maxScale, layoutMaxWidth);
  381.  
  382.         Transform[] selectedTransforms = Selection.transforms;
  383.         string btnLabel = "Scale " + _transform.name;
  384.         if (selectedTransforms.Length > 1)
  385.             btnLabel = "Scale selection";
  386.  
  387.         if (Button(btnLabel))
  388.         {
  389.             RandomScale(scaleAxisFlag, selectedTransforms, scaleSame);
  390.         }
  391.     }
  392.  
  393.     private void RandomScale(AxisFlag axis, Transform[] selected , bool scaleSame)
  394.     {
  395.         for (int i = 0; i < selected.Length; i++)
  396.         {
  397.             Vector3 temp = selected[i].localScale;
  398.             Vector3 random = Vector3.zero;
  399.             if (scaleSame)
  400.             {
  401.                 float rdm = Random.Range(minScale, maxScale);
  402.                 random.x = rdm;
  403.                 random.y = rdm;
  404.                 random.z = rdm;
  405.             }
  406.             else
  407.             {
  408.                 random.x = Random.Range(minScale, maxScale);
  409.                 random.y = Random.Range(minScale, maxScale);
  410.                 random.z = Random.Range(minScale, maxScale);
  411.             }
  412.  
  413.             if ((axis & AxisFlag.X) == AxisFlag.X)
  414.                 temp.x = random.x;
  415.  
  416.             if ((axis & AxisFlag.Y) == AxisFlag.Y)
  417.                 temp.y = random.y;
  418.  
  419.             if ((axis & AxisFlag.Z) == AxisFlag.Z)
  420.                 temp.z = random.z;
  421.  
  422.             Undo.RecordObject(_transform, "random scale " + selected[i].name);
  423.             selected[i].localScale = temp;
  424.         }
  425.     }
  426.  
  427.  
  428.     private Vector3 minPosition, maxPosition;
  429.     private void RandomPositionInspector()
  430.     {
  431.         EditorGUILayout.LabelField("Random Position", EditorStyles.boldLabel, layoutMaxWidth);
  432.         minPosition = EditorGUILayout.Vector3Field("Min", minPosition, layoutMaxWidth);
  433.         maxPosition = EditorGUILayout.Vector3Field("Max", maxPosition, layoutMaxWidth);
  434.  
  435.         Transform[] selectedTransforms = Selection.transforms;
  436.         string btnLabel = "Move " + _transform.name;
  437.         if (selectedTransforms.Length > 1)
  438.             btnLabel = "Move selection";
  439.  
  440.         if (Button(btnLabel))
  441.         {
  442.             RandomPosition(minPosition, maxPosition, selectedTransforms);
  443.         }
  444.     }
  445.  
  446.    
  447.  
  448.     private void RandomPosition(Vector3 min , Vector3 max, Transform[] t)
  449.     {
  450.         for (int i = 0; i < t.Length; i++)
  451.         {
  452.             Vector3 temp = t[i].position;
  453.             if (!Mathf.Approximately(min.x, max.x))
  454.                 temp.x = Random.Range(min.x, max.x);
  455.  
  456.             if (!Mathf.Approximately(min.y, max.y))
  457.                 temp.y = Random.Range(min.y, max.y);
  458.  
  459.             if (!Mathf.Approximately(min.z, max.z))
  460.                 temp.z = Random.Range(min.z, max.z);
  461.  
  462.             Undo.RecordObject(t[i], "Random position " + t[i].name);
  463.             t[i].position = temp;
  464.         }
  465.     }
  466. }
RAW Paste Data
Top