I'm writing custom interactable code and hand calling DialogueManager.StartConversation instead of using a Trigger. However, I want my Interactable class to reveal the Conversation Picker drop down menu in the inspector, as it does for ConversationTriggers.
I poked around the source code, and I see the ConversationPicker class, but I can't figure out how you put that in the ConversationTrigger script. All I see there is a public string field for Conversation.
I have it working with a string, and I know I can then check that string against the database pretty quickly, but ideally I'd be able to use the dropdown menu just like you do on the ConversationTrigger. Is this possible?
Thanks again!
Using the ConversationPicker dropdown in the inspector
Using the ConversationPicker dropdown in the inspector
Hi,
Yup, you can use the same ConversationPicker class. You need to write a custom inspector editor. Try something like this:
Interactable.cs:
using UnityEngine;
using PixelCrushers.DialogueSystem;
public class Interactable : MonoBehaviour {
// The conversation to run when interacted.
[HideInInspector] // Hide in default inspector; we'll draw it custom.
public string conversation;
// Your other data:
public bool someBool;
public float someFloat; // etc.
// Used internally by ConversationPicker:
[HideInInspector] public DialogueDatabase selectedDatabase = null;
[HideInInspector] public bool useConversationPicker = false;
}
InteractableEditor.cs: (put this inside a folder named 'Editor')
using UnityEngine;
using UnityEditor;
using PixelCrushers.DialogueSystem;
[CustomEditor(typeof(Interactable))]
public class InteractableEditor : Editor {
// An instance of the ConversationPicker editor GUI helper:
private ConversationPicker conversationPicker = null;
public void OnEnable() {
var interactable = target as Interactable;
conversationPicker = new ConversationPicker(interactable.selectedDatabase, interactable.conversation, interactable.useConversationPicker);
}
public override void OnInspectorGUI() {
DrawConversationPicker(); // Draw custom conversation picker.
DrawDefaultInspector(); // Then draw your other data.
}
private void DrawConversationPicker() {
var interactable = target as Interactable;
conversationPicker.Draw();
interactable.conversation = conversationPicker.currentConversation;
interactable.useConversationPicker = conversationPicker.usePicker;
interactable.selectedDatabase = conversationPicker.database;
}
}
Yup, you can use the same ConversationPicker class. You need to write a custom inspector editor. Try something like this:
Interactable.cs:
using UnityEngine;
using PixelCrushers.DialogueSystem;
public class Interactable : MonoBehaviour {
// The conversation to run when interacted.
[HideInInspector] // Hide in default inspector; we'll draw it custom.
public string conversation;
// Your other data:
public bool someBool;
public float someFloat; // etc.
// Used internally by ConversationPicker:
[HideInInspector] public DialogueDatabase selectedDatabase = null;
[HideInInspector] public bool useConversationPicker = false;
}
InteractableEditor.cs: (put this inside a folder named 'Editor')
using UnityEngine;
using UnityEditor;
using PixelCrushers.DialogueSystem;
[CustomEditor(typeof(Interactable))]
public class InteractableEditor : Editor {
// An instance of the ConversationPicker editor GUI helper:
private ConversationPicker conversationPicker = null;
public void OnEnable() {
var interactable = target as Interactable;
conversationPicker = new ConversationPicker(interactable.selectedDatabase, interactable.conversation, interactable.useConversationPicker);
}
public override void OnInspectorGUI() {
DrawConversationPicker(); // Draw custom conversation picker.
DrawDefaultInspector(); // Then draw your other data.
}
private void DrawConversationPicker() {
var interactable = target as Interactable;
conversationPicker.Draw();
interactable.conversation = conversationPicker.currentConversation;
interactable.useConversationPicker = conversationPicker.usePicker;
interactable.selectedDatabase = conversationPicker.database;
}
}
Using the ConversationPicker dropdown in the inspector
I wasn't getting this to work right away, and realized that it's (I think) because my Interactable class is a base class, and I guess this code isn't playing nicely with polymorphism? Other base class members show up fine in the inspector (e.g. my previous public string conversation), but the custom editor code doesn't seem to work. It simply doesn't show up. I confirmed that changing the editor script to use a subclass of Interactable does indeed work, but obviously then I'd need to write one for every subclass, negating the point of my base Interactable class.
Any tips for how I might solve this?
Any tips for how I might solve this?
Using the ConversationPicker dropdown in the inspector
Create empty editor subclasses:
[CustomEditor(typeof(Interactable))]
public class InteractableEditor : Editor {
//--All of the ConversationPicker functionality goes here--
}
[CustomEditor(typeof(ChildInteractable1))]
public class ChildInteractable1Editor : InteractableEditor { }
[CustomEditor(typeof(ChildInteractable2))]
public class ChildInteractable2Editor : InteractableEditor { }
etc.
[CustomEditor(typeof(Interactable))]
public class InteractableEditor : Editor {
//--All of the ConversationPicker functionality goes here--
}
[CustomEditor(typeof(ChildInteractable1))]
public class ChildInteractable1Editor : InteractableEditor { }
[CustomEditor(typeof(ChildInteractable2))]
public class ChildInteractable2Editor : InteractableEditor { }
etc.
Using the ConversationPicker dropdown in the inspector
Gotcha. That gave me an idea for a slightly easier solution (for my project). Here's what I did, in case anyone else finds this useful.
Rather than making a new editor subclass for every child of Interactable that I create, I just made the dropdown menu itself its own component, exactly how you have it above.
Then my base Interactable class has a private string _conversation, and in Awake(), I just GetComponent to the dropdown script and grab the conversation.
Now I just need to add a ConversationDropdown script to any Interactable object. It's not perfect, but I think it does save me time compared to remembering to make a blank editor script for every single Interactable object.
Tony, if this sets off any red flags for you, let me know.
Rather than making a new editor subclass for every child of Interactable that I create, I just made the dropdown menu itself its own component, exactly how you have it above.
Then my base Interactable class has a private string _conversation, and in Awake(), I just GetComponent to the dropdown script and grab the conversation.
Now I just need to add a ConversationDropdown script to any Interactable object. It's not perfect, but I think it does save me time compared to remembering to make a blank editor script for every single Interactable object.
Tony, if this sets off any red flags for you, let me know.
Using the ConversationPicker dropdown in the inspector
That works. I'm a fan of composition. You never know when another class (not derived from Interactable) might also need a reference to a conversation.
If you ever do want to pull it back into Interactable, you could use a custom property attribute. The class definition might look like this:
public class Interactable : MonoBehaviour {
[ConversationTitle]
public string conversation;
}
But that glosses over the complicated process of writing ConversationTitleAttribute and ConversationTitleDrawer classes that would implement a drop-down picker. If your current solution works, it's not worth the headache to switch to a custom property attribute.
If you ever do want to pull it back into Interactable, you could use a custom property attribute. The class definition might look like this:
public class Interactable : MonoBehaviour {
[ConversationTitle]
public string conversation;
}
But that glosses over the complicated process of writing ConversationTitleAttribute and ConversationTitleDrawer classes that would implement a drop-down picker. If your current solution works, it's not worth the headache to switch to a custom property attribute.