Search Unity

Variables modified by handles are being temporarily reset at runtime

Discussion in 'Scripting' started by CoatsinkPC, Mar 16, 2013.

  1. CoatsinkPC

    CoatsinkPC

    Joined:
    Mar 16, 2013
    Posts:
    1
    RESOLVED
    I asked the same question at Unity Answers:
    http://answers.unity3d.com/questions/418321/handle-modified-variables-being-temporarily-reset.html

    where my question was promtly answered by Whydoidoit:
    This worked perfectly!


    Hello, long-time lurker, first time poster. I've tried my best to get as far as I could with existing documentation and support that I've found online, but now I am officially stuck! I'm sure I'm missing something fundamental here, so lets see how badly I'm failing.

    What I'm trying to do:
    I'm creating an editor extension that will include the ability to quickly add and modify box and sphere colliders to aid in camera tracking.

    I've made prefabs of these objects with custom inspectors to modify their size and shape, among other settings. I've also written some custom camera facing gizmos to display their size and shape to the user while they are testing their game. The objects also have handles that will allow the user to modify the collider's size and shape from within the scene view, with the intention being that they can quickly make modifications without having to look over to the inspector.

    The actual problem:
    My problem is that, while these handles will successfully modify the variables I want, updating the gizmos to show the updated information, the moment I press play, the gizmos reset to the last known setting made by the inspector, completely ignoring the handle modifications.

    The variables aren't forgotten though, and when I select the object again in editor mode, the gizmos instantly revert to their correct size and shape.

    This is only happening when the variables are modified by the handles. when they are modified by the custom inspector, the whole thing works as intended.







    Here is the code I'm using. It's based on this star tutorial.

    The data storage, retrieval and gizmo drawing script
    Code (csharp):
    1. using UnityEngine;
    2. using System.Collections;
    3.  
    4. [ExecuteInEditMode]
    5. public class TestData : MonoBehaviour {
    6.    
    7.     public Vector2 innerRect = new Vector2(7, 4);   //Area data
    8.     public Vector2 outerRect = new Vector2(10, 5);
    9.    
    10.     public float Radius = 0.5f;     //radius data
    11.  
    12.    
    13.     //Set Zone Data
    14.     public void UpdateTestData(){
    15.        
    16.         ClampValues();
    17.        
    18.         var boxInner = GetComponent<BoxCollider>();
    19.         boxInner.size = new Vector3(innerRect.x, innerRect.y, innerRect.x);
    20.        
    21.         var boxOuter = transform.Find("Outer Box").GetComponent<BoxCollider>();
    22.         boxOuter.size = new Vector3(outerRect.x, outerRect.y, outerRect.x);
    23.        
    24.         var sphere = transform.Find("Outer Sphere").GetComponent<SphereCollider>();
    25.         sphere.radius = Radius;
    26.     }
    27.    
    28.     //Get Test Data
    29.     public void GetTestData(){
    30.        
    31.         var boxInner = GetComponent<BoxCollider>();
    32.         innerRect = new Vector2((boxInner.size.x > boxInner.size.z) ? boxInner.size.x : boxInner.size.z, boxInner.size.y);
    33.        
    34.         var boxOuter = transform.Find("Outer Box").GetComponent<BoxCollider>();
    35.         outerRect = new Vector2((boxOuter.size.x > boxOuter.size.z) ? boxOuter.size.x : boxOuter.size.z, boxOuter.size.y);
    36.        
    37.         var sphere = transform.Find("Outer Sphere").GetComponent<SphereCollider>();
    38.         Radius = sphere.radius;
    39.        
    40.         ClampValues();
    41.     }
    42.    
    43.     //Clamp Values to reasonable limits
    44.     void ClampValues() {
    45.        
    46.         //Inner Bounds
    47.         innerRect.x = (innerRect.x < 0.1f) ? 0.1f : innerRect.x;
    48.         innerRect.y = (innerRect.y < 0.1f) ? 0.1f : innerRect.y;
    49.        
    50.         //Outer Bounds
    51.         outerRect.x = (innerRect.x >= outerRect.x) ? innerRect.x : outerRect.x;
    52.         outerRect.y = (innerRect.y >= outerRect.y) ? innerRect.y : outerRect.y;
    53.        
    54.         Radius = (Radius < 0) ? 0: Radius;
    55.        
    56.     }
    57.    
    58.     void onEnable(){
    59.         UpdateTestData();
    60.     }
    61.    
    62.     void Reset () {
    63.         UpdateTestData();
    64.     }
    65.    
    66.     void OnDrawGizmos(){
    67.         //Drawing a custom rectangle to represent the zone bounds
    68.        
    69.         Vector3 currentCamRot = Camera.main.transform.forward;
    70.         Quaternion lookRot = Quaternion.LookRotation(currentCamRot);        //Get the camera-facing angle
    71.        
    72.         //Draw inner bounds
    73.         Gizmos.color = Color.red;
    74.         //Get the 4 corners of the area
    75.         Vector3 PointA = new Vector3((-innerRect.x/2), innerRect.y/2, 0f),
    76.                 PointB = new Vector3(innerRect.x/2, innerRect.y/2, 0f),
    77.                 PointC = new Vector3(innerRect.x/2, (-innerRect.y/2), 0f),
    78.                 PointD = new Vector3((-innerRect.x/2), (-innerRect.y/2), 0f);
    79.        
    80.         //Draw the 4 edges of the area
    81.         Gizmos.DrawLine(transform.TransformPoint(lookRot * PointA),  transform.TransformPoint(lookRot * PointB));
    82.         Gizmos.DrawLine(transform.TransformPoint(lookRot * PointB), transform.TransformPoint(lookRot * PointC));
    83.         Gizmos.DrawLine(transform.TransformPoint(lookRot * PointC),  transform.TransformPoint(lookRot * PointD));
    84.         Gizmos.DrawLine(transform.TransformPoint(lookRot * PointD), transform.TransformPoint(lookRot * PointA));
    85.        
    86.        
    87.         //Draw outer bounds
    88.         Gizmos.color = Color.yellow;
    89.         //Get the 4 corners of the area
    90.         PointA = new Vector3((-outerRect.x/2), outerRect.y/2, 0f);
    91.         PointB = new Vector3(outerRect.x/2, outerRect.y/2, 0f);
    92.         PointC = new Vector3(outerRect.x/2, (-outerRect.y/2), 0f);
    93.         PointD = new Vector3((-outerRect.x/2), (-outerRect.y/2), 0f);
    94.        
    95.         //Draw the 4 edges of the area
    96.         Gizmos.DrawLine(transform.TransformPoint(lookRot * PointA),  transform.TransformPoint(lookRot * PointB));
    97.         Gizmos.DrawLine(transform.TransformPoint(lookRot * PointB), transform.TransformPoint(lookRot * PointC));
    98.         Gizmos.DrawLine(transform.TransformPoint(lookRot * PointC),  transform.TransformPoint(lookRot * PointD));
    99.         Gizmos.DrawLine(transform.TransformPoint(lookRot * PointD), transform.TransformPoint(lookRot * PointA));
    100.        
    101.         //Draw Circle
    102.         Gizmos.color = Color.green;
    103.         int sides = 32;
    104.         Vector3 RadiusVector = new Vector3(0f, Radius, 0f);
    105.         for(int i=0;i<sides;i++){
    106.            
    107.             Quaternion  rotationA = Quaternion.Euler(0f, 0f, (360f/sides)*i),
    108.                         rotationB = Quaternion.Euler(0f, 0f, (360f/sides)*(i+1));//get points for the side we're on
    109.            
    110.             PointA = rotationA * RadiusVector;
    111.             PointB = rotationB * RadiusVector;//scale points by the size of the ring
    112.            
    113.             PointA = transform.TransformPoint(lookRot * PointA);
    114.             PointB = transform.TransformPoint(lookRot * PointB);//rotate the ring towards the camera
    115.            
    116.             Gizmos.DrawLine(PointA, PointB);
    117.         }
    118.     }
    119. }
    120.  
    The editor script
    Code (csharp):
    1. using UnityEngine;
    2. using UnityEditor;
    3. using System.Collections;
    4.  
    5. [CanEditMultipleObjects, CustomEditor( typeof(TestData))]
    6. public class ACTestEditor : Editor {
    7.    
    8.     private static Vector3 pointSnap = Vector3.one * 0.1f;
    9.    
    10.     private SerializedObject test;
    11.     private SerializedProperty
    12.         innerRect,
    13.         outerRect,
    14.         Radius;
    15.    
    16.     void OnEnable(){
    17.        
    18.         test        = new SerializedObject(targets);
    19.         innerRect   = test.FindProperty("innerRect");
    20.         outerRect   = test.FindProperty("outerRect");
    21.         Radius      = test.FindProperty("Radius");
    22.     }
    23.    
    24.     public override void OnInspectorGUI ()
    25.     {
    26.         foreach(TestData t in targets){
    27.                 t.GetTestData();
    28.         }
    29.         test.Update();
    30.        
    31.        
    32.         EditorGUILayout.BeginHorizontal();
    33.         {
    34.             EditorGUILayout.PropertyField(innerRect, true);
    35.             EditorGUILayout.PropertyField(outerRect, true);
    36.         }
    37.         EditorGUILayout.EndHorizontal();
    38.         EditorGUILayout.BeginHorizontal();
    39.         {
    40.             EditorGUILayout.PropertyField(Radius);
    41.         }
    42.         EditorGUILayout.EndHorizontal();
    43.        
    44.         if(test.ApplyModifiedProperties() ||    (Event.current.type == EventType.ValidateCommand    Event.current.commandName == "UndoRedoPerformed")){
    45.             foreach(TestData t in targets){
    46.                 t.UpdateTestData();
    47.             }
    48.         }
    49.     }
    50.    
    51.     void OnSceneGUI(){
    52.         //Custom Handles
    53.         TestData test = (TestData)target;
    54.         test.GetTestData();
    55.         Transform tTransform = test.transform;
    56.         Undo.SetSnapshotTarget(test, "Adjust Test Data");
    57.        
    58.         //Camera angle
    59.         Vector3 CamRot = Camera.main.transform.forward;
    60.         Quaternion lookRot = Quaternion.LookRotation(CamRot);
    61.        
    62.        
    63.         //inner box
    64.         Handles.color = Color.red;
    65.         Vector3 innerRectWidth  = new Vector3(test.innerRect.x/2, 0, 0),
    66.                 innerRectHeight = new Vector3(0, test.innerRect.y/2, 0);
    67.        
    68.         for(int i=0; i<4; i++){
    69.  
    70.             Vector3 handlePoint;
    71.            
    72.             switch(i){
    73.                 case 0:
    74.                     handlePoint = innerRectHeight - innerRectWidth/2;
    75.                     break;
    76.                 case 1:
    77.                     handlePoint = innerRectWidth + innerRectHeight/2;
    78.                     break;
    79.                 case 2:
    80.                     handlePoint = -innerRectHeight + innerRectWidth/2;
    81.                     break;
    82.                 case 3:
    83.                     handlePoint = -innerRectWidth - innerRectHeight/2;
    84.                     break;
    85.                 default:
    86.                     handlePoint = Vector3.zero;
    87.                     break;
    88.             }
    89.            
    90.             handlePoint = tTransform.TransformPoint(lookRot * handlePoint);
    91.            
    92.             Vector3 newPoint = Handles.FreeMoveHandle(handlePoint, Quaternion.identity, HandleUtility.GetHandleSize(handlePoint)/5, pointSnap, Handles.SphereCap);
    93.            
    94.             if(handlePoint != newPoint){
    95.                 newPoint = newPoint - tTransform.position;
    96.                 newPoint = Quaternion.Inverse(lookRot) * newPoint;
    97.                
    98.                 switch(i){
    99.                     case 0:
    100.                         test.innerRect.y = newPoint.y*2;
    101.                         break;
    102.                     case 1:
    103.                         test.innerRect.x = newPoint.x*2;
    104.                         break;
    105.                     case 2:
    106.                         test.innerRect.y = -newPoint.y*2;
    107.                         break;
    108.                     case 3:
    109.                         test.innerRect.x = -newPoint.x*2;
    110.                         break;
    111.                     default:
    112.                         break;
    113.                 }
    114.                 test.UpdateTestData();
    115.             }
    116.         }
    117.        
    118.         //outer box
    119.         Handles.color = Color.yellow;
    120.         Vector3 outerRectWidth  = new Vector3(test.outerRect.x/2, 0, 0),
    121.                 outerRectHeight = new Vector3(0, test.outerRect.y/2, 0);
    122.        
    123.         for(int i=0; i<4; i++){
    124.  
    125.             Vector3 handlePoint;
    126.            
    127.             switch(i){
    128.                 case 0:        
    129.                     handlePoint = outerRectHeight + outerRectWidth/2;
    130.                     break;
    131.                 case 1:
    132.                     handlePoint = outerRectWidth - outerRectHeight/2;
    133.                     break;
    134.                 case 2:
    135.                     handlePoint = -outerRectHeight - outerRectWidth/2;
    136.                     break;
    137.                 case 3:
    138.                     handlePoint = -outerRectWidth + outerRectHeight/2;
    139.                     break;
    140.                 default:
    141.                     handlePoint = Vector3.zero;
    142.                     break;
    143.             }
    144.            
    145.             handlePoint = tTransform.TransformPoint(lookRot * handlePoint);
    146.                
    147.             Vector3 newPoint = Handles.FreeMoveHandle(handlePoint, Quaternion.identity, HandleUtility.GetHandleSize(handlePoint)/5, pointSnap, Handles.SphereCap);
    148.                
    149.             if(handlePoint != newPoint){
    150.                 newPoint = newPoint - tTransform.position;
    151.                 newPoint = Quaternion.Inverse(lookRot) * newPoint;
    152.                    
    153.                 switch(i){
    154.                     case 0:
    155.                         test.outerRect = new Vector2(test.outerRect.x, newPoint.y*2);
    156.                         break;
    157.                     case 1:
    158.                         test.outerRect = new Vector2(newPoint.x*2, test.outerRect.y);
    159.                         break;
    160.                     case 2:
    161.                         test.outerRect = new Vector2(test.outerRect.x, -newPoint.y*2);
    162.                         break;
    163.                     case 3:
    164.                         test.outerRect = new Vector2(-newPoint.x*2, test.outerRect.y);
    165.                         break;
    166.                     default:
    167.                         break;
    168.                 }
    169.                 test.UpdateTestData();
    170.             }
    171.         }
    172.        
    173.        
    174.         //radius
    175.         Handles.color = Color.green;
    176.         Vector3 RadiusVector = new Vector3(0f, test.Radius, 0f);
    177.         for(int i = 0; i < 4; i++){
    178.             Quaternion rotation = Quaternion.Euler(0f, 0f, 90f*i);
    179.             Vector3 oldPoint = rotation * RadiusVector;
    180.                
    181.             oldPoint = tTransform.TransformPoint(lookRot * oldPoint);
    182.                
    183.             Vector3 newPoint = Handles.FreeMoveHandle(oldPoint, Quaternion.identity, HandleUtility.GetHandleSize(oldPoint)/5, pointSnap, Handles.SphereCap);
    184.            
    185.             if(oldPoint != newPoint){
    186.                 test.Radius = Vector3.Magnitude(newPoint - tTransform.position);
    187.                 test.UpdateTestData();
    188.             }
    189.         }
    190.     }
    191. }
    192.  
    An example:
    I've created an isolated package of the problem in hopes that it might make my issue clearer to others.
    https://dl.dropbox.com/u/1672880/test bug package.unitypackage
    • Simply add the package to an empty project, drag the test object into the scene and modify its shape using the handles.
    • (If you see wireframes of the collider components over the gizmos, just collapse the components in the inspector)
    • Make sure the object is deselected and then press play. You'll see the gizmos reset to their original shape and size.
    • If you go back to edit mode and reselect the object, you should see the gizmos update to their proper settings.
    • Additionally, if you now edit the shapes from the custom inspector, those settings will be remembered at runtime.

    My current suspicions are that it is something to do with serialization, which I admit I know very little about, so any help or push in the right direction would be greatly appreciated, thankyou.
     
    Last edited: Mar 16, 2013