Reputation: 11325
The editor script.
The problem is that I see in the ReorderableList items from index 0 to 17 and then many more item but they are all Missing. And when trying to delete them they are not deleted.
I want to add new items using the MenuItem and the Selection. I want to add more propertied to per item like Undo so Undo will remove from the gameobject in the list the BoxCollider and the script Whilefun.FPEKit.FPEInteractablePickupScript
The idea is that when I select an gameobject in the hierarchy if I'm doing right click and select Generate as Pickup Item only then add the BoxCollider and the script Whilefun.FPEKit.FPEInteractablePickupScript and only then add that selected gameobject as item to the ReorderableList and if I make in the ReorderableList on one of them items right click with the mouse and select undo then first remove the Box Collider and the Whilefun.FPEKit.FPEInteractablePickupScript and then remove the gameobject item from the ReorderableList.
using System;
using System.Collections;
using System.Collections.Generic;
using UnityEditor;
using UnityEditorInternal;
using UnityEngine;
[CustomEditor(typeof(PickupObjects))]
public class PickupObjectsEditor : Editor
{
private static List<GameObject> pickeditems = new List<GameObject>();
private static bool picked = false;
[MenuItem("GameObject/Generate as Pickup Item", false, 30)]
public static void GeneratePickupItems()
{
if (Selection.gameObjects.Length > 0)
{
pickeditems.Clear();
for (int i = 0; i < Selection.gameObjects.Length; i++)
{
if (Selection.gameObjects[i].GetComponent<Whilefun.FPEKit.FPEInteractablePickupScript>() == null)
{
Selection.gameObjects[i].AddComponent<BoxCollider>();
Selection.gameObjects[i].AddComponent<Whilefun.FPEKit.FPEInteractablePickupScript>();
}
Selection.gameObjects[i].layer = 9;
Selection.gameObjects[i].tag = "Pickup Item";
pickeditems.Add(Selection.gameObjects[i]);
}
picked = true;
}
}
PickupObjects _target;
private ReorderableList _myList;
public void OnEnable()
{
_target = (PickupObjects)target;
_myList = new ReorderableList(serializedObject, serializedObject.FindProperty("pickUpObjects"), true, true, true, true);
_myList.drawHeaderCallback = rect =>
{
EditorGUI.LabelField(rect, "My Reorderable List", EditorStyles.boldLabel);
};
_myList.drawElementCallback =
(Rect rect, int index, bool isActive, bool isFocused) =>
{
var element = _myList.serializedProperty.GetArrayElementAtIndex(index);
EditorGUI.ObjectField(new Rect(rect.x, rect.y, rect.width, EditorGUIUtility.singleLineHeight), element, GUIContent.none);
};
}
public override void OnInspectorGUI()
{
serializedObject.Update();
_myList.DoLayoutList();
serializedObject.ApplyModifiedProperties();
}
}
And the mono script
using System.Collections.Generic;
using UnityEditor;
using UnityEngine;
public class PickupObjects : MonoBehaviour
{
public List<GameObject> pickUpObjects = new List<GameObject>();
}
This is a screenshot of the ReorderableList. All messed :
Upvotes: 0
Views: 4329
Reputation: 90724
As mentioned Missing
actually means the reference was set before but according object was deleted/destroyed.
Since you do pickedItems.Clear()
that list should never contain more then the selection actually.
In order to add an additional button you can simply extend your drawElement callback like e.g.
public void OnEnable()
{
//_target = (PickupObjects)target;
_myList = new ReorderableList(serializedObject, serializedObject.FindProperty("pickUpObjects"))
{
draggable = true,
// I wouldn't show the Add button
// since you have your own add functionality
displayAdd = false,
// I wouldn't show the remove button either
// since you want a custom button for removing items
displayRemove = false,
drawHeaderCallback = rect => EditorGUI.LabelField(rect, "My Reorderable List", EditorStyles.boldLabel),
drawElementCallback = (rect, index, isActive, isFocused) =>
{
if (index > _myList.serializedProperty.arraySize -1 ) return;
var element = _myList.serializedProperty.GetArrayElementAtIndex(index);
// In order to prevent errors when directly changing the reference
// I would forbid the direct editing of thisfield
EditorGUI.BeginDisabledGroup(true);
{
EditorGUI.PropertyField(new Rect(rect.x, rect.y, rect.width - 20, EditorGUIUtility.singleLineHeight), element, GUIContent.none);
}
EditorGUI.EndDisabledGroup();
if (GUI.Button(new Rect(rect.x + rect.width - 20, rect.y, 20, EditorGUIUtility.singleLineHeight), "X"))
{
var obj = (GameObject) element.objectReferenceValue;
if (obj)
{
var boxCollider = obj.GetComponent<BoxCollider>();
if (boxCollider) DestroyImmediate(boxCollider);
var picker = obj.GetComponent<Whilefun.FPEKit.FPEInteractablePickupScript>();
if(picker) DestroyImmediate(picker);
}
if(_myList.serializedProperty.GetArrayElementAtIndex(index).objectReferenceValue != null)
_myList.serializedProperty.DeleteArrayElementAtIndex(index);
_myList.serializedProperty.DeleteArrayElementAtIndex(index);
serializedObject.ApplyModifiedProperties();
}
}
};
}
Also I just noted that you removed the entire part where you actually ADD objects to the list!
public override void OnInspectorGUI()
{
var list = serializedObject.FindProperty("pickUpObjects");
serializedObject.Update();
if(picked)
{
picked = false;
foreach(var newEntry in pickeditems)
{
// check if already contains this item
bool alreadyPresent = false;
for(var i=0; i < list.arraySize; i++)
{
if((GameObject)list.GetArrayElementAtIndex(i).objectReferenceValue == newEntry)
{
alreadyPresent = true;
break;
}
}
if(alreadyPresent) continue;
// Otherwise add via the serializedProperty
list.arraySize++;
list.GetArrayElementAtIndex(list.arraySize - 1).objectReferenceValue = newEntry;
}
pickeditems.Clear();
}
_myList.DoLayoutList();
serializedObject.ApplyModifiedProperties();
}
Since I don't have your component I did it only with the BoxCollider
for the demo ;)
As you can see after adding the objects to the list they all hace the BoxCollider
, after removing them they do not have it anymore.
Upvotes: 2