NodeCanvas Forums › Support › Can't add properties to StatementNode
I’m working on a dialogue system and wanted more control from the Statement Node.
I added the options for statements to be additive, wait for input, and have an end delay.
All of these changes are in the original Statement.cs and StatementNode.cs file. I updated the inspector and the fields are serialized, but whenever I change the custom values in the node editor, it isn’t reflected in the statement data sent through the dialogue events.
I have the values sent through the event printed the moment they’re received and they are always set to their default values.
Statement.cs
Here’s the modified interface.
1 2 3 4 5 6 7 8 9 10 11 12 |
///An interface to use for whats being said by a dialogue actor public interface IStatement { string text { get; } AudioClip audio { get; } bool additive { get; } bool waitForInput { get; } float endDelay { get; } string meta { get; } } |
And the modified class implementation
1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19 20 21 22 23 24 25 26 27 28 29 30 31 32 33 34 35 36 37 38 39 40 41 42 43 44 45 46 47 48 49 50 51 52 53 54 |
///Holds data of what's being said usualy by an actor [System.Serializable] public class Statement : IStatement { [SerializeField] private string _text = string.Empty; [SerializeField] private AudioClip _audio; [SerializeField] private bool _additive; [SerializeField] private bool _waitForInput = true; [SerializeField] private float _endDelay; [SerializeField] private string _meta = string.Empty; public string text { get { return _text; } set { _text = value; } } public AudioClip audio { get { return _audio; } set { _audio = value; } } public bool additive { get { return _additive; } set { _additive = value; } } public bool waitForInput { get { return _waitForInput; } set { _waitForInput = value; } } public float endDelay { get { return _endDelay; } set { _endDelay = value; } } public string meta { get { return _meta; } set { _meta = value; } } |
StatementNode.cs
1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19 20 21 22 23 24 25 26 27 28 29 30 31 32 33 34 35 36 37 38 39 40 41 42 43 44 45 46 47 48 49 50 51 52 53 54 55 56 |
using NodeCanvas.Framework; using ParadoxNotion.Design; using UnityEngine; namespace NodeCanvas.DialogueTrees{ [Name("Say")] [Description("Make the selected Dialogue Actor talk. You can make the text more dynamic by using variable names in square brackets\ne.g. [myVarName] or [Global/myVarName]")] public class StatementNode : DTNode{ [SerializeField] private Statement statement = new Statement("This is a dialogue text"); public override bool requireActorSelection{ get {return true;} } protected override Status OnExecute(Component agent, IBlackboard bb){ var tempStatement = statement.BlackboardReplace(bb); DialogueTree.RequestSubtitles( new SubtitlesRequestInfo(finalActor, tempStatement, OnStatementFinish) ); return Status.Running; } void OnStatementFinish(){ status = Status.Success; DLGTree.Continue(); } //////////////////////////////////////// ///////////GUI AND EDITOR STUFF///////// //////////////////////////////////////// #if UNITY_EDITOR protected override void OnNodeGUI(){ var displayText = statement.text.Length > 30? statement.text.Substring(0, 30) + "..." : statement.text; GUILayout.Label("\"<i> " + displayText + "</i> \""); } protected override void OnNodeInspectorGUI(){ base.OnNodeInspectorGUI(); var areaStyle = new GUIStyle(GUI.skin.GetStyle("TextArea")); areaStyle.wordWrap = true; GUILayout.Label("Dialogue Text"); statement.text = UnityEditor.EditorGUILayout.TextArea(statement.text, areaStyle, GUILayout.Height(100)); statement.audio = UnityEditor.EditorGUILayout.ObjectField("Audio File", statement.audio, typeof(AudioClip), false) as AudioClip; statement.additive = UnityEditor.EditorGUILayout.Toggle ("Additive", statement.additive); statement.waitForInput = UnityEditor.EditorGUILayout.Toggle ("Wait For Input", statement.waitForInput); statement.endDelay = UnityEditor.EditorGUILayout.FloatField ("End Delay", statement.endDelay); statement.meta = UnityEditor.EditorGUILayout.TextField("Metadata", statement.meta); } #endif } } |
Ok, I finally figured it out. The statement is sent through the BlackboardReplace method, which returns a new Statement. It uses a constructor that (obviously) has no idea of the custom properties I’ve added so the values are set to their defaults.
Hey,
You figured it out before my reply, but indeed, this is exactly what was happening 🙂
With that said, I’ve just changed BlackboardReplace to be more convenient by making a serialized copy instead of using a constructor to return a new statement, so that it is more convenient (and probably more correct), thus avoid mandatory adding your properties to the constructor.
– Add this on the first line of BlackboardReplace method:
1 2 3 |
var copy = ParadoxNotion.Serialization.JSONSerializer.Clone<Statement>(this); |
Return this by the end instead of the constructor:
1 2 3 4 |
copy.text = s; return copy; |
If you have any further problems, please let me know.
Thanks!
Join us on Discord: https://discord.gg/97q2Rjh
Thanks for the reply and alternative to constantly updating the constructor.