- Home /
*Really* need help on Serialisation, stuck on this for over a week now, deadline looming
--Edit---------------
Ok, I've tried all of the below suggestions to no avail.
The current behaviour is this: Any changes made to the CheckPointAttributes list immediately after compile do work correctly, but once I've entered play mode the list is "frozen" in it's current state. So if I added an element before entering play mode, once I've entered play mode from that point onwards that element will be stuck in the list and I cannot add/remove/clear it. The same behaviour is observed when I enter play mode with no elements in the list, it is stuck that way until I recompile.
But, when I print the .Count of the list it does return as zero if I have cleared it even though I can clearly see an element in the list, once I enter and exit play mode however it will continue to return as 1.
This problem has delayed me for over a week, I had no idea Unity editor scripting was so finicky and I'm going to need to find an alternate method to creating a custom inspector if I can't solve this by the end of the day, as I have a deadline in one week. So any and all suggestions are welcome. I've updated the scripts below
Panel_Controller, the class on the object being inspected
using UnityEngine;
using System;
using System.Collections;
using System.Collections.Generic;
/*
# ===================================================================
# Notes: Controls each panel's attributes, which define
it's behavious;
Animation of transform/rotation/scale
# ===================================================================
*/
public class Panel_Controller : MonoBehaviour
{
public List<Checkpoint_Attributes> CheckpointAttributes = new List<Checkpoint_Attributes>();
public List<bool> Foldouts = new List<bool>();
public enum PanelType {SelectType, GameObj, CanvasObj};
public PanelType TypeOfPanel;
private GameObject gameManager;
private Game_Manager gameManClass;
private bool gameObjPanWasTrue = false;
private bool gameObjPan = false;
private bool gameObjTween = false;
private int i = 0;
private int activeCheckpIndex = 0;
void Awake ()
{
gameManager = GameObject.Find("Game_Manager");
gameManClass = gameManager.GetComponent<Game_Manager>();
}
void Update ()
{
if (gameManClass.Moving)
{
CheckForTargetCheckpointMatch();
if (gameObjPan)
{
PanGameObjPanel();
}
}
else
{
if (gameObjPanWasTrue)
{
TweenGameObjPanel();
}
}
}
void CheckForTargetCheckpointMatch ()
{
for (i=0; i<CheckpointAttributes.Count; i++)
{
if (CheckpointAttributes[i].TargetCheckpoint == gameManClass.TargetCheckpoint)
{
if (TypeOfPanel == PanelType.GameObj)
{
activeCheckpIndex = i;
gameObjPan = true;
}
break;
}
}
}
void PanGameObjPanel ()
{
gameObjPanWasTrue = true;
if (gameObjTween)
{
gameObjTween = false;
if (iTween.Count(gameObject) > 0)
{
iTween.Stop(gameObject);
}
}
if (CheckpointAttributes[activeCheckpIndex].DoesMove)
{
transform.position = Vector3.Lerp(transform.position, CheckpointAttributes[activeCheckpIndex].TargetPosition, Time.deltaTime*(gameManClass.AbsMoveDelta*CheckpointAttributes[activeCheckpIndex].MoveSpeed));
}
}
void TweenGameObjPanel ()
{
gameObjPanWasTrue = false;
gameObjTween = true;
if (CheckpointAttributes[activeCheckpIndex].DoesMove)
{
gameObjTween = true;
iTween.MoveTo(gameObject, iTween.Hash("name",gameObject.name, "position",CheckpointAttributes[activeCheckpIndex].TargetPosition, "time",CheckpointAttributes[activeCheckpIndex].MoveSpeed, "easeType","easeOutCubic"));
}
}
}
PanelController_Editor, the editor script used for PanelController
using UnityEditor;
using UnityEngine;
using System.Collections;
using System.Collections.Generic;
/*
# ===================================================================
# Notes: Creates the custom inspector on the Panel's
Panel_Controller component
# ===================================================================
*/
[CustomEditor(typeof(Panel_Controller))]
public class PanelController_Editor : Editor
{
private Vector3 tempPos;
private Quaternion tempRot;
private Vector3 tempScale;
private bool tempDoesMove = false;
private bool tempDoesRot = false;
private bool tempDoesScale = false;
private float tempMoveSpeed = 1f;
private float tempRotSpeed = 1f;
private float tempScaleSpeed = 1f;
private int inputCheckpoint = 0;
private Panel_Controller panelCtrlClass;
void OnEnable ()
{
}
public override void OnInspectorGUI()
{
DrawDefaultInspector();
panelCtrlClass = target as Panel_Controller;
GUI.changed = false;
//Display Panel Type Enum to choose the type for this panel
panelCtrlClass.TypeOfPanel = (Panel_Controller.PanelType)EditorGUILayout.EnumPopup ("Panel Type", panelCtrlClass.TypeOfPanel);
//Execute method for this panel type
switch(panelCtrlClass.TypeOfPanel)
{
case Panel_Controller.PanelType.GameObj:
GameObjectType();
break;
case Panel_Controller.PanelType.CanvasObj:
//Code
break;
}
//Update Panel Controller script's values
if (GUI.changed)
{
EditorUtility.SetDirty(panelCtrlClass);
}
}
void GameObjectType ()
{
//Draw the checkpoint input and add/remove buttons
DrawInputBox("Target Checkpoint:");
if (GUILayout.Button("Add Checkpoint"))
{
AddGameObjCheckpoint();
}
if (GUILayout.Button("Clear All Checkpoints"))
{
ClearCheckpoints();
}
if (GUILayout.Button("Print checkpoint count"))
{
LogCheckpoints();
}
}
void AddGameObjCheckpoint ()
{
//Add new item to main CheckpointAttributes List on Panel Controller, values passed in are all zero
panelCtrlClass.CheckpointAttributes.Add(new Checkpoint_Attributes(inputCheckpoint, tempPos, tempRot, tempScale, tempDoesMove, tempDoesRot, tempDoesScale, tempMoveSpeed, tempRotSpeed, tempScaleSpeed));
Debug.Log("Checkpoint added, list count = " + panelCtrlClass.CheckpointAttributes.Count);
}
void ClearCheckpoints ()
{
if (panelCtrlClass.CheckpointAttributes.Count < 1)
{
Debug.Log("List already cleared, list count = " + panelCtrlClass.CheckpointAttributes.Count);
return;
}
//Empty the main CheckpointAttributes list on Panel Controller
panelCtrlClass.CheckpointAttributes.Clear();
Debug.Log("All checkpoints cleared, list count = " + panelCtrlClass.CheckpointAttributes.Count);
// panelCtrlClass.Foldouts.Clear();
}
void LogCheckpoints ()
{
Debug.Log("List count = " + panelCtrlClass.CheckpointAttributes.Count);
}
void DrawCheckpointMenu (int menuID)
{
if (panelCtrlClass.Foldouts.Count < (menuID+1))
{
bool tempBool = new bool();
panelCtrlClass.Foldouts.Add(tempBool);
panelCtrlClass.Foldouts[menuID] = true;
}
if (panelCtrlClass.CheckpointAttributes.Count < (menuID+1))
{
panelCtrlClass.Foldouts[menuID] = EditorGUILayout.Foldout(panelCtrlClass.Foldouts[menuID], "Checkpoint " + inputCheckpoint);
}
else
{
if (panelCtrlClass.CheckpointAttributes[menuID].TargetCheckpoint == -1)
{
panelCtrlClass.CheckpointAttributes[menuID].TargetCheckpoint = inputCheckpoint;
}
panelCtrlClass.Foldouts[menuID] = EditorGUILayout.Foldout(panelCtrlClass.Foldouts[menuID], "Checkpoint " + panelCtrlClass.CheckpointAttributes[menuID].TargetCheckpoint);
}
if (panelCtrlClass.Foldouts[menuID])
{
EditorGUI.indentLevel = 1;
DrawCheckpointFoldouts(menuID);
}
EditorGUI.indentLevel = 0;
}
void DrawCheckpointFoldouts (int menuID)
{
if (GUILayout.Button("Remove Checkpoint"))
{
RemoveCheckpoint(menuID);
}
EditorGUILayout.Space();
if (panelCtrlClass.CheckpointAttributes.Count < (menuID+1))
{
// tempTargTran = EditorGUILayout.ObjectField("Target", tempTargTran, typeof(Transform), true) as Transform;
tempDoesMove = EditorGUILayout.Toggle("Does Move?", tempDoesMove);
if (tempDoesMove)
{
EditorGUI.indentLevel = 2;
tempMoveSpeed = EditorGUILayout.FloatField("Speed", tempMoveSpeed);
tempPos = EditorGUILayout.Vector3Field(" Position", tempPos);
EditorGUI.indentLevel = 1;
}
tempDoesRot = EditorGUILayout.Toggle("Does Rotate?", tempDoesRot);
if (tempDoesRot)
{
EditorGUI.indentLevel = 2;
tempRotSpeed = EditorGUILayout.FloatField("Speed", tempRotSpeed);
EditorGUI.indentLevel = 1;
}
tempDoesScale = EditorGUILayout.Toggle("Does Scale?", tempDoesScale);
if (tempDoesScale)
{
EditorGUI.indentLevel = 2;
tempScaleSpeed = EditorGUILayout.FloatField("Speed", tempScaleSpeed);
EditorGUI.indentLevel = 1;
}
panelCtrlClass.CheckpointAttributes.Add(new Checkpoint_Attributes(inputCheckpoint, tempPos, tempRot, tempScale, tempDoesMove, tempDoesRot, tempDoesScale, tempMoveSpeed, tempRotSpeed, tempScaleSpeed));
return;
}
// panelCtrlClass.CheckpointAttributes[menuID].TargetTransform = EditorGUILayout.ObjectField("Target", panelCtrlClass.CheckpointAttributes[menuID].TargetTransform, typeof(Transform), true) as Transform;
panelCtrlClass.CheckpointAttributes[menuID].DoesMove = EditorGUILayout.Toggle("Does Move?", panelCtrlClass.CheckpointAttributes[menuID].DoesMove);
if (panelCtrlClass.CheckpointAttributes[menuID].DoesMove)
{
EditorGUI.indentLevel = 2;
panelCtrlClass.CheckpointAttributes[menuID].MoveSpeed = EditorGUILayout.FloatField("Speed", panelCtrlClass.CheckpointAttributes[menuID].MoveSpeed);
panelCtrlClass.CheckpointAttributes[menuID].TargetPosition = EditorGUILayout.Vector3Field("Target Position", panelCtrlClass.CheckpointAttributes[menuID].TargetPosition);
EditorGUI.indentLevel = 1;
}
panelCtrlClass.CheckpointAttributes[menuID].DoesRotate = EditorGUILayout.Toggle("Does Rotate?", panelCtrlClass.CheckpointAttributes[menuID].DoesRotate);
if (panelCtrlClass.CheckpointAttributes[menuID].DoesRotate)
{
EditorGUI.indentLevel = 2;
panelCtrlClass.CheckpointAttributes[menuID].RotateSpeed = EditorGUILayout.FloatField("Speed", panelCtrlClass.CheckpointAttributes[menuID].RotateSpeed);
EditorGUI.indentLevel = 1;
}
panelCtrlClass.CheckpointAttributes[menuID].DoesScale = EditorGUILayout.Toggle("Does Scale?", panelCtrlClass.CheckpointAttributes[menuID].DoesScale);
if (panelCtrlClass.CheckpointAttributes[menuID].DoesScale)
{
EditorGUI.indentLevel = 2;
panelCtrlClass.CheckpointAttributes[menuID].ScaleSpeed = EditorGUILayout.FloatField("Speed", panelCtrlClass.CheckpointAttributes[menuID].ScaleSpeed);
EditorGUI.indentLevel = 1;
}
}
void RemoveCheckpoint (int mID)
{
panelCtrlClass.CheckpointAttributes.RemoveAt(mID);
}
void DrawInputBox (string txt)
{
EditorGUILayout.BeginHorizontal();
EditorGUILayout.PrefixLabel(txt);
inputCheckpoint = EditorGUILayout.IntField(inputCheckpoint);
EditorGUILayout.EndHorizontal();
}
/*
void SetClassDirty ()
{
EditorUtility.SetDirty(target);
// EditorUtility.SetDirty(panelCtrlClass);
// EditorUtility.SetDirty(panelCtrlClass.gameObject);
}
*/
}
Checkpoint_Attributes, the struct class used for the CheckpointAttributes List
using UnityEngine;
using System;
using System.Collections;
[Serializable]
public class Checkpoint_Attributes
{
public int TargetCheckpoint = -1;
public Vector3 TargetPosition;
public Quaternion TargetRotation;
public Vector3 TargetScale;
public bool DoesMove = false;
public bool DoesRotate = false;
public bool DoesScale = false;
public float MoveSpeed = 1f;
public float RotateSpeed = 1f;
public float ScaleSpeed = 1f;
public Checkpoint_Attributes (int tCheck, Vector3 targPos, Quaternion targRot, Vector3 targScale, bool dMove, bool dRot, bool dScale, float mSpeed, float rSpeed, float sSpeed)
{
tCheck = TargetCheckpoint;
targPos = TargetPosition;
targRot = TargetRotation;
targScale = TargetScale;
dMove = DoesMove;
dRot = DoesRotate;
dScale = DoesScale;
mSpeed = MoveSpeed;
rSpeed = RotateSpeed;
sSpeed = ScaleSpeed;
}
}
The desired results are;
Create gameobject in scene
Drag and drop Panel_Controller class onto said gameobject
PanelController_Editor script displays a custom inspector
Inspector asks you to choose what type of object this gameobject is (options are canvas and gameobject)
You type in a checkpoint id into an int field in the inspector, this checkpoint tells the object when it needs to move
You click add checkpoint and a new element is added to a List on Panel_Controller, the List inherits from a Checkpoint_Attributes constructor with various parameters
The problem is the List elements and their parameters are not being stored correctly, below is what the inspector looks like
Hi, I answered your previous question yesterday, but saw someone else posted the same answer a few seconds before that so I removed my answer to keep "Answers" clean :) Usually it's preferable to edit your question or add a comment to bump it on top of the list as it may help the community to better know the problem and remove the risk of duplicated questions.
For your problem: the code seems ok. You used SetDirty on the component, I already had strange behaviors with using it only on the component: can you try using it also on the target.gameObject to see if it makes things better ?
I would also try using DrawDefaultInspector() at the beginning of the OnInspectorGUI: it will help you see what Unity "see", inspect your data and help debug.
You can also remove the serializable attribute on the monobehavior-based class (but I don't thing it changes anything)
Sorry I figured since the problem has changed into something a bit different a new post would be best.
I tried SetDirty(panelCtrlClass.gameObject) and SetDirty(panelCtrlClass) but both resulted in the same behaviour as SetDirty(target), although I did not try SetDirty(target.gameObject).
I didn't realise the serializable on the monobehaviour was unnecesary, so will remove that. I'm out of the office at the moment though so can't try until tomorrow morning.
What puzzles me is why the SetDirty seems to work perfectly immediately after a compile, but at no other time, perhaps I'm losing a reference or something? I experiemented with ScriptableObject but after reading the docs it didn't seem appropriate for my case.
Could it be that I am referencing panelCtrlClass in OnEnable, then using that to set my values in OnInspectorGUI, rather than using target? Perhaps that reference is lost after the OnEnable?
Hummm, then maybe you could set panelCtrlClass to target at the beginning of OnInspectorGUI then, as I think OnEnable is called after a recompile. $$anonymous$$aybe try first without the CanEdit$$anonymous$$ultipleObjects attribute too, just in case.
Edit: ha ha, same thought at the same time abpout OnEnable :)
I'll give that a go in the morning so, thank you very much for your help!
Out of curiousity, why is the [serializable] on the mono class not necesary? Because all of the variables used by the editor script are public?
Answer by Fourthings · Jan 26, 2015 at 02:26 PM
So I think I found the problem, you know the little Lock icon in the top right of the inspector? I had the component I was watching locked and it seems after making changes to the component, then playing, and then exiting play, where the gameobject would normally be deselected the connection between the inspector component you're viewing and the object you still appear to have selected is severed. Meaning you're looking at old values that are not reflecting the current actual values.
This also caused bizarre behaviour when logging these values. Once I unchecked that lock icon everything started behaving as it should. I don't think this is the entire answer but everything works as it should now. I'll update with any further pertinent information