- Home /
Adding To Array From Editor
I have an editor script that displays a window where you enter dialog for the characters to say, I have another script called dialog controller which displays the dialog in the game. What I want is to be able to type stuff here and then hit an add button and it will add the string as an element in the array in the dialog controller script. By the way the array is a JS array, if that helps any. I'm not getting any errors but the code simply isn't adding to the array. What am I doing wrong here?
import UnityEditor;
@CustomEditor(DialogController)
var dialog : String = "Enter Dialog";
var player : SerializedProperty;
class MyPlayerEditor extends Editor {
function OnEnable () {
// Setup the SerializedProperties
player = serializedObject.FindProperty ("playerDialog");
}
}
class Dialog extends EditorWindow {
@MenuItem("Tools/Dialog Editor")
static function Init() {
var window = GetWindow(Dialog);
window.Show();
}
function OnGUI() {
dialog = EditorGUI.TextArea(Rect(3,3,position.width - 6, position.height - 65), dialog);
if(GUI.Button(Rect(0, position.height - 60, position.width, 25), "Add"))
player.Add (dialog);
if(GUI.Button(Rect(0, position.height - 30, position.width, 25), "Close"))
this.Close();
}
}
Answer by phodges · Oct 19, 2012 at 05:43 AM
It might be worth you taking a look at the documentation for SerializedObject and SerializedProperty. Here are a few things to consider:
call update on your serializedObject before testing and changing properties.
work with the serialized property's methods to make changes: InsertArrayElementAtIndex should be useful to you
when you're finished a round of changes, call ApplyModifiedProperties on the object
I'm not sure how these functions work and there really aren't any examples of them, can you provide some?
Answer by phodges · Oct 19, 2012 at 09:19 AM
EDIT TO EDIT - As also discussed, it does seem a little unnecessary to create a custom editor window for this use case, however for the sake of completeness I have written one (in C#) and added a couple of features. As the answer to this question is now somewhat sprawling I have added the source to github, and it can be found here
EDIT - Added a javascript equivalent. As mentioned below, it really is worth reading Extending the Editor, SerializedObject and SerializedProperty as there is lots of useful information there.
Ok. Here's something really quick that does something similar to what you are aiming for:
// COMPONENT FILE
using UnityEngine;
public class TextDemo : MonoBehaviour
{
public string[] messages;
}
// EDITOR FILE
using UnityEditor;
using UnityEngine;
[CustomEditor(typeof(TextDemo))]
[CanEditMultipleObjects]
class TextDemoEd : Editor
{
SerializedProperty _propMessage;
string _content;
void OnEnable() {
_propMessage = serializedObject.FindProperty("messages");
if (!_propMessage.isArray) {
// You shouldn't expect to see this.
Debug.LogError("Property is not an array!");
}
}
public override void OnInspectorGUI() {
serializedObject.Update();
base.DrawDefaultInspector();
bool enlarge = false;
EditorGUILayout.BeginVertical();
EditorGUILayout.LabelField(string.Format("Message count = {0}", _propMessage.arraySize));
_content = EditorGUILayout.TextArea(_content);
if (!string.IsNullOrEmpty(_content) && GUILayout.Button("Add")) {
enlarge = true;
}
EditorGUILayout.EndVertical();
if (enlarge) {
EnlargeArray();
serializedObject.ApplyModifiedProperties();
// I'm not in love with setting the array value this way.
// Can't see an appropriate property method though.
TextDemo t = target as TextDemo;
t.messages[t.messages.Length-1] = _content;
_content = "";
}
}
void EnlargeArray() {
int enlarged = _propMessage.arraySize;
_propMessage.InsertArrayElementAtIndex(enlarged);
}
}
// JAVASCRIPT VERSION
// COMPONENT FILE - TextDemo2.js
#pragma strict
public var messages : String[];
// EDITOR FILE - Editor/TextDemo2Ed.js
#pragma strict
@CustomEditor (TextDemo2) @CanEditMultipleObjects class TextDemo2Ed extends Editor {
var _propMessages : SerializedProperty;
var _content : String;
function OnEnable() {
_propMessages = serializedObject.FindProperty("messages");
if (!_propMessages){
Debug.LogError("Could not find messages property");
}else{
Debug.Log("Found property" );
}
}
function OnInspectorGUI() {
serializedObject.Update();
DrawDefaultInspector();
var enlarge : boolean = false;
if (_propMessages) {
EditorGUILayout.BeginVertical();
EditorGUILayout.LabelField(String.Format("Message count= {0}", _propMessages.arraySize));
_content = EditorGUILayout.TextArea(_content);
if (!String.IsNullOrEmpty(_content) && GUILayout.Button("Add")) {
enlarge = true;
}
EditorGUILayout.EndVertical();
}else{
EditorGUILayout.LabelField("Property was not found");
}
if (enlarge) {
EnlargeArray();
serializedObject.ApplyModifiedProperties();
var t : TextDemo2 = target as TextDemo2;
t.messages[t.messages.Length - 1] = _content;
_content = "";
}
}
function EnlargeArray() {
var enlarged : int _propMessages.arraySize;
_propMessages.InsertArrayElementAtIndex(enlarged);
}
}
How are you getting the serialized object? I keep getting error.
$$anonymous$$y example relies on you adding the TextDemo component to an object. The TextDemoEd component should then be placed in an Editor folder.
I get what you said above but the I keep getting an error that says the serializedObject is an unknown identifier? Perhaps you can rewrite your code in JS because I translated it as best as I could and there are still a few errors.
It's important to mention that the errors you saw were in a completely different piece of code (i.e. one written by you). I've added a JS version of the script; the formatting messed up, but you ought to be able to copy and use it.
You've now got implementations both as custom inspectors and now as an editor window. You would be hard pressed to say you aren't getting good value out of this question.
Answer by Bunny83 · Oct 20, 2012 at 11:52 PM
Your main problem is that you define two classes in one file. Unity need it's classes in seperate files and the file name has to match the class name. Since you can omit the class construct for classes that are derived from MonoBehaviour, you have to write it out for classes derived from Editor or EditorWindow.
Your two variables "dialog" and "player" are declared outside of both classes. I guess the filename match one of your classes, so the variable will belong to this class.
You can't just cross access member variables between classes. If you want to access a variable from another class you need a reference to an instance of the class.
It would help to know your script file names and to see how "DialogController" is defined.
To answer your question in the comments, serializedObject is a variable in the Editor class. An Editor is an inspector "plugin" which shows the GUI for a certain class when it's selected. In the first place an EditorWindow has nothing to do with the inspector or the current selection. However you can use the Selection class in your EditorWindow to get the current selected onject.
I suggest you read the docs on Editor and EditorWindow again. Pay attention to the first paragraph which explains what this classes are good for. There are also examples on the pages.
Also like phodges said, take a look at SerializedObject and SerializedProperty.
edit
Since you want to use your EditorWindow like an inspector you have to obtain a serialized object manually. Something like that:
class Dialog extends EditorWindow
{
var serObj : SerializedObject;
@MenuItem("Tools/Dialog Editor")
static function Init()
{
var window = GetWindow(Dialog);
window.Show();
}
function OnSelectionChange()
{
var objs = Selection.GetFiltered(DialogController, SelectionMode.Editable);
if (objs != null && objs.Length > 0)
{
serObj = new SerializedObject(objs)
// setup any SerializedProperties you need here
}
else
serObj = null;
}
function OnGUI()
{
if (serObj == null)
return; //No object selected that contains a DialogController
serObj.Update();
// Draw your GUI here
}
}
I'm not sure why you want this in an Editorwindow. The Inspector is made for editing selected components, so why don't use extend the inspector for your DialogController?
When you implement the OnInspectorGUI like this you still have the same inspector but with additional GUI elements at the end (or start)
@CustomEditor(DialogController)
class MyPlayerEditor extends Editor
{
var player : SerializedProperty;
function OnEnable ()
{
// Setup SerializedProperties
player = serializedObject.FindProperty ("playerDialog");
}
function OnInspectorGUI()
{
serializedObject.Update();
// Draw additional GUI before the normal inspector
DrawDefaultInspector();
// Draw additional GUI after the normal inspector
}
}
Just to clarify I'm adding to this array from a window and not the inspector. From what I've read there isn't a serialized object variable when editing from a window.
I know, but you use an inspector (your $$anonymous$$yPlayerEditor class) and an EditorWindow (your Dialog class). Those are two seperate classes for totally different purposes. First both classes need to be in a seperate file because the file name has to match the class name.
Second, i guess all you actually want is a serializedobject of the current selected object(s) inside your EditorWindow. In this case you don't need an inspector at all. Just create a SerializedObject in OnSelectionChange
Your answer
Follow this Question
Related Questions
Create GUI based on an array 2 Answers
changing GUI Button text with a string array 2 Answers
Split string in C#? 1 Answer
Custom dialog in editor 3 Answers
Converting Text to a String Array Format 2 Answers