How can I serialize an Interface? (to replace Trigger strings)

I wanted to do change the onEnterAction and onExitAction to no longer be strings but instead be a Triggerable object. I created an interface called ITriggerable. I then went to change the DialogueNode as follows but it doesn’t serialize in the inspector. It seems this is a known limitation of Unity. [SeralizeReference] doesn’t work. I tried searching many forums but couldn’t understand some of the recommendations.

My fallback plan is to take in a UnityEngine.Object and then in OnValidate reject anything that doesn’t implement ITriggerable.

    public class DialogueNode : ScriptableObject
    {

        [SerializeField] ITriggerable onEnterAction;
        [SerializeField] ITriggerable onExitAction;
  }
namespace RPG.Core
{
    public interface ITriggerable
    {
        public void Trigger();
    }
}

To see what I want to do and why I need an interface here are other relevant parts of the code. As you can see I want things that inherit from MonoBehaviors and ScriptableObjects to implement ITriggerable. So this would allow me to

  • trigger a quest to start
  • trigger a quest objective to be completed
  • trigger an aggro group to activate

namespace RPG.Dialogue
{
    public class PlayerConversant : MonoBehaviour {
        private void TriggerEnterAction()
        {
            if (currentNode != null)
            {
                TriggerAction(currentNode.GetOnEnterAction());
            }
        }

        private void TriggerExitAction()
        {
            if (currentNode != null)
            {
                TriggerAction(currentNode.GetOnExitAction());
            }
        }
        private void TriggerAction(ITriggerable action)
        {
            if (action == null) return;

            action.Trigger();
        }
    }
}
using RPG.Core;
using UnityEngine;

namespace RPG.Combat
{
    public class AggroGroup : MonoBehaviour, ITriggerable
    {
        public void Trigger()
        {
            Activate(true);
        }
    }
}
using RPG.Core;
using UnityEngine;

namespace RPG.Quests
{
    [CreateAssetMenu(fileName = "QuestCompletion", menuName = "RPG/Quest/Completion", order = 0)]
    public class QuestCompletion : ScriptableObject, ITriggerable
    {
        [SerializeField] Quest quest;
        [SerializeField] string objective;
        public void Trigger()
        {
            QuestList questList = GameObject.FindGameObjectWithTag("Player").GetComponent<QuestList>();
            questList.CompleteObjective(quest, objective);
        }
    }
}
    public class Quest : ScriptableObject, ITriggerable
    {
        public void Trigger()
        {
            QuestList questList = GameObject.FindGameObjectWithTag("Player").GetComponent<QuestList>();
            questList.AddQuest(this);
        }
    }
1 Like

Hi, you’ve accidentally posted this question in the Blender 3D forum.

I now have it working with this except it’s quite annoying that the picker in the inspector doesn’t filter. I would love to get this working with an Interface. It is SOOO much easier to set up triggers now.

:slight_smile: No more dialogue triggers, no more quest givers, no more quest completion monobehaviors, no more magic strings :slight_smile:

Anyone have a better suggestion than my OnValidate trick though?

Also another small issue. I cannot drag an item from the scene into this. I guess that makes sense. It still works with prefabs.

Sorry. Fixed.

1 Like

Repeat after me: Custom Inspector…

Amen

Repeat after me: Custom Inspector

Can’t help you there. You cannot serialize a scene reference in a ScriptableObject or Prefab. There is another solution for that, however, albeit it has some limitations (and opens up possibities at the same time).

using RPG.Core;
using UnityEngine;

namespace RPG.Dialogue
{
    public class DialoguePassthrough : ScriptableObject, ITriggerable
    {
        public event System.Action TriggerActivated;
        
        public void Trigger()
        {
            TriggerActivated?.Invoke();
        }
    }
}
using UnityEngine;
using UnityEngine.Events;

namespace RPG.Dialogue
{
    public class DialoguePassthroughTriggerReceiver : MonoBehaviour
    {
        [SerializeField] private DialoguePassthrough trigger;

        public UnityEvent OnTrigger;
        void OnEnable()
        {
            if (trigger != null)
            {
                trigger.TriggerActivated += Trigger;
            }
        }

        private void OnDisable()
        {
            if (trigger != null)
            {
                trigger.TriggerActivated -= Trigger;
            }
        }

        private void Trigger()
        {
            OnTrigger?.Invoke();
        }
    }
}

Known Limitations:

  • If you have more than one scene Object using the same DialoguePassthrough, they will all receive the trigger.

Known Possibilities:

  • If you have more than one scene Object using the same DialoguePassthrough, they will all receive the trigger.

So much to learn so little time. :slight_smile: i have to read through your property drawer posting. Are the basic building blocks for solving this problem in there?

Yes, and no. The problem, in this case, is that you also can’t write a PropertyDrawer for an interface…

That means that you’ll actually have to write an Editor for the entire DialogueNode class and then write custom code to present all MonoBehaviours and ScriptableObjects from the assets that implement the interface.

So that’s another thing I’ve been meaning to learn how to do. I would like to have within the inspector, have the acceptable values of one field depend upon what the user input in another. For example you have an enum field and based on what someone picks then another field changes how it looks in the inspector.

Imagine for example you have one field n the inspector that takes in a certain class of a scriptableobject and another adjacent drop down field where the dropdown values are specified by a method on the scriptable object you just linked in the inspector.

Is that kind of thing possible?

If you look carefully at the Condition Property editor, you’ll see that based on the IPredicate, different types of fields are shown.

1 Like

This topic was automatically closed 24 hours after the last reply. New replies are no longer allowed.

Privacy & Terms