Hello,
I am getting a problem in custom script (Just not able to get it)
In my custom script anything like a text field,label if i add through a button press in Override Function then it won’t work(nothing happens,Just button clicks) even i try through function call .
If i turn on play mode everything i insert using for loop get erased , is there any way to store those things (text field, color patterns, objects etc.)
Here is my example code .
using UnityEngine;
using System.Collections;
using UnityEditor;
//Creates a custom Label on the inspector for all the scripts named ScriptName
// Make sure you have a ScriptName script in your
// project, else this will not work.
[CustomEditor(typeof(AiOperations))]
public class TestOnInspector : Editor
{
public override void OnInspectorGUI()
{
DrawDefaultInspector();
if (GUILayout.Button("Click!")) {
newfunction();
}
}
public void newfunction()
{
GUILayout.Label ("This is a Label in a Custom Editor");
}
}
So, how the Editor scripts mode work is they are Immediate-mode GUIs. The OnInspectorGUI() function will get called whenever the editor gets updated, the editor’s drawing surface will get cleared, and the entire editor area will get repainted, that’s why the label is disappearing. All the GUI* functions do is setup a draw/layout order, and you control that with data in your editor or the object it’s editing.
As for keeping changes in an editor, they’ll either need to be on the target object being updated (via SerializedProperty), or as member variables of the editor itself (I believe you can have variables be marked for serialization on an Editor or EditorWindow, and those values will survive a swap into play mode, I haven’t messed with this in a while however).
What I recommend is this, based on my own experience:
Create an OnEnable() function on the Editor to setup serialized property references/initialize data or cache structures in the editor.
Draw in OnInspectorGUI()
Create commands to manipulate data that get called by buttons and sliders and whatever else you have setup in OnInpsectorGUI()
As your editor code grows, break it down into smaller drawing sub-functions and helper data manipulator functions.
I’m at work at the moment, so I can’t give you a sample from here, but I will see if I can find a simple example when I get home and can get to my old project’s codebase.
As for your example right now:
using UnityEngine;
using System.Collections;
using UnityEditor;
using UnityEngine.Assertions; //I prefer using assertions as it makes things easier to debug in the long run.
//Creates a custom Label on the inspector for all the scripts named ScriptName
// Make sure you have a ScriptName script in your
// project, else this will not work.
[CustomEditor(typeof(MYCUSTOMCLASS))]
public class TestOnInspector : Editor
{
// cache references to help make the editor run faster, wherever
// it's appropriate
private SerializedProperty m_exampleDataProp = null;
private void OnEnable()
{
// grab an editable wrapper to the data we want to view and manipulate
m_exampleDataProp = serializedObject.FindProperty("m_exampleData");
// ensure our property exists and it's what we expect it to be
Assert.IsNotNull(m_exampleDataProp);
Assert.AreEqual(m_exampleDataProp.propertyType, SerializedPropertyType.Boolean);
}
public override void OnInspectorGUI()
{
// draws the base inspector first, if we're going fully custom, we don't need this step
DrawDefaultInspector();
// show the value of our data in the button.
// you don't have to do it this way but I did it for the sake of a quick example.
if (GUILayout.Button(string.Format("Click! {0}", m_exampleDataProp.boolValue))
{
ToggleData();
}
// display our "sub-GUI" based on some data value
if(m_exampleDataProp.boolValue)
newfunction();
}
public ToggleData()
{
m_exampleDataProp.boolValue = !m_exampleDataProp.boolValue;
}
public void newfunction()
{
GUILayout.Label ("This is a Label in a Custom Editor");
}
}
Managed to find an old example on my laptop, WARNING: SOMEWHAT COMPLICATED AND OLD
I’m not using this version of the framework anymore, as my Entity framework got complicated, but here’s an old example from an Entity-Traits I made for an earlier version of my game (Unity 4.X, so I’d rewrite it if I were to use it again in 5.X):
Edit:
I will admit I’ve tried to clean up my coding style between then and now.
using Hydrogen;
using Hydrogen.Reflection;
using System.Collections.Generic;
using UnityEditor;
using UnityEngine;
using System.Linq;
using Hydrogen.Editor;
[CustomEditor(typeof(Entity))]
public class EntityEditor : Editor
{
private int m_lastSelectedTraitType = 0;
private GUIContent[] m_traitGUIContent = null;
private List<System.Type> m_availableTraitTypes = null;
private static readonly GUIContent m_addLabel = new GUIContent("+");
private static readonly GUIContent m_selectTypeLabel = new GUIContent("Select Type: ");
private static readonly GUIContent m_removeLabel = new GUIContent("-");
private static readonly GUIContent m_upLabel = new GUIContent("^");
private static readonly GUIContent m_downLabel = new GUIContent("v");
private Entity m_editingEntity = null;
public static void RegisterHeirarchyChangedIfNeeded()
{
EditorApplication.hierarchyWindowChanged -= OnCheckForEntityDeleted;
EditorApplication.hierarchyWindowChanged += OnCheckForEntityDeleted;
}
private static void OnCheckForEntityDeleted()
{
var all = Resources.FindObjectsOfTypeAll<Trait>();
foreach (var trait in all)
{
if (trait.Entity == null)
trait.AcquireEntity();
}
}
public void OnEnable()
{
m_editingEntity = serializedObject.targetObject as Entity;
Verify.Assert(m_editingEntity != null);
RemoveDeadTraits();
RegisterHeirarchyChangedIfNeeded();
PopulateTraitTypeLabels();
}
private void PopulateTraitTypeLabels()
{
// create a list of available types, and sort them
var existing_types = (from trait in m_editingEntity.Traits where !(trait is IMultiInstanceTrait) select trait.GetType()).ToList();
m_availableTraitTypes = TypeUtils.GetInstantiableSubClasses<Trait>();
m_availableTraitTypes = m_availableTraitTypes.Except(existing_types).ToList();
m_availableTraitTypes.Sort((_a, _b) => _a.Name.CompareTo(_b.Name));
// create an array of GUIContents from the typenames
m_traitGUIContent = (from type in m_availableTraitTypes select new GUIContent(type.Name)).ToArray();
}
private void RemoveDeadTraits()
{
if (m_editingEntity.RemoveDeadTraits() > 0)
{
EditorUtility.SetDirty(m_editingEntity);
serializedObject.UpdateIfDirtyOrScript();
}
}
private bool hasValidTypeList
{
get { return m_traitGUIContent != null && m_availableTraitTypes != null; }
}
public override void OnInspectorGUI()
{
serializedObject.UpdateIfDirtyOrScript();
DrawTypeSelector();
EditorGUILayout.Separator();
DrawTraitList();
}
private void DrawTypeSelector()
{
EditorGUILayout.BeginHorizontal();
{
m_lastSelectedTraitType = EditorGUILayout.Popup(m_selectTypeLabel, m_lastSelectedTraitType, m_traitGUIContent);
if (GUILayout.Button(m_addLabel, GUILayout.Width(20.0f)))
{
var new_trait_type = m_availableTraitTypes[m_lastSelectedTraitType];
Undo.RecordObject(serializedObject.targetObject, "Undo Add " + new_trait_type.Name);
m_editingEntity.CreateTrait(new_trait_type);
serializedObject.SetIsDifferentCacheDirty();
serializedObject.UpdateIfDirtyOrScript();
EditorUtility.SetDirty(serializedObject.targetObject);
}
}
EditorGUILayout.EndHorizontal();
}
private void DrawTraitList()
{
var trait_list = serializedObject.FindProperty("m_traits");
var total_traits = trait_list.arraySize;
var is_dirty = false;
trait_list.isExpanded = EditorGUILayout.Foldout(trait_list.isExpanded, "Traits: " + total_traits.ToString());
if (trait_list.isExpanded && (total_traits > 0))
{
var should_remove = false;
var remove_idx = -1;
EditorGUI.indentLevel++;
string name_str = null;
for (var idx = 0; idx < total_traits; ++idx)
{
var trait_prop_element = trait_list.GetArrayElementAtIndex(idx);
var selected_trait = trait_prop_element.objectReferenceValue as Trait;
#region Trait Control Buttons
EditorGUILayout.BeginHorizontal();
{
if (selected_trait == null)
continue;
GUILayout.Space(-10.0f);
name_str = selected_trait.TraitName;
EditorGUILayout.LabelField(name_str);
GUILayout.FlexibleSpace();
if (selected_trait.gameObject != m_editingEntity.gameObject)
{
name_str = "Edit: " + selected_trait.gameObject.name;
if (GUILayout.Button(name_str))
HEditorUtility.SelectAndPing(selected_trait);
}
#region Removal
if (GUILayout.Button(m_removeLabel, GUILayout.Width(20.0f)))
{
remove_idx = idx;
should_remove = true;
}
#endregion Removal
}
EditorGUILayout.EndHorizontal();
#endregion
}
EditorGUI.indentLevel--;
#region Handle Removal
if (should_remove && remove_idx >= 0 && remove_idx < total_traits)
{
var remove_trait = m_editingEntity.GetTraitAtIndex(remove_idx);
var dependent_types = m_editingEntity.GetDependentsForTrait(remove_trait);
Verify.Assert(m_editingEntity.HasTrait(remove_trait));
if (dependent_types.Count == 0)
{
is_dirty |= true;
// capture the serialized field state for the trait list
Undo.RegisterFullObjectHierarchyUndo(m_editingEntity, "Removed Trait " + remove_trait.TraitName);
// remove trait from trait list
m_editingEntity.RemoveTrait(remove_trait);
remove_trait.Entity = null;
remove_trait.hideFlags = HideFlags.None;
// create an undo-able deletion
Undo.DestroyObjectImmediate(remove_trait);
serializedObject.SetIsDifferentCacheDirty();
serializedObject.UpdateIfDirtyOrScript();
is_dirty = true;
}
else if (dependent_types.Count > 0)
{
var display_str = dependent_types[0].Name;
if (dependent_types.Count > 3)
{
display_str += " and " + (dependent_types.Count - 1).ToString() + " other Traits";
}
else if (dependent_types.Count > 1)
{
for (var idx = 0; idx < dependent_types.Count; ++idx)
{
if (idx < dependent_types.Count - 1)
display_str += ", " + dependent_types[idx];
else
display_str += " and " + dependent_types[idx];
}
}
EditorUtility.DisplayDialog("Can't Remove Trait", "Cannot Remove " + remove_trait.TraitName + " because " + display_str + " depends on it!", "OK");
}
}
#endregion Handle Removal
}
is_dirty |= serializedObject.ApplyModifiedProperties();
if (is_dirty)
{
EditorUtility.SetDirty(m_editingEntity);
}
}
}
So in short we can say ,
-use repaint or redraw kind of keyword to re-update oninspectorgui()
-and use serialization ,To prevent getting disappear after playmode
By drawing functions I mean GUI/GUILayout/EditorGUI/EditorGUILayout functions, anything that is meant to be called in OnInspectorGUI() or other similar editor methods. For drawing in a scene editor, this would be the Handles family of functions, for example.