Modifying NodeCanvas?

NodeCanvas Forums Support Modifying NodeCanvas?

Viewing 2 posts - 1 through 2 (of 2 total)
  • Author
    Posts
  • #10619
    hatchling
    Participant

    Hi,

    I’m modifying NodeCanvas slightly to suit our needs more closely. I’d like to discuss this change with more experienced users on the best way to implement a change, or whether it is necessary in the first place.

    We’re interested in using NodeCanvas to help with chatacter state management – specifically, given the state of the character, what actions are available?
    Previously this was done in a somewhat ugly way. Each ability would have it’s own “state machine”, describing the state of the ability. They were simple, operated through System.Enums and sometimes only had two states – Active and Idle. Some had sub-states; for example, MeleeState.Attack had substates MeleeAttackType.Chop and MeleeAttackType.Stab, then those had different phases: MeleeAttackPhase.Anticipation, MeleeAttackPhase.Action and MeleeAttackPhase.Reaction.
    We wanted to ensure that only one ability could be triggered at a time – that is, in order for an action to trigger, it’d have to check the states of every other action being performed to make sure they were all idle. Because of this it was difficult to know what actions were possible at any given time due to how spread out this process was. It also coupled a lot of stuff together.

    Using a state machine would simplify this problem and make it much more intuitive to work with.

    That being said, many of our actions operate in this fashion: Character abilities would be represented as one or more behaviours. They’d have access to the current state of their associated state machine, as well as the current progress through that state. Based on those parameters, they’d execute different code. Usually the current progress value would drive the progress through an animation clip of the given action.

    This seems to run contrary to the intended usage of NC’s state machines. Rather than Behaviours reading into the state of the state machine and executing differently, the state machine itself runs the behaviours and the behaviours themselves have no awareness of their place in the state machine.
    While I agree that the latter approach is probably better in at least the majority of cases, we cannot really afford to rewrite all of our behaviour code. A more feasible alternative seems to me that we should have our behaviours read the state of the state machine as before, but where our ugly pseudo-state-machines are replaced by a single NC state machine.

    So far to accomplish this goal, we’ve changed Node.cs so that in addition to a name, tag and description, nodes may also have a System.Enum. This has advantages over strings in that it’s difficult to verify whether you’ve made a typo, whereas if you’ve done so with an Enum, the compiler would tell you right away. This is working great so far.

    This is where I’m currently stuck:
    The MeleeState.Attack state contains a nested FSM with five states. The first state is a dummy “start” node that immediately transitions into one of the other four states depending on conditions attached. The other four states are the four different attack variations that each melee weapon has: MeleeAttackType.SwingLeft, MeleeAttackType.SwingRight, MeleeAttackType.Chop, MeleeAttackType.Stab.
    Those four states too are nested FSM’s with three states: MeleeAttackPhase.Anticipation, MeleeAttackPhase.Action and MeleeAttackPhase.Reaction.

    We need to be able to control the timing of state changes depending on whether you are in the MeleeAttackPhase.Anticipation, MeleeAttackPhase.Action or the MeleeAttackPhase.Reaction phase of the attack. In other words, the duration of each one of these states differ. Ideally, we’d like to have a single ActionTask on each of these states, and then use the Enum value associated with the FSMState as lookup parameters for the weapon’s timing stats. However, it appears that it is currently impossible to access the parent Node from within an ActionTask.

    Furthermore, we need to be able to control the timing of state changes depending on what type of attack you are doing. That is, the rate at which MeleeAttackPhase.Anticipation progresses into MeleeAttackPhase.Action differs depending on whether the “parent” state is MeleeAttackType.Chop or MeleeAttackType.Stab. It appears that there is currently no way to determine the Enum value of “parent” states, even if it were possible to access the Node from within the ActionTask.

    I am considering changing the code so that it is possible to navigate the node heirarchy from any point in the FSM similar to how GameObjects operate, but this seems like a big undertaking. I thought I’d ask for advice before I start.

    Thanks in advance for any help you may provide! 🙂

    #10626
    Gavalakis
    Keymaster

    Hello!

    Thanks for the detailed info and sorry for the late reply.
    If I understood the issue correctly down to it’s core, the problem is that you want to control the timing for a transition to happen, rather than taking place immediately. So basicaly something like a time based condition.

    Here is a Timeout ConditionTask. Basicaly, what it does, is that it only returns true after a period of time has passed while it is checked.
    You could use this Timeout condition along with some other conditions within a ConditionList on the transition, which is set to “ALL TRUE”.

    As such, the transition will take place only when all the conditions are true, including that the Timeout time has also come to pass.

    Then as far as setting the timer, it can be done so through it’s parent state by setting a Blackboard Float Variable, and setting the Timeout condition ‘timeout’ BBParameter to read from that float variable.

    Please let me know if that works for you, or maybe I completely misunderstood the actual issue 🙂
    Thanks!

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

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