Hi! I’m a bit of a novice with C# but I’m very familiar with many of the Unity tools and concepts. I’d appreciate some help!
I’ve been following this tutorial, but it doesn’t work well when I swap simple variables like floats and strings out for Unity Events.
My goal:
I’m making a scripted event system which could be triggered from anything. It should fire off a list of Unity Events with delays between each one. It should have a custom inspector component so that the list is reorderable.
My problem:
Correctly displaying this list as a Reorderable List in a custom Inspector component.
My setup:
I’ve created a struct, which uses a UnityEvent (the action) and a float (the delay) for each object in the list.
I then have another script as a container (I think? not too sure of the correct terminology there) which iterates through the list and calls each event in order.
This works exactly how I want it to, but the Inspector tools for this are a bit difficult to work with because it’s not reorderable. Here’s how it looks by default:
When I add the custom editor script, everything overlaps each other. Here’s the same list with the custom inspector:
Here’s all the code:
The event struct:
using UnityEngine;
using UnityEngine.Events;
using System;
// An event which can be called as part of a Scripted Sequence
[Serializable]
public struct ScriptedSequenceEvent {
public float delay;
public UnityEvent scriptedEvent;
}
Container for the events. Also processes the list when I call the Scripted Sequence:
using System.Collections;
using System.Collections.Generic;
using UnityEngine;
// A container for the events
public class ScriptedSequence : MonoBehaviour {
private IEnumerator sequenceCoroutine;
public bool startAutomatically;
public bool onlyTriggerOnce;
private bool started = false;
// The list of events
public List<ScriptedSequenceEvent> events = new List<ScriptedSequenceEvent>();
void Start () {
if (startAutomatically)
StartScriptedSequence ();
}
public void StartScriptedSequence () {
if (!onlyTriggerOnce) {
BeginSequence ();
} else {
if (!started) {
BeginSequence ();
}
}
}
void BeginSequence () {
started = true;
sequenceCoroutine = ProcessSequence ();
StartCoroutine (sequenceCoroutine);
}
private IEnumerator ProcessSequence () {
int i = 0;
// Iterate through each item in the list.
foreach(ScriptedSequenceEvent currentEvent in events) {
// Wait for the delay, if it's > 0.
if (currentEvent.delay > 0f)
yield return new WaitForSeconds (currentEvent.delay);
// Invoke the event.
currentEvent.scriptedEvent.Invoke ();
// Increase the current iteration number so we move on to the next one in the next loop.
i++;
}
}
}
Custom Inspector code:
using UnityEngine;
using UnityEditor;
using UnityEditorInternal;
// The custom inspector script which lets use make the list of events reorderable, and lets us draw it how we want.
[CustomEditor(typeof(ScriptedSequence))]
public class ScriptedSequence_Editor : Editor {
private ReorderableList list;
private void OnEnable() {
// Create the list
list = new ReorderableList (serializedObject, serializedObject.FindProperty ("events"), true, true, true, true);
// Draw header label
list.drawHeaderCallback = (Rect rect) => {
EditorGUI.LabelField(rect, "Events");
};
// Draw each element in the list
list.drawElementCallback =
(Rect rect, int index, bool isActive, bool isFocused) => {
var element = list.serializedProperty.GetArrayElementAtIndex(index);
rect.y += 2;
EditorGUI.PropertyField (
new Rect(rect.x, rect.y, rect.width - 30, EditorGUIUtility.singleLineHeight),
element.FindPropertyRelative("scriptedEvent"), GUIContent.none);
EditorGUI.PropertyField (
new Rect(rect.x + rect.width - 25, rect.y, 25, EditorGUIUtility.singleLineHeight),
element.FindPropertyRelative("delay"), GUIContent.none);
};
}
public override void OnInspectorGUI() {
serializedObject.Update ();
list.DoLayoutList ();
serializedObject.ApplyModifiedProperties ();
}
}
Thanks in advance!