NodeCanvas and Factory & Observer patterns

NodeCanvas Forums General Discussion NodeCanvas and Factory & Observer patterns

Viewing 6 posts - 1 through 6 (of 6 total)
  • Author
    Posts
  • #8976

    Greetings, Love the asset and just left a 5 star review on the asset store.

    I’m working to implement behavior trees into a real production game, NeuroMage. I have both NodeCanvas and Behavior Designer and trying each to determine which should be the backbone for the AI in the game. One of the main sticking points I’ve always had with Playmaker and other state machines is integrating with design patterns that I’ve already built my game around. Specifically the observer pattern and factory patterns.

    So for the observer pattern I will typically want to sent out messages that other objects can subscribe to. For example…

    Then I can raise the event for any subscribers…

    So with this pattern it is naturally easy for me to subscribe to that event with something like

    Player.DamageDealtToPlayerEvent += DamageReceived;

    So what I’m looking for is the best way to integrate NodeCanvas BT’s and FSM’s with this pattern. How can I broadcast an event that other objects can subscribe to and how can I respond to events like I did above? I realize of course I may need to do a few things to get it clean but I’d rather have a clear methodology for implementing the observer pattern consistently than have this vague notion as to how it may be achieved.

    An example of the factory pattern I’m currently doing in C# and want to integrate with BT’s… My Mage can conjure a minion and the factory determines at runtime if the minion is a goblin, vampire, demon, dragon etc. Often I’m ‘upcasting’ (think that is the right term) so I can reference the minion generically (type minion) which the actual minion itself is of type ‘goblin’ or other subclass.

    Naturally I could bind the behavior tree to the prefab that goes with that minion. Where the factory part comes in for the BT’s and FSM’s come in however is that I may want to add extra behaviors depending on upgrades that unlock specific spells/abilities for that minion. So when you spend points on an upgraded spell the demon might get new behaviors such as a stun effect or the ability to set an opponent on fire. My hope would be a factory type pattern that could create specify the behavior trees at run time and attach them to the minion giving them additional abilities with a clean design pattern that can easily be extended.

    It seems that NodeCanvas’s ability to work with lists of objects and perhaps therefore lists of behavior trees could create some really powerful solutions. Would it be possible for example to have a list of behavior trees in which could be dynamically iterated?

    At this point I don’t expect to solve this quickly… but would like some direction on how I can implement some of these patterns I know well in C# and integrate them with BT’s and FSM’s in NodeCanvas without pulling my hair out.

    Love the product and hoping you can give me some guidance on how to proceed.

    Thanks in advance.

    #8981
    Gavalakis
    Keymaster

    Hello and thanks a lot 🙂

    NodeCanvas is really focused on working on top of your design and there are various ways you can go about using the observer pattern.
    Most commonly you will want to use an event as a condition task within the behaviour tree instead of an action. So lets suppose that you have this example:

    Then you can create a ConditionTask as such:

    You can now assign this Condition Task on a Condition node, an Accessor Decorator, an Interruptor Decorator or even an FSM transition depending on the design you are after. Notice that this condition will latch the event received until the condition is checked. Another probably better way if you want the condition to only return true in the same frame that the event was raised would be this:

    The YieldReturn function is a special one that helps you do just what we are after here. This above condition will return true only the frame in which the event was raised. This is also what is used in the Trigger, Collision etc conditions by the way.

    You can of course further expand this condition task to also store the damage amount received in a blackboard float variable if you want to.
    I would also like to let you know that under ‘Script Control’ category there is a reflection based event subscriber condition called “Check CSharpEvent”. This lets you subscribe to an event of a MonoBehaviour through reflection, but the downside is that currently it supports only events without parameters. I can certainly improve this to accept parameters as well.

    Let me know if that is what you are after.

    Regarding the factory pattern example. Currently the way this can be done is to use a SubTree for each of those different upgradable behaviours within the minions ‘master’ behaviour tree. Based on conditions that determine whether or not the minion has that ability/behaviour, the SubTree can be filtered to execute or not. Probably the best way to achieve this would be to use an Accessor Decorator above each of those subtrees, like in the attached image. Notice that the Accessor Decorator, can be assigned any Condition Task.

    Note that in next versions, the target behaviour of the SubTree node will become a variable able to be selected from the blackboard. As such you will be able to “inject” the target subtree at runtime, stored in the blackboard, and thus dynamicaly alter the behaviour far easier than it now is. This way, as you correctly noticed, SubTrees will also be able to be used with lists and the use of the ‘Iterate List’ Decorator for example.

    Don’t hesitate to ask any further questions that you may have.
    Cheers!

    Join us on Discord: https://discord.gg/97q2Rjh

    #8980

    This is very excellent and exactly what I was looking for. I could see the advantages of expanding script control with subscribe/check events that support standard parameters and then perhaps an option to sync/post the parameter to the BB. If this isn’t super hard I think it could add a lot of power and make it easier to tie bt’s and state machines into existing event based systems.

    Overall I know one of the things I do struggle with is that when I build behavior trees there is so much dragging and dropping of specific game objects to tie things together… but then in runtime I need them to be dynamic and the instances injected into various nodes. At this point I don’t have specific question/problems but that is an area of the overall architecture I’m still wrapping my brain around.

    Many thanks for all your help.

    #8979
    Gavalakis
    Keymaster

    Hello,

    The best way to avoid drag/droping of various game objects in nodes and to do things dynamicaly, is to instead of providing direct references in nodes, to create and use blackboard variables from where the nodes will read/write from and to.
    This way you have all your references within a single place (the blackboard) and you can also easily modify the variables in runtime with some simple functions. For example:

    You could initialize the blackboard variables in some sort of initialization if you want to alter them dynamicaly.
    As an effect all nodes reading from those blackboard variables will use that new variable value.

    Cheers

    Join us on Discord: https://discord.gg/97q2Rjh

    #8978

    Many thanks for the help. I’m finding that I can usually push through and find a way to make it work but I often feel like I’m missing a better way.

    I think when I have a simple type and a common component it is straight forward. I’m struggling a bit with more customized scripts at getting those attached to the blackboard.

    So if I have a LearnSpell script that is on my mage game object. I’d like to delegate out the various conditions so on my blackboard and in my trees I’d like to reference the scripts and properties from that script. I’ve found I can bind the game object pretty well dynamically but then to dig in and get the various attributes out is not always easy.

    I will say you have written very excellent code and that helps me alot in seeing how things are fitting together. So like I know that somehow I must be able to specify custom types into the blackboard and make it more easy to bind them there than it is right now… like the framework is there to be easily extended to do whatever I could possibly need.

    Can you give me any insights into how best to access the components in game objects? I do plan to spend more time going back through your examples which always I seem to uncover more ways to do things.

    All the best

    #8977
    Gavalakis
    Keymaster

    Hello,

    If I understood you correclty you want to call methods and get/set properties on components found on your game objects (?)
    To do this you can use the various actions and conditions underneath the “Script Control” category for both actions and conditions respectively.
    With those you can execute functions on your components, get/set properties, check properties, or check functions that return a value against another value and even start coroutines. All this without the need to write custom tasks.

    Another way to directly communicate with your own code is the ability to bind blackboard variables to a component property. So instead of having a variable that is just a float value you can bind that variable to one float property in one of your components on the game object. Thus whenever you use that variable within one of the tasks, the property value will be returned (or set) instead. For example:

    You can bind/unbind a variable to a property with the small button on the far right on the variable.

    Join us on Discord: https://discord.gg/97q2Rjh

Viewing 6 posts - 1 through 6 (of 6 total)
  • You must be logged in to reply to this topic.