Search Unity

  1. Megacity Metro Demo now available. Download now.
    Dismiss Notice
  2. Unity support for visionOS is now available. Learn more in our blog post.
    Dismiss Notice

NodeCanvas - (Behaviour Trees | State Machines | Dialogue Trees)

Discussion in 'Assets and Asset Store' started by nuverian, Feb 8, 2014.

  1. Haagndaaz

    Haagndaaz

    Joined:
    Feb 20, 2013
    Posts:
    232
    Hm, thanks for the info! What I am trying to use this for is to be able to have my blackboard in a separate scene and be able to allow a programmer to pick and assign variables in their scripts using the blackboard, so if possible I need to be able to assign via inspector, not through hardcoding. Any ideas? I got this working just fine using NodeCanvas, but needing blackboards for a little more custom stuff
     
  2. BTables

    BTables

    Joined:
    Jan 18, 2014
    Posts:
    61
    Hi there,

    I am trying to integrate NodeCanvas in as a client side predicted state machine for player equipment. I must say the codebase is very well written, and very extensible. I was able to quickly implement my own State machine that mimics mechanim's behavior of each node having a duration, with the added functionality of being able to re-wind / replay the simulation in a single frame.

    Only point of confusion now is how blackboards are supposed to work when not being driven by the standard FSMOwner.

    As my state machines are loaded and destroyed as a player equips items, I am saving my FSM as an asset that is either instantiated or re-deserialized from JSON on equip (not sure what solution will be faster at this point still doing RnD). I then initiate all method calls myself as they are done inside a synchronized tick with movement / metabolism code that isn't directly bound to the update loop.

    The thing that seems odd, is the only way to edit a state machine with the context of a blackboard is to use FSM Owner on a gameobject with a blackboard script attached. You can then serialize out the state machine with the links to the blackboard (looks like these are just name links), and I am unclear if the blackboard default values are written with it or not. Secondly I am wondering why there isn't a similar feature to save a blackboard asset to the project with the variable names and default values.

    I would expect to be able to use a blackboard in the editor while modifying an asset by clicking something like "create internal blackboard" that is bound to the asset. Am I missing something?
     
  3. nuverian

    nuverian

    Joined:
    Oct 3, 2011
    Posts:
    2,087
    Sorry for the late replies

    Hello,
    Unfortunately using BBParameters as is in normal monobehaviours is not really possible to do in a way that it's worth it. The BBParameters have to be correctly serialized/deserialized to json as well as be set the blackboard reference to read/write from correctly. So there are some steps that need to be done and doing those steps in each monobehaviour that you need use BBParameters will be tedious and can be error prone. I will take another look if this can somehow be more easy (less steps/code) to be achieved and let you know.
    Thanks.

    Hello,

    Thanks. I am really glad you like NodeCanvas and to hear that you've extended it to create your own system :)
    The graphs and blackboards are two completely separate elements that work together. Only the blackboard has the actual variable data (value, binding etc), while task and nodes in the graphs use what's called BBParameter, which can optionaly be linked to read/write from/to a variable on the blackboard. As such, when the graph is serialized the variables of the blackboards do not, but the BBParameters of course do. Thus to answer your first question, the blackboard variables values only serialize/deserialize along with the blackboard and when it does.

    The reason that graph and blackboards are separate, is so that 1) A graph can be parametrized with different blackboards, so that the same graph behaves differently depending on the blackboard it's set to read (which is usually taken from the agent), and 2) So that it's possible to have scene object references assigned for variables even when the agent is using an graph asset instead of bound, which would otherwise would not be possible (assets can't have scene object references).

    Here are the two scripts required to create blackboard assets if you require, which I have already made for a feature I'm working on. This BlackboardAsset, just like the other normal Blackboard, can also be provided to a graph to use when it is started via Graph.StartGraph(Component agent, IBlackboard blackboard).
    Code (CSharp):
    1. using UnityEngine;
    2. using System.Collections.Generic;
    3. using NodeCanvas.Framework;
    4. using NodeCanvas.Framework.Internal;
    5. using ParadoxNotion.Serialization;
    6. using ParadoxNotion.Design;
    7.  
    8. namespace NodeCanvas.Framework{
    9.  
    10.     public class BlackboardAsset : ScriptableObject, ISerializationCallbackReceiver, IBlackboard{
    11.  
    12.         [SerializeField]
    13.         private string _serializedBlackboard;
    14.         [SerializeField]
    15.         private List<UnityEngine.Object> _objectReferences;
    16.  
    17.         [System.NonSerialized]
    18.         private BlackboardSource _blackboard = new BlackboardSource();
    19.  
    20.         //serialize blackboard variables to json
    21.         public void OnBeforeSerialize(){
    22.             _objectReferences = new List<UnityEngine.Object>();
    23.             _serializedBlackboard = JSONSerializer.Serialize(typeof(BlackboardSource), _blackboard, false, _objectReferences);
    24.         }
    25.  
    26.         //deserialize blackboard variables from json
    27.         public void OnAfterDeserialize(){
    28.             _blackboard = JSONSerializer.Deserialize<BlackboardSource>(_serializedBlackboard, _objectReferences);
    29.             if (_blackboard == null) _blackboard = new BlackboardSource();
    30.         }
    31.  
    32.         new public string name{
    33.             get {return string.IsNullOrEmpty(_blackboard.name)? base.name + "_BB" : _blackboard.name;}
    34.             set    {_blackboard.name = value;}
    35.         }
    36.  
    37.         ///An indexer to access variables on the blackboard. It's recomended to use GetValue<T> instead
    38.         public object this[string varName]{
    39.             get { return _blackboard[varName]; }
    40.             set { SetValue(varName, value); }
    41.         }
    42.  
    43.         ///The raw variables dictionary. It's highly recomended to use the methods available to access it though
    44.         public Dictionary<string, Variable> variables{
    45.             get {return _blackboard.variables;}
    46.             set {_blackboard.variables = value;}
    47.         }
    48.  
    49.         ///The GameObject target to do variable/property binding
    50.         public GameObject propertiesBindTarget{
    51.             get {return null;}
    52.         }
    53.  
    54.         ///Add a new variable of name and type
    55.         public Variable AddVariable(string name, System.Type type){
    56.             return _blackboard.AddVariable(name, type);
    57.         }
    58.  
    59.         ///Get a Variable of name and optionaly type
    60.         public Variable GetVariable(string name, System.Type ofType = null){
    61.             return _blackboard.GetVariable(name, ofType);
    62.         }
    63.  
    64.         //Generic version of get variable
    65.         public Variable<T> GetVariable<T>(string name){
    66.             return _blackboard.GetVariable<T>(name);
    67.         }
    68.  
    69.         ///Get the variable value of name
    70.         public T GetValue<T>(string name){
    71.             return _blackboard.GetValue<T>(name);
    72.         }
    73.  
    74.         ///Set the variable value of name
    75.         public Variable SetValue(string name, object value){
    76.             return _blackboard.SetValue(name, value);
    77.         }
    78.  
    79.         ///Get all variable names
    80.         public string[] GetVariableNames(){
    81.             return _blackboard.GetVariableNames();
    82.         }
    83.  
    84.         ///Get all variable names of type
    85.         public string[] GetVariableNames(System.Type ofType){
    86.             return _blackboard.GetVariableNames(ofType);
    87.         }
    88.  
    89.         #if UNITY_EDITOR
    90.  
    91.         [UnityEditor.MenuItem("Assets/Create/NodeCanvas/Blackboard Asset")]
    92.         public static void Create(){
    93.             var path = EditorUtils.GetAssetUniquePath("BlackboardAsset.asset");
    94.             var newBB = EditorUtils.CreateAsset<BlackboardAsset>(path);
    95.             UnityEditor.Selection.activeObject = newBB;
    96.         }
    97.  
    98.         #endif
    99.     }
    100. }

    Code (CSharp):
    1. #if UNITY_EDITOR
    2.  
    3. using NodeCanvas.Framework;
    4. using ParadoxNotion.Design;
    5. using UnityEditor;
    6. using UnityEngine;
    7.  
    8.  
    9. namespace NodeCanvas.Editor{
    10.  
    11.     [CustomEditor(typeof(BlackboardAsset))]
    12.     public class BlackboardAssetInspector : UnityEditor.Editor {
    13.  
    14.         private BlackboardAsset bb{
    15.             get {return (BlackboardAsset)target;}
    16.         }
    17.  
    18.         public override void OnInspectorGUI(){
    19.             BlackboardEditor.ShowVariables(bb, bb);
    20.         }
    21.     }
    22. }
    23.  
    24. #endif

    Finaly, local blackboards per graph, is also something I'm working towards and will be implemented soon, but once again right now blackboards are different element from graphs for the reasons described above by design.

    Please let me know what you are trying to achieve a bit more specifically as far as the variables and I will help as best as I can.

    Thanks.
     
  4. timmehhhhhhh

    timmehhhhhhh

    Joined:
    Sep 10, 2013
    Posts:
    157
    hi there,

    i'm wondering about the best way to save state using dialogue trees, specifically, a history of selected dialogues. is there a built in way to do this?

    also, i'm unable to download the latest update through the asset store. may be my connection (in china), but other assets seem to have no issue.

    cheers, love the product so far :)
     
  5. nuverian

    nuverian

    Joined:
    Oct 3, 2011
    Posts:
    2,087
    Hello,
    Thanks. I am glad you like NodeCanvas :)

    There is no built in way for this, but it can easily be achieved by listening to the events raised by the DialogueTree. Here is an example script which saves the dialogue text being said in a list:
    Code (CSharp):
    1. using UnityEngine;
    2. using System.Collections.Generic;
    3. using NodeCanvas.DialogueTrees;
    4.  
    5. public class ExampleScript : MonoBehaviour {
    6.  
    7.     public List<string> dialogueHistory;
    8.  
    9.     void Start(){
    10.         DialogueTree.OnDialogueStarted += (x)=>{ dialogueHistory.Clear(); };
    11.         DialogueTree.OnSubtitlesRequest += OnSubtitlesRequest;
    12.     }
    13.    
    14.     void OnSubtitlesRequest(SubtitlesRequestInfo info){
    15.         dialogueHistory.Add(info.statement.text);
    16.     }
    17. }
    18.  
    The SubtitlesRequestInfo contains various other information in case you require them, like the actor saying the dialogue part for example. (look at DialogueEventArguments.cs file).

    Let me know if this works for you.
    Thanks.
     
  6. nuverian

    nuverian

    Joined:
    Oct 3, 2011
    Posts:
    2,087
  7. timmehhhhhhh

    timmehhhhhhh

    Joined:
    Sep 10, 2013
    Posts:
    157
    am doing something similar already. appreciate the quick reply :)
     
  8. Smolli

    Smolli

    Joined:
    Mar 12, 2014
    Posts:
    84
    Hi nuverian,

    thanks for your help, I could only download the pdf's after the holidays, but I downloaded the single pages to have at least something. The PDF's need a little formatting though, see Node References, but otherwise it's a great help.

    One quick question I have, how would you use the Love and Hate asset with NC? What is the main asset and what the sub? In the manual from L&H there is an example for branching conversation based on affinity (Page 31). First I thought I would do this with NC, but now I'm unsure what way to go...

    Thanks
     
  9. nuverian

    nuverian

    Joined:
    Oct 3, 2011
    Posts:
    2,087
    You are welcome :)

    Hey,

    There are different action and condition tasks for Love/Hate for doing different things in the extension package which you can download from the NodeCanvas website. The main asset would be NC in a sense of controlling or evaluating Love/Hate with it, so you basically interface with Love/Hate through NC. For the example you mentioned, here are some screens:

    CheckAffinityDLG.png
    In the context of Dialogue Trees, using a 'Multiple Condition' node.

    CheckAffinityBT.png
    In the context of Behaviour Trees, using a Sequencer with Conditional Decorators beneath.

    The Love/Hate condition task used here is "Check Affinity".
    Let me know if this works for you.
    Cheers!
     
    Smolli likes this.
  10. Smolli

    Smolli

    Joined:
    Mar 12, 2014
    Posts:
    84
  11. timmehhhhhhh

    timmehhhhhhh

    Joined:
    Sep 10, 2013
    Posts:
    157
    a couple of questions:

    1. i'm trying to maintain a list of the id's of nodes that have been entered. so am publishing the event like this:

    Code (CSharp):
    1.  
    2.     ///Enters the provided node
    3.     public void EnterNode(DTNode node){
    4.         // HACK this is some custom code to make saving and loading graph state a bit easier
    5.         if (OnEnterNode != null)
    6.             OnEnterNode (node);
    7.         else Debug.LogWarning("<b>DialogueTree:</b> Enter Node event has no subscribers. Make sure to add the default '@DialogueGUI' prefab or create your own GUI.");
    8.  
    9.         currentNode = node;
    10.         currentNode.Reset(false);
    11.         if (currentNode.Execute(agent, blackboard) == Status.Error ){
    12.             Stop(false);
    13.         }
    14.     }
    15.  
    i have a system that just subscribes to dialogue tree events and publishes them for others to consume. something like this:

    Code (CSharp):
    1.  
    2. void OnEnterNodeHandler (DTNode data)
    3. {
    4.     this.PublishAsync (new NodeEntered (){ Node = data });
    5. }
    6.  
    however, if i don't have the NodeCanvas graph inspector window open while the game is running, this will always give a node id of "0". if i have the window in focus, it gives the correct id. any ideas?

    2. i need to be able to jump around the dialogue tree, for example reversing past decisions. i've tried setting the prime node, using DialogueTree.EnterNode, DialogueTree.StartDialogue, etc... i am able to jump backwards but can't seem to find the right combination of these; the tree jumps back but when the statement finishes, it doesn't Continue() correctly. what's the correct combination of commands for this?

    EDIT: seems i can safely just use "EnterNode" here without pausing. is this correct?

    cheers :)
     
    Last edited: Apr 15, 2016
  12. Problematic

    Problematic

    Joined:
    Sep 29, 2012
    Posts:
    3
    Amazing asset! I am loving it.

    One question, though: is it possible to "map" subtree blackboard values to different parent values? For example, if my subtree assigns something to a value "myList", is it possible to indicate that "myList" refers to another name on the parent blackboard? In my mind, that would make subtree BTs MUCH more flexible, but so far my searching hasn't turned up anything.
     
  13. Haagndaaz

    Haagndaaz

    Joined:
    Feb 20, 2013
    Posts:
    232
    I am attempting to jump between ActionStates in an FSM by grabbing the ActionState by tag and then using the FSM.EnterState method, but it seemingly does nothing. Ideas?

    EDIT: LOL! Turns out I am special hahahah, I was trying to enter the action on the FSM rather than the FSMOwner. It works when calling EnterState on the FSM Owner hahaha
     
    Last edited: Apr 15, 2016
  14. nuverian

    nuverian

    Joined:
    Oct 3, 2011
    Posts:
    2,087
    You are welcome and thanks for the link :)
    I can't say for certain as for a specific time right now, sorry :/. But, please let me know if you have any other questions and I will be glad to help!
    Thanks.

    Hey,
    Regarding correct IDs, to fix this, please open up Graph.cs and un-comment line #512 (UpdateNodeIDs). Something I omitted. Thanks for reminder.
    As for jumping around the dialogue tree, there is a node already for that called "GOTO" where you can select from a dropdown another node to go to. If you want to do this through code, DialogueTree.EnterNode should work (that's how GOTO node works too. Alternatively if you don't have a node reference, you can get one by it's ID (now that it's fixed), by calling GetNodeWithID(int) on the dialogue tree reference.

    Let me know if this works for you.
    Thanks

    Hello and thanks a lot! I am glad you like NodeCanvas :)
    This is exactly the feature I've been working on and hopefully soon to be released. If not in the next version, then certainly in the one after that. The way that this would work, will be that each sub tree will have it's own local blackboard and we will be able to map that local blackboard variables, from the parent's graph blackboard and so on, ultimately leading up to the blackboard attached on the GraphOwner if so desired.

    I hope that is what you mean :)
    Thanks!

    Hey :)
    Glad it's sorted out and works for you now.
    Thanks for letting me know.
     
  15. Haagndaaz

    Haagndaaz

    Joined:
    Feb 20, 2013
    Posts:
    232
    Even though I got the EnterState to work, one thing i would like to be able to do is have nodes in between reset or skip to the end depending on direction, basically I am trying to do step jumping :) Any thoughts?
     
  16. Problematic

    Problematic

    Joined:
    Sep 29, 2012
    Posts:
    3
    I think so. Here's my use case: I have a subtree that I use to spawn new units and add them to a list. I use it to spawn, for example, enemies, allies, and players, so I want to be able to add them to a generically named list in the subtree (say, "spawnedUnits") and then, in the parent tree, say "this subtree's blackboard variable 'spawnedUnits' refers to the variable 'spawnedEnemies' on my own blackboard". Ideally, I would be able to use the same subtree multiple times within a parent tree, and map the same variable on each subtree to different variables in the parent.
     
  17. nuverian

    nuverian

    Joined:
    Oct 3, 2011
    Posts:
    2,087
    Hey,
    I am not sure what you mean exactly. When you say nodes do you mean state nodes, or action tasks in states?
    Also, there is a 'previousStateName' property in FSMOwner class, that you can use for in a sense checking direction, but because I am not yet sure what you mean, maybe that is irelevant :)
    Let me know.

    Hey,
    Yes, thats exactly how it will work when the mapping feature is implemented :)
    Hopefully that is coming very soon!
    Thanks again.
     
    Problematic likes this.
  18. Der_Kevin

    Der_Kevin

    Joined:
    Jan 2, 2013
    Posts:
    517
    I have a pretty quick question.do you also support Puppetmaster and final ik?
     
  19. nuverian

    nuverian

    Joined:
    Oct 3, 2011
    Posts:
    2,087
    Hey,
    Puppetmaster is currently not yet supported, while FinalIK is supported through a community extension which is quite cheap and also very good :) Please check it out here.
    Cheers!
     
    Der_Kevin likes this.
  20. Der_Kevin

    Der_Kevin

    Joined:
    Jan 2, 2013
    Posts:
    517
    is there anything planed? i just sent the guys from the FInalIk extension a mail :)
    Edit: they answered and dont plan a puppetmaster action pack :/
    oh, great! thanks!
     
    Last edited: Apr 28, 2016
  21. Der_Kevin

    Der_Kevin

    Joined:
    Jan 2, 2013
    Posts:
    517
    or. before we continue thinking about third party integration.. i want to use node canvas to create some soccer ai. do you think that would be a good idea to use nodecanvas for this? and if yes, do you have any best practice how to achieve a good soccer ai using nodecanvas? something i have to take care of or any useful hint is welcome :)
     
    Last edited: Apr 28, 2016
  22. Kiupe

    Kiupe

    Joined:
    Feb 1, 2013
    Posts:
    528
    Hi,

    I have a question about BlackBoard variables. It's possible to add a preferred type variable and then be able to add that type of variable in a blackboard. When you do so the Blackboard displays an input field in which you have to drop a GameObject which should have a script component of the same type. That means you have to manually add scripts on GOs in order to set BB custom type variables.

    Would it be possible not to ? I mean, let's say I have a Weapon class which has some basic informations like name, range, power etc. I'd like to be able to create a list of Weapon directly in the Blackboard and not have to previously create them onto GOs and then drops them in the BB. I know it means that NodeCanvas should know what type of input it should displays for the type - but may be there is a solution for that, so I try my chance and ask :)

    Thanks
     
  23. nuverian

    nuverian

    Joined:
    Oct 3, 2011
    Posts:
    2,087
    Hey,
    Using BehaviourTrees and/or FSMs for a soccer AI ought to be a nice fit. As such NodeCanvas is a nice fit as well :)
    There are many approaches one can take to achieve a soccer AI, but I will be able to help a bit more if knew some extra info or specification about what needs to be done. Right now is quite vague what the specifications are.
    Please met me know a bit more specific. Thanks :)

    Hello,
    If your class is not a MonoBehaviour (or is a struct), it can be added and be stored locally within the blackboard. Not all classes have to derive from MonoBehaviour :)
    Here is an example:

    Code (CSharp):
    1. public class Weapon{
    2.    
    3.     public string name;
    4.     public float range;
    5.     public float power;
    6. }
    WeaponsExample.png

    And here is an action task that works with the Weapon class for example.
    Code (CSharp):
    1. namespace NodeCanvas.Tasks.Actions{
    2.  
    3.     public class SomeAction : ActionTask{
    4.  
    5.         public BBParameter<Weapon> weapon;
    6.  
    7.         protected override void OnExecute(){
    8.            
    9.             Debug.Log(weapon.value.power);
    10.             EndAction();
    11.         }
    12.     }
    13. }
    Let me know if that works for you.
    Thanks :)
     
  24. Jingle-Fett

    Jingle-Fett

    Joined:
    Oct 18, 2009
    Posts:
    614
    Hi @nuverian I was wondering, is it possible to have nested FSMs/BTs that are bound? Meaning that we can have nested FSMs that behave exactly the same as they currently do (which require a saved asset FSM/BT), except that we're able to just make a bound one instead of using a saved asset? I don't think we can do this currently but I'm not 100% sure so I wanted to ask (I would absolutely love to be able to do that). Thanks!
     
  25. Der_Kevin

    Der_Kevin

    Joined:
    Jan 2, 2013
    Posts:
    517
    sure, no problem. So its for a 5vs5 Soccer Game where you can also beat up other people. So to say a Soccer Beat em up. If you wanna know more about the Game, just visit or reddit: https://www.reddit.com/r/Footbrawl/ :)

    So the difficulties regarding the Soccer Ai is in my opinion that not everybody chasing the ball. So that some players know when they have to defend and when they have to offend. also a smart prediction about what is happening next and so called release (running to the front when they see the chance of a goal). and on top of that comes the beat em up behavior. so that some players attacking other players but not chasing them all the time and leave them alone at some point to go back to the soccer game.
    so a good balance between trying to score a goal, trying to defend a goal and just beaten up other player. also some randomness since the game is not serious at all :D

    And by the way, what do you think about that: http://www.gamasutra.com/blogs/Jako...88/Are_Behavior_Trees_a_Thing_of_the_Past.php

    edit: okay, so i just bought NC cause my curiosity to mess around with it was to big. to as a first exercise i tried to convert the case soldier demo to mecanim&puppetmaster. works pretty good so far but somehow i dont realy get the difference between sequencer and selector.

    also i wanted my ai bot to run a "bow" to its new target (now he is only rotating on place and run to the target) but i have no clue how that works or if this is more a navmesh thing ornodecanvas thing :D ive got already runright/left sharp/normal states in my mecanim blendtree controlled by a turn float value which are working perfect but no real idea how to set them up in my BT
     
    Last edited: May 3, 2016
  26. Der_Kevin

    Der_Kevin

    Joined:
    Jan 2, 2013
    Posts:
    517
    so i wanted to create some puppetmaster actions for nodecanvas. for this i had a look at the already done final ik actions. a simple "look at" action looks like this for example: http://pastebin.com/dFBdkh5W

    so, based on that i wanted to create the usercontrolAi as an action. which looks like this at the moment:

    Code (CSharp):
    1. using NodeCanvas.Framework;
    2. using ParadoxNotion.Design;
    3. using UnityEngine;
    4. using RootMotion.Dynamics;
    5.  
    6.  
    7. namespace NodeCavasAddons.Puppetmaster
    8. {
    9.     [Category("Puppetmaster")]
    10.     [Name("Ai Move")]
    11.     [Description("Move the Ai Bot")]
    12.     public class PuppetmasterMove : ActionTask {
    13.  
    14.         public Transform moveTarget;
    15.         public float stoppingDistance = 0.5f;
    16.         public float stoppingThreshold = 1.5f;
    17.         public Transform transform;
    18.  
    19.         public bool repeat;
    20.  
    21.         public struct State {
    22.             public Vector3 move;
    23.             public Vector3 lookPos;
    24.             public bool crouch;
    25.             public bool jump;
    26.             public int actionIndex;
    27.         }
    28.  
    29.         public bool walkByDefault;        // toggle for walking state
    30.         public State state = new State();
    31.         protected Transform cam;                    // A reference to the main camera in the scenes transform
    32.  
    33.  
    34.         protected override void OnExecute(){Move();}
    35.         protected override void OnUpdate(){Move();}
    36.  
    37.         //void Start () {
    38.             // get the transform of the main camera
    39.         //    cam = Camera.main.transform;
    40.         //}
    41.  
    42.         void Move()
    43.         //protected override void OnExecute()
    44.         {
    45.            
    46.             float moveSpeed = walkByDefault? 0.5f: 1f;
    47.  
    48.             Vector3 direction = moveTarget.position - transform.position;
    49.             direction.y = 0f;
    50.  
    51.             float sD = state.move != Vector3.zero? stoppingDistance: stoppingDistance * stoppingThreshold;
    52.  
    53.             state.move = direction.magnitude > sD? direction.normalized * moveSpeed: Vector3.zero;
    54.  
    55.             // calculate the head look target position
    56.             //state.lookPos = transform.position + cam.forward * 100f;
    57.  
    58.         }
    59.     }
    60. }
    but the result of this is, that the puppet doesnt move. here is the original script i wanted to convert as an action: http://pastebin.com/S3K6RQG4

    also the nodecanvas layout gets totaly destroyed and the nodes are placed elsewhere when i press play with this action script attached.

    is there anything at the script above that doesent make any sense to you?
     
  27. nuverian

    nuverian

    Joined:
    Oct 3, 2011
    Posts:
    2,087
    Sorry for the late replies due to Eastern time.

    Hey,
    No unfortunately having bound nested graphs is not possible, at least right now. This feature is requested quite a lot of times and I will take a look at this once the current more pressing ones are implemented :)
    Thanks!


    Hey,

    Thanks for getting NodeCanvas.
    Your game look like a lot of fun :)
    The difference between Sequencer and Selector is quite simple actually. The Sequencer will execute it's child in order until one Fails, while the Selector will execute it's child in order until one Succeeds. They are the opposite. Another way to think of them, would be like an AND and an OR. Obviously this becomes more relevant when you have conditions for children. The docs here explain both of them in more detail, but if you need any further example let me know.

    Regarding Utility AI, I think it's a good approach to AI, but in contrary to the article I don't think it can replace Behaviour Trees, just like Behaviour Trees can't replace State Machines. Each approach has it's pros and cons and designed to tackle different problems.

    Can you please explain a bit more on your last question about " to run a "bow"" I don't get the phrase :)
    Thanks!

    The code here does not seem to have anything going wrong as far as the NodeCanvas side. Of course it can be improved a lot by using BBParameters so that it is possible to link Blackboard variables instead of only direct values for example. Regarding the playmode layout issue, is there any error logged in the console?

    One obvious thing here, is that the action does not seem to alter anything on any target transform and thus why the puppet does not move. The original PuppetMaster script you posted derives from UserControlThirdPerson and probably that base class has an OnLateUpdate that actually moves the puppet after the changes made in the inherited "state" and in the overridden Update. This is just an assumption since I do not own PuppetMaster.

    What you probably need to do is to create the action in such a way as to alter the "State" of a relevant script like UserControlThirdPerson attached already on the owner gameobject. Here is what could work. I haven't tested this since I don't own PupperMaster, but may give you pointers to the right direction.

    Code (CSharp):
    1. namespace NodeCavasAddons.Puppetmaster
    2. {
    3.     [Category("Puppetmaster")]
    4.     [Name("Ai Move")]
    5.     [Description("Move the Ai Bot")]
    6.     //Derive from generic ActionTask. Where T can be any component type.
    7.     //When this is done, property 'agent' refers to a component of that type that is attached on the owner.
    8.     public class PuppetmasterMove : ActionTask<UserControlThirdPerson> {
    9.         //Use BBParameter so that moveTarget can be linked to a variable optionally.
    10.         public BBParameter<Transform> moveTarget;
    11.         public float stoppingDistance = 0.5f;
    12.         public float stoppingThreshold = 1.5f;
    13.         public bool walkByDefault;        // toggle for walking state
    14.  
    15.         protected override void OnExecute(){Move();}
    16.         protected override void OnUpdate(){Move();}
    17.         void Move()
    18.         {
    19.             float moveSpeed = walkByDefault? 0.5f: 1f;
    20.             Vector3 direction = moveTarget.value.position - agent.transform.position;
    21.             direction.y = 0f;
    22.             float sD = agent.state.move != Vector3.zero? stoppingDistance: stoppingDistance * stoppingThreshold;
    23.             agent.state.move = direction.magnitude > sD? direction.normalized * moveSpeed: Vector3.zero;
    24.         }
    25.     }
    26. }
    By the way, I will contact PuppetMaster author for an integration.

    Let me know :)
    Thanks!
     
    Last edited: May 3, 2016
  28. Jingle-Fett

    Jingle-Fett

    Joined:
    Oct 18, 2009
    Posts:
    614
    Good to know, thanks. Hopefully we won't have to wait too long!
     
  29. nuverian

    nuverian

    Joined:
    Oct 3, 2011
    Posts:
    2,087
    The new version 2.5.5, is live on the Asset Store.

    The most important new feature is the long requested ability to create custom object and attribute drawer. You can read more on how easily this can now be done on the new relevant Custom Object & Attribute Drawers documentation.

    Further changes include:
    • New: Auto-Properties are now inspectable in the editor as read-only editor fields. (debugging purposes)
    • New: Refactoring namespaces of types where methods/properties are 'referenced' in the ScriptControl tasks are now handled.
    • Fix: Bug where child object references in prefabs were not referenced correctly when the prefab got instantiated in runtime.
    • Fix: BBParameters no longer lose reference to linked variables due to variable name changes that was taking place in some cases.
    • Fix: Missing methods/properties in Script Control tasks are now correctly shown in red color.
    • Fix: Object Editor window errors when entering/exiting playmode.

    @Jingle Fett Your requested feature is high in the TODO list allready, so hopefully it comes around soon :)
    Cheers!
     
    Jingle-Fett likes this.
  30. Der_Kevin

    Der_Kevin

    Joined:
    Jan 2, 2013
    Posts:
    517
    so, thats what the UserControlThirdPerson.cs looks like: http://pastebin.com/uKasamfX

    I somehow cant see any reference to a target transform. The script youve postet above mark the <UserControlThirdPerson> red. If you look at the CharacterThirdPerson.cs (http://pastebin.com/Bt0M6rze) script (that CharacterPuppet inherits from), it has a reference to a UserControlThirdPerson. It will use it's state as input to calculate the movements. So the script needs to extend UserControlThirdPerson and be referenced as "User Control" in the CharacterPuppet.cs (http://pastebin.com/ZsGtA43a). But i sadly cant figure out how to do this.

    also, one more question: how can I let a nodecanvas action change (for example) a public transform from a script that is attached to the same gameobject where the nodecanvas is on?
     
    Last edited: May 6, 2016
  31. nuverian

    nuverian

    Joined:
    Oct 3, 2011
    Posts:
    2,087
    Hello again,

    So as far as I can see you can do the following:
    Add the CharacterPuppet script on the gameobject where NodeCanvas owner is as well.
    In NodeCanvas use the action "Script Control Task/Execute Function" and with the "Select Method" button in that action chose "CharacterPuppet/Move(Vector3, Quaternion)".
    Doing this will will in essence allow you to call the Move method of the CharacterPuppet script and thus moving the puppet by specified deltaPosition and deltaRotation parameters.

    You can probably achieve the same by using the CharacterThirdPerson component instead (as far as I can see) and also use the "Script Control" categorized actions/conditions to interface with it's public fields, properties and methods.

    To further elaborate on your last question, you can do this using the action "Script Control/Set Field" (or Set Property) and choosing the Transform property/field you want to change, with the relevant button "Select Field" (or Property).

    Let me know if that works for you.
     
  32. Der_Kevin

    Der_Kevin

    Joined:
    Jan 2, 2013
    Posts:
    517
    Its working! thank you so much :)
    simple run-to-nearest-taget behavior. works great now :)


    i think the script control action is the best thing part of nodecanvas - now that i discovered it :D thanks!

    so. now i can start with setting up the ai. do you have any tips for a 5vs5 soccer ai with beating up other players? how would you set that up - one behavior tree controlling everything or different BT for each player?

    i somehow dont know how to set up a "passing" ai. so that the ai also giving the ball to another player instead of always run straight to the goal. a huge questionmark is also over my head when i think about how to not let every player run to the ball if another player is already on its way. also how to set up defense and offense ai would be nice to know :)
    thanks!

    Edit: oh, just found this ebook https://unisalesianogames.files.wor...gramming-game-ai-by-example-mat-buckland2.pdf which actually answers all my questions :D do you think the stuff which is written on page 133 is doable with nc so far?
    Still every hint is usefull for me :) and ism still confused if i should use fsm's or behavior trees for my case?
     
    Last edited: May 7, 2016
  33. nuverian

    nuverian

    Joined:
    Oct 3, 2011
    Posts:
    2,087
    Thanks. Glad to know you got it working.

    One way you can approach this, would be for each player to be an FSM agent with 2 states being Offense and Defense. Both of those states would be BehaviourTree state, so that the offense and defense can be modeled separately easier.

    Approaching this with a single BehaviourTree for each team instead of for each player could be doable with the use of the Iterator BT node (doing a 'foreach player'), but depending on the final complexity of the game, it may turn out to be messy and hard to manage.

    Furthermore a thing that I think would really help here, would be to create two Global Blackboards, one for each team named something like "TeamRed", "TeamBlue". So each player of each team have a common pool of variables they can work with, like for example which player is currently running at the ball, or has the ball.

    I skimmed through the pages of the book. There is no reason not to be doable with NC :). If you implement the various methods and object provided there as monobehaviours for example, you can once again use NC to call these methods when required from within either BT or FSM using the Script Control tasks.

    I hope this helps. Let me know
    Thanks.
     
  34. Der_Kevin

    Der_Kevin

    Joined:
    Jan 2, 2013
    Posts:
    517
    thanks :) so i stumbled upon my first problem. its more scripting related and i don't know how i can set a bool in a blackboard to true.
    so i have a ball and, the player and a collider as a child object infront of him.
    the ball has this script attached:

    Code (CSharp):
    1. oid OnTriggerEnter(Collider collision)
    2.      {
    3.        
    4.          ControllingFeet = collision.transform;
    5.          if(collision.gameObject.name == "DribbleCollider")
    6.          {
    7.              Debug.Log("Collide");
    8.              
    9.          }
    10. }
    11. void FixedUpdate()
    12.      {
    13.        
    14.          bool isControlled = ControllingFeet != null;
    15.          if (isControlled)
    16.          {
    17.          //    Vector3 targetPos = ControllingFeet.GetDribblePosition();
    18.              Vector3 targetPos = ControllingFeet.transform.position;
    19.              targetPos.y = GetComponent<Rigidbody>().position.y;
    20.              Vector3 newPos = Vector3.Lerp(transform.position, targetPos, controlAmount);
    21.              GetComponent<Rigidbody>().MovePosition(newPos);
    22.              Vector3 delta = newPos - transform.position;
    23.              Vector3 movementVel = delta / Time.fixedDeltaTime;
    24.              controlledVelocity.x = movementVel.x;
    25.              controlledVelocity.y = GetComponent<Rigidbody>().velocity.y;
    26.              controlledVelocity.z = movementVel.z;
    27.              Debug.DrawLine(transform.position, targetPos, Color.black);
    28.          }
    29.      }
    which actually just puts the collider from the character as the "ControllingFeet" and then the ball copies the position of that collider which looks like dribbeling.

    what i want to do now is, set a hasBall bool in my blackboard to true as soon as the player has the ball. the blackboard is in a parent of the ControllingFeet. how can i do this?
     
  35. nuverian

    nuverian

    Joined:
    Oct 3, 2011
    Posts:
    2,087
    Hey,

    It's actually very easy :)
    If you want to set a blackboard variable from within some of your scripts outside of a NodeCanvas task/node, you can do something like this:
    Code (CSharp):
    1. public class Example : MonoBehaviour{
    2.  
    3.     void Do(){
    4.  
    5.         var bb = ControllingFeet.GetComponent<Blackboard>();
    6.         bb.SetValue("hasBall", true);
    7.  
    8.         //this is also how to read:
    9.         var someFloat = bb.GetValue<float>("myFloat");
    10.     }
    11. }
     
  36. Der_Kevin

    Der_Kevin

    Joined:
    Jan 2, 2013
    Posts:
    517
    okay. I think iam doing something wrong here, right?
    Code (CSharp):
    1. public GameObject bb;
    2.  
    3.  
    4.     void Awake()
    5.     {
    6.         normalColliderRadius = GetComponent<SphereCollider>().radius;
    7.         ControllingFeet = this.gameObject.transform;
    8.     }
    9.  
    10.  
    11.     void OnTriggerEnter(Collider collision)
    12.     {
    13.        
    14.         ControllingFeet = collision.transform;
    15.         bb = ControllingFeet.parent.GetComponent<Blackboard>();
    16.         bb.SetValue("hasBall", true);
    17.  
    18.         if(collision.gameObject.name == "DribbleCollider")
    19.         {
    20.             Debug.Log("Collide");
    21.             //Destroy(collision.gameObject);
    22.         }
     
  37. nuverian

    nuverian

    Joined:
    Oct 3, 2011
    Posts:
    2,087
    Hey,
    bb should be a Blackboard type, not a GameObject at the top.
    Code (CSharp):
    1. public Blackboard bb;
     
  38. Der_Kevin

    Der_Kevin

    Joined:
    Jan 2, 2013
    Posts:
    517
    ah, thanks :) I also forgot to add using NodeCanvas.Framework; :)
    okay, here comes another one :
    i wanna use a if can see target condition with the settings: distance:15 - view angle: 10
    my target is a 5x4 big cube. but the condition is only true when i am focusing the center of the cube, not everything.
    i tried the "If LOS" but that also gives me a "true" even if i stand with the back towards the cube? i think it works like that, right? so that it doesent check the direction

    and, can i place the NodeCanvas/FlowCanvas and NC/FC Resources Folder in a subloder? or even in the plugins Folder? or will that break something?
     
    Last edited: May 10, 2016
  39. LazloBonin

    LazloBonin

    Joined:
    Mar 6, 2015
    Posts:
    809
    Hi! Great plugin.

    I'm getting lots of warnings on compilation; they're minor and I could fix them all myself, but they'd get overwritten at every update. Could you please fix them for a future version?

     
  40. TSabos

    TSabos

    Joined:
    Mar 8, 2015
    Posts:
    94
    We are working off 1 main AI tree and when we populate our areas with monster spawns they correctly select the right AI tree at runtime. We're seeing some major delay when bringing in even 20 monsters into the world and plan on there being closer to 100 per area, each area only loaded async as the player needs them.

    Here's the results of instantiating the monsters.. any insight into the major overhead?
    https://snag.gy/TCn5Ih.jpg
     
  41. Smolli

    Smolli

    Joined:
    Mar 12, 2014
    Posts:
    84
    Hi there,

    I'm trying desperately to write a value back to a Blackboard. I'm trying to write an integration for the LocalizedEditor-Asset. (https://www.assetstore.unity3d.com/en/#!/content/36006)
    This is what I have, but I can't get the value back and I need it for the say action. Any ideas?

    Code (CSharp):
    1. using UnityEngine;
    2. using System.Collections.Generic;
    3. using NodeCanvas.Framework;
    4. using ParadoxNotion.Design;
    5. using LocalizationEditor;
    6.  
    7. namespace NodeCanvas.Tasks.LocalizationEditor{
    8.  
    9.     [Category("LocalizationEditor/GetString")]
    10.     public class LEGetString<T> : ActionTask {
    11.         public BBParameter<string> LE_Keyname;
    12.         public BBParameter<string> LE_LocalizedString;
    13.  
    14.         protected override void OnExecute(){
    15.             LE_LocalizedString = LEManager.Get(LE_Keyname.value);
    16.      
    17.             Debug.Log(LE_LocalizedString.value);
    18.             EndAction();
    19.         }
    20.     }
    21. }
     
  42. Smolli

    Smolli

    Joined:
    Mar 12, 2014
    Posts:
    84
    Solved it, suddenly it was easy :) I'll post my solution tomorrow. 2:36AM and I'm on wrong Computer.
     
  43. Smolli

    Smolli

    Joined:
    Mar 12, 2014
    Posts:
    84
    Ok, here is the way to write to blackboard variables if anybody needs it.
    Code (CSharp):
    1. using UnityEngine;
    2. using System.Collections.Generic;
    3. using NodeCanvas.Framework;
    4. using ParadoxNotion.Design;
    5. using LocalizationEditor;
    6.  
    7. namespace NodeCanvas.Tasks.LocalizationEditor {
    8.  
    9.     [Category("LocalizationEditor/GetString")]
    10.     public class LEGetString<T> : ActionTask {
    11.         public BBParameter<string> LE_Keyname;
    12.         public BBParameter<string> LE_LocalizedString;
    13.  
    14.         protected override void OnExecute(){
    15.             LE_LocalizedString = LEManager.Get(LE_Keyname.value);
    16.             string exText = LE_LocalizedString.value;
    17.             blackboard.SetValue("myString", exText );
    18.             Debug.Log(LE_LocalizedString.value);
    19.             EndAction();
    20.         }
    21.     }
    22. }

    But this is only part of the way. A much better way would be to override the say class so I can add the possibility to look for the ID (or key as it's called) and if not found show the text as dialogue text.
    And how do I use the 'choices' for having multiple choices within a BT? I did only see the node in DT.

    And how can I access Global Variables inside a Say Action where I normally write [variableName] to access the local BBVars?
     
    Last edited: May 17, 2016
  44. Der_Kevin

    Der_Kevin

    Joined:
    Jan 2, 2013
    Posts:
    517
    Hey! How would you implement the following case:

    I have 5 characters standing in a circle and in the middle is a sphere. So all 5 have the same distance.
    All 5 get the call to move to the sphere. Everyone has is own BT
    But only 1 guy should perform the action.
    So somehow like you would yell to your team "dont go, i go!"
     
  45. Tinjaw

    Tinjaw

    Joined:
    Jan 9, 2014
    Posts:
    518
    I am just learning BT and NodeCanvas....

    So you want one object to communicate with another object. Sounds like a textbook cases for blackboard to me. What am I missing?
     
    nuverian likes this.
  46. Der_Kevin

    Der_Kevin

    Joined:
    Jan 2, 2013
    Posts:
    517
    but how exactly? i am lacking the knowledge of the basic concept about how to tell every teammate from one character outgoing that he should stop his current task.

    how do i define which character should move in the end (random) to the target.
    how can i sent the next character when the other one is dying?
    how do i sent a message to each teammate if i dont know how many there are?
    how do i tell all the other characters that they should do something else instead and not just stand there
    how can i even set up one supporting character that supports character 1 after a certain time?
     
  47. Tinjaw

    Tinjaw

    Joined:
    Jan 9, 2014
    Posts:
    518
    You just went from one question to six. I'll let somebody else answer.
     
  48. LazloBonin

    LazloBonin

    Joined:
    Mar 6, 2015
    Posts:
    809
    I can't get a custom event condition to work. I want a Condition that returns True when I call the "Interact" event (in my own code) with a specific "InteractionType".

    Here's my code for the ConditionTask:

    Code (CSharp):
    1. using NodeCanvas.Framework;
    2. using ParadoxNotion.Design;
    3. using UnityEngine;
    4.  
    5. namespace Test.NodeCanvas
    6. {
    7.     [Category("Test")]
    8.     [EventReceiver("Interact")]
    9.     public class CheckInteract : ConditionTask
    10.     {
    11.         protected override bool OnCheck()
    12.         {
    13.             return false;
    14.         }
    15.  
    16.         public InteractionType type = InteractionType.Down;
    17.  
    18.         public void Interact(InteractionType type)
    19.         {
    20.             Debug.Log("This never shows");
    21.  
    22.             if (this.type == type)
    23.             {
    24.                 YieldReturn(true);
    25.             }
    26.         }
    27.     }
    28. }
    And here's how I trigger the event:

    Code (CSharp):
    1. behaviourTreeOwner.SendEvent("Interact", InteractionType.Down);
    With the "Log Events" option checked, the log shows:

    But Test.NodeCanvas.Interact never gets called. Is this a bug or did I misundestand something?
     
  49. LazloBonin

    LazloBonin

    Joined:
    Mar 6, 2015
    Posts:
    809
    I got it working with this, but I consider this code really unintuitive. Could there be native support for my first code?

    Code (CSharp):
    1. using NodeCanvas.Framework;
    2. using ParadoxNotion;
    3. using ParadoxNotion.Design;
    4.  
    5. namespace Test.NodeCanvas
    6. {
    7.     [Category("Test")]
    8.     [EventReceiver("OnCustomEvent")]
    9.     public class CheckInteract : ConditionTask
    10.     {
    11.         // ...
    12.  
    13.         public void OnCustomEvent(EventData receivedEvent)
    14.         {
    15.             if (isActive && receivedEvent.name == "Interact")
    16.             {
    17.                 Interact(((EventData<Interaction>)receivedEvent).value);
    18.             }
    19.         }
    20.     }
    21. }
     
  50. nuverian

    nuverian

    Joined:
    Oct 3, 2011
    Posts:
    2,087
    Wow. I missed all those posts! The forums never send me a notification for reasons unknown to me. I am so sorry!


    Hey,

    The LOS check is simply a line of sight (linecast) so yes, direction/view angle does not matter. The Can See condition should work fine though. A 10 view angle is quite small for the CanSee Target condition by the way. It's only 10 degrees cone of view, which is quite small. Thus you probably need a bigger cone. Something like 90 should work fine :)

    Regarding folder organization, sure. Feel free to place the folders in any way you like :)

    Let me know.
    Thanks.



    Hey.
    Odd enough, I don't get any warnings here. Can you please re-post the image (or text) to see the whole warning paths?
    Thanks!

    Hey,
    When instantiating a BehaviourTree owner (or any GraphOwner) there is bound to be some memory allocation due to deserialization. With that being said though, the allocation here is due to the serialization unity callback (OnBeforeSerialize), which in runtime is not called at all, even though it does in editor.
    So in runtime the only allocation should be just the one seen bellow (OnAfterDeserialize: 144KB).
    If you open up Graph.cs you will see that OnBeforeSerialize is wrapped into an #if UNITY_EDITOR.

    Thanks!

    Hello,

    There is actually a better way of writing back into the blackboard, by simply using BBParameters and set their .value property :)
    Setting the .value property of a BBParameter will in turn set the value of any variable it is linked to. Here is an example code for you:
    Code (CSharp):
    1.     public class Wait : ActionTask {
    2.  
    3.         public BBParameter<float> waitTime = 5f;
    4.         [BlackboardOnly]
    5.         public BBParameter<float> elapsed;
    6.  
    7.         protected override void OnUpdate(){
    8.             elapsed.value += Time.deltaTime;
    9.             if (elapsed.value >= waitTime.value){
    10.                 EndAction();
    11.             }
    12.         }
    13.     }
    The [BlackboardOnly] attribute is not really needed, but stricts the BBParameter in the editor to only be linkable to variables and impossible to specify a direct value. Using this way, it's also possible to select a global blackboard variable to link the BBParameter to, and as a result setting .value, would in turn set the linked variable's value.

    Regarding replacing text in Say action through a global blackboard variable, this is currently not possible, but it's a nice addition to have and I will include this in the next version. The way this will work, would be by entering the path to that variable, like for example: "There are [Global/myVariable] trees in the world". Localization is also high priority in the TODO list by the way, but you can definetely create/duplicate the Say action task and include a string ID, for fetching and replacing the text from the localization database if found. I thing it's a better way of doing this, than using variables in my opinion.

    Finally, The MultipleChoices node is strictly a DialogueTree node since it has to do with dialogue options, actors talking and branching. There is no such node in Behaviour Trees, even though such a node can definitely be created for BTs as well. I could help you with that if you want :)

    Let me know if this works for you.
    Thanks!

    Probably the best way to communicate and tell others about things happening, would be either to use Global Blackboards or use Global Events.

    Using global blackboards for example, you can set variables from one character when some game state changes, and then other characters can check these variables to control the flow of their behaviour tree as desired.
    Using global blackboards would be better than using global events, because in NC, you can have more than one global blackboards. In your case, these can be one for Team Red and another for Team Blue. And maybe a third one for really global data.

    Furthermore, a node that should prove quite useful to you as far as I can tell, would be the Iterator node. With the Iterator node, you can iterate a list of objects for each of it's elements and perform actions or check conditions for example. In your case, this list would be the list of players.

    Regarding your questions per-se, it's quite difficult for me to provide a concrete answer to them all, since there are lot's of different ways things can be achieved and it really depends on the rest of the context and these questions are quite right now quite abstract :). If you let me know of some more self-contained example you are after though, I would be able to help further.

    Once again, I suggest using global variables for communicating data between different agents/characters.

    Let me know.
    Thanks!

    Hey,

    So, Here is a new Condition Task that will be included in the next version (Check Event Value). This condition, checks whether the event is received like the existing Check Event condition, but it also checks the event value against another value before returning true, so avoiding the need to save the CheckEvent value to variable before checking it.
    Code (CSharp):
    1. using NodeCanvas.Framework;
    2. using ParadoxNotion;
    3. using ParadoxNotion.Design;
    4. using ParadoxNotion.Services;
    5. using UnityEngine;
    6.  
    7. namespace NodeCanvas.Tasks.Conditions{
    8.  
    9.     [Category("✫ Utility")]
    10.     [Description("Check if an event is received and it's value is equal to specified value, then return true for one frame")]
    11.     [EventReceiver("OnCustomEvent")]
    12.     public class CheckEventValue<T> : ConditionTask<GraphOwner> {
    13.  
    14.         [RequiredField]
    15.         public BBParameter<string> eventName;
    16.         public BBParameter<T> value;
    17.  
    18.         protected override string info{ get {return string.Format("Event [{0}].value == {1}", eventName, value);} }
    19.         protected override bool OnCheck(){ return false; }
    20.         public void OnCustomEvent(EventData receivedEvent){
    21.             if (receivedEvent is EventData<T> && isActive && receivedEvent.name.ToUpper() == eventName.value.ToUpper()){
    22.                 var receivedValue = ((EventData<T>)receivedEvent).value;
    23.                 if (receivedValue != null && receivedValue.Equals(value.value)){
    24.                  
    25.                     #if UNITY_EDITOR
    26.                     if (NodeCanvas.Editor.NCPrefs.logEvents){
    27.                         Debug.Log(string.Format("Event '{0}' Received from '{1}'", receivedEvent.name, agent.gameObject.name), agent);
    28.                     }
    29.                     #endif          
    30.                  
    31.                     YieldReturn(true);
    32.                 }
    33.             }
    34.         }      
    35.     }
    36. }

    If this new condition does not work for you and would rather like to do it with the code you initially created using EventReceiver, I can tell you how to make the necessary changes for it to work, which I will anyway do so and include for the next version.

    Let me know.
    Thanks!