Tick() broken for non-repeat graph without actions running over time

Forums 💬 NodeCanvas ⚙️ Support Tick() broken for non-repeat graph without actions running over time

Viewing 10 posts - 1 through 10 (of 10 total)
  • Author
    Posts
  • #17052
    clem
    Participant

      Hi,

      Updating Node Canvas to the latest version broke my existing logic and I’ve been digging into what happens.

      My setup is very similar to the section in the documentation called “Manual Tick (BehaviourTrees only)”
      – I instantiate a BehaviourTreeOwner at runtime
      – I set its “behaviour” property to the behavior I want (obtained via inspector variable)
      – I set it to not repeat
      – Then I call Tick() on that owner from Update

      What seems to happen is that my graph is never technically running, since I don’t start it, and it executes in one frame (it doesn’t contain running actions, all actions it contains return Success right away).

      The updates to BehaviourTree.cs and BehaviourTreeOwner.cs that I can see from my previous version and the latest one seem to no longer directly call Tick on the behavior but instead use UpdateBehaviour. However, this leads to a check if graph.isRunning == true before actually calling GraphUpdate(). Since my graph is not runnning, this check fails and it will never actually update the graph when I call Tick().

      Could you please either provide a fix for this, or let me know what the new correct way of achieving that result is?

      My code is

      Thank you

      #17061
      Gavalakis
      Keymaster

        Hello,

        Thanks for finding and letting me know of this bug.
        A quick fix/solution to that (in the latest version), would be to make a call to “StartGraph” with the parameter “autoUpdate” being false in your Initialize method. In that same ‘StartGraph’ overload that takes the “autoUpdate” parameter, you can also provide a callback for when the behaviour is finished. You can if you want use that callback to also stop the graph when that is done.
        Here is an example code:

        Please let me know if that works for you.
        Thank you!

        #17060
        clem
        Participant

          Thank you, for now I just commented out the check for IsRunning as I’m not using graphs extensively and don’t have any graphs that will run more than a frame so it won’t break anything yet.

          I believe I’ve tried something similar to what you suggest while playing around and looking into the source code, but since my graph stops right away, starting it just gives me one frame of execution before it’s no longer running again. I noticed that adding a node that runs over multiple frames (e.g. a debug log for 2 seconds) would allow the graph to update for those 2 seconds then stop.

          I’ll leave it like that until my next update and hopefully by then a better fix will have been released for this use-case. Thank you

          #17059
          clem
          Participant

            Hello again!

            I updated to the latest version of NodeCanvas and the problem is back so I have to repeat my local hacky fix again, and figured I’d point out the issue once more in hope for an official fix.

            Here’s how I’m using Node Canvas:

            • I control my player character with a Behavior Tree so I can visually organize what to do based on conditions (e.g. is the player trying to move, is the movement allowed, etc.) not necessarily because this makes more sense than hard-coding player logic but because that way all actors in the game, whether AI or players, follow the same structure and I can share modules between them.
            • At the moment, that BT controlling my player does not actually run any actions for longer than a frame. For instance, it determines what forces to apply or what direction to move to, but does not enter an action that completes later, and so the BT ends the frame it is called.
            • My actor setup is fairly advanced, so I want the BT to be called after a lot of other scripts have ran (e.g. sensing the surroundings into data that can be used for determining what to do this frame) and before others do (e.g. kinematic physics calculations) so I want to call it manually at a specific point each frame with Tick() (not to set it to repeat automatically)

            This used to work just fine when I initially created this setup, but after upgrading NodeCanvas a few months ago, it is no longer executing my BT each time I Tick() it, only once the first time.

            In CanvasCore/Framework/Runtime/Graph/Graph.cs, I have to remove the check for isRunning == true in the UpdateGraph function to make my BT work, as a graph that doesn’t start any longer-than-one-frame action will apparently only “run” for one frame, and so Tick() will not execute it past the 1st frame (where it actually starts and gets executed once).

            You suggestion from a few months ago does not help, the graph still isn’t considered to be running after the initial frame it ran and completed on, so Tick() does nothing.

            Repro steps:
            – Create a new project
            – Import NodeCanvas
            – Create a new GameObject
            – Add a Behaviour Tree Owner to that object & set it to not repeat and do nothing on Enable/Disable
            – Create a bound BT for that owner that simply logs a variable value from the blackboard
            – Create a MonoBehaviour on that same object that contains the following code:

            What happens:
            – The value of the blackboard variable is logged once

            What I expect:
            – The value of the blackboard variable is logged each frame

            This would work:

            but means it won’t work for any graph that lasts more than one frame.

            Could you look into this issue please, and either support that functionality again, or let me know of an alternative supported way to achieve that result?

            I guess the old Tick() behavior was “start or update” and the new one is “update if running” which is causing my issues. I’d just like to be able to update NodeCanvas without having to reapply fixes each time to maintain the functionality of the NodeCanvas version I started my project with.

            Thank you

            EDIT:
            I guess I was a bit caught up on making sure Tick() worked like it did before, I can do this I guess:

            Let me know if you see any issues with that approach, thank you

            #17058
            soren bach
            Participant

              Yeah, I came here to say I have the exact same problem. Why has this not been fixed yet? : I’m using the latest version from the asset store (2.9.6).

              For now I’m using the fix that Clem posted.

              #17057
              Gavalakis
              Keymaster

                Hello,

                Aparently I completely missed Clem’s last post. I am really sorry about that!

                Tick() should always be called after a graph is Started (regardless of whether or not the behaviour is repeated). StartBehaviour must be called since it is responsible for setting references as well as calling various callbacks in nodes like OnGraphStarted (which are essential for correct initialization).

                If we want to manually Update a graph (or Tick a tree in case of BT), we need to call StartBehaviour with the autoUpdate argument set to false owner.StartBehaviour(false, null);.

                In cases where we manually Tick the tree, leaving the “repeat” option enabled is desirable, since the point of the “repeat” option is to automatically Stop() the tree (disable it). Thus if we do not want any automation like that, we need to keep the “repeat” option enabled.

                As such, to manually Tick() a tree correctly, all we have to do is leave the “repeat” option enabled and do something like this in code:

                I have just updated the documentation (which was missing the part that StartBehaviour needs to be called). I have also now added a warning if UpdateGraph is called without first having the graph started to avoid any confusion.

                Please let me know if this works for you.

                #17056
                soren bach
                Participant

                  Hey, thanks for getting back to this. I’ve tried implementing your way, but I’m getting some odd behaviour. This could be because of my own AI logic though, so I’ll have to investigate.

                  But when I’m using your implementation, I’m getting a few warnings that doesn’t seem to lead back to any of my code?

                  #17055
                  Gavalakis
                  Keymaster

                    Hey,

                    You are welcome.
                    In the BehaviourTreeOwner inspector, you need to set the “OnEnable” setting to “Do Nothing”. Otherwise if it is set to “Start Behaviour”, the behaviour will be started automatically as normal and by default. However if in your case you want to start the behaviour manually (like the code provided) you don’t want the BehaviourTreeOwner to also start it. Thus setting “OnEnable” to “Do Nothing” will prevent this 🙂

                    #17054
                    soren bach
                    Participant

                      Worked like a charm, thank you 🙂 !

                      #17053
                      Gavalakis
                      Keymaster

                        You are very welcome 🙂

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