News Forums Search Search Results for 'timer'

Viewing 15 results - 1 through 15 (of 167 total)
  • Author
    Search Results
  • #39556

    kasperfm
    Participant

    Is the Timer action broken in the newest version of Unity? :-/

    I try using it, but it just keep staying in the “Running” state. Or are there a specific way to use the Timer action? :)


    kkgeffert
    Participant

    I am creating some of my behavior trees at run time and am struggling with the timer node:

    RAIN.BehaviorTrees.BTTimerNode timer = new RAIN.BehaviorTrees.BTTimerNode();

    What is the correct way to set the wait time to random e.g. Random(12,20)? I’m pretty sure I have to use RAIN.Representation.Expression API, but I don’t know exactly how. The API documentation does not provide examples.

    In case anyone wants to know, I solved it like this:

    RAIN.BehaviorTrees.BTTimerNode timer = new RAIN.BehaviorTrees.BTTimerNode()
    {
    WaitTime=RAIN.Representation.ExpressionParser.Parse (“Random(12,20)”)

    };

    • This topic was modified 2 weeks, 4 days ago by  kkgeffert.
    • This topic was modified 2 weeks, 4 days ago by  kkgeffert.
    #39450

    In reply to: Behavior Tree Question


    Sigil
    Keymaster

    Since the behavior tree isn’t actually threaded and can’t really run in parallel, all running children will be updated that one last time before the parallel “interrupts” them. The interrupting part is that even if a child returns running at that point, the parallel is done and is going to return failure or success, so the execution will never return to that child in its current state and the next time around it will get reset.

    root
       parallel (fail: any, succeed: any)
          sequencer
             timer (seconds: 3)
             expression (expression: debug("Parallel is going to stop now"), returns: success)
          sequencer
             timer (seconds: 6)
             expression (expression: debug("I am never going to get a chance to run"), returns: success)

    After three seconds the first timer is going to return success, and since the parallel is set to succeed if any of it’s children succeed, it will return success after that happens. The sequencer with the 6 second timer will get updated one last time (the same update the 3 second timer returns success on) but unless you had some incredible lag for that update it won’t get a chance to finish.

    • This reply was modified 3 weeks, 4 days ago by  Sigil. Reason: fixed a bug in the behavior tree
    #39442

    In reply to: Behavior Tree Question


    Sigil
    Keymaster

    You are correct that a behavior tree updates every frame. Incoming wall of text.

    So normally when a node is executed it returns success or failure. If it is a decision it often returns success or failure based on what its children return. Since you sometimes need to hold execution in the tree for awhile, a node can also return running, which tells its parent to come back next update and try again to get a success or failure.

    In RAIN, if a behavior tree returns success or failure, on the next update we reset the tree and start over. If a tree returns running though, on the next update we walk through the tree, following all the running nodes until we get to the last running node. At that point we try to get a success or failure again from the node and keep going (it can return running again if it likes).

    When you mark a node to repeat, it tells the node that instead of returning success or failure, it should return running and start again the next update. In the case where the repeating node was going to return running anyways, we allow that through, and whatever child node returned running will continue on the next update.

    Since a tree always returns (either success, failure, or running) it can never halt the update loop, the only thing that can do that would be a custom action that never returns for whatever reason. Repeating nodes can, however, stop the remaining execution of your behavior tree, which might make your AI halt in a way.

    An example:

    root
       sequencer
          sequencer
             timer (seconds: 3)
             expression (expression: debug("3 second timer expired", returns: success)
          sequencer (repeat: forever)
             timer (seconds: 6)
             expression (expression: debug("6 second timer expired", returns: success)
          sequencer
             timer (seconds: 9)
             expression (expression: debug("never going to get here")

    So this would pause 3 seconds and output and then pause 6 seconds and output, and then pause 6 seconds and output, and continue that forever.

    #39391

    Sigil
    Keymaster

    Hmmm, well I don’t think I have an exact solution for you. For the most part a behavior tree always starts at its root node on every single frame, and the variables/state that you have in your AI memory get it back to where it was executing each time it runs.

    The exception to this are nodes like animation, or timer, or any custom action that returns RUNNING for awhile. In these cases the tree skips and goes straight to that node until it finishes running. Unfortunately there isn’t a way to save that state. Like if a timer had run for 4 seconds, or an audio node had played for 10 seconds, that can’t be saved and restored accurately.

    You should be able to get close if you are saving your memory out, but it won’t be an exact state.

    #39385

    ngtrhieu0011
    Participant

    Hi,

    Currently I have a simple AI which look like this:

    - Selector [root]
    — Chase player and attack [Sequence]
    ——- Find player [Action - custom - failure when cannot detect player]
    ——- <to be implemented>
    — Wander [Sequence]
    ——- Random wander point [Action - custom]
    ——- Move to wander point [Action - custom]
    ——- Wait a bit [Action - timer]

    The idea is, when the AI not detecting the player, it will on “Wander” state and keep moving around. However, when the player is detected, it should goes into the “Chase” state and chase down the player. However, the AI will not detect player when it is in the middle of running the Wander sequence (either when it is moving or waiting). Is there a way to “break” the sequence?

    Another way to ask: is there a way to force RAIN AI to start again at the root at every tick instead?

    ——-
    P.s: I am aware of the method of using parallel node as showing in this thread http://rivaltheory.com/forums/topic/example-xml-files. However, I feel it would later complicating the tree with so many nested parallel group :(

    • This topic was modified 1 month, 1 week ago by  ngtrhieu0011.

    Sigil
    Keymaster

    Generally I use a timer if the animation can be interrupted, like a looping animation of some kind: idle, look around, etc. For animations that can’t be I most often end up in a Custom Action to handle it.

    The main reason I use a Custom Action in this case is that I almost always pair my attack with some custom code to handle damage, or to line up the damage with the animation. Check out this thread for a more detailed behavior tree, with an attack that used a custom action.


    wightwhale
    Participant

    I put in a timer which seems to be working now.

    #39279

    Sigil
    Keymaster

    To answer your previous questions:

    1) Repeat forever essentially means that if the node ever returns anything other then running it will reset and start again. So if you have something like this:

    sequencer
        sequencer (repeat forever)
            timer (seconds: 5)
            expression (expresson: debug("times up"), returns: success)
        expression (expression: debug("never gonna get here"), returns: success)

    It will display “times up” in the console every 5 seconds, and much like the message says, it will never get to the second expression.

    2) Yes, repeat until success will repeat the node until it returns success, but I think you got that figured out based on your message.

    Repeating can be useful if you want to hold the AI in a state until something happens. I often use this pattern when waiting to detect the player:

    sequencer
        parallel (succeed: any, fail: any, tie breaker: fail)
            detect (repeat: until success, aspect: "player")
            waypoint patrol (waypoint route: "waypoints", move target variable: waypointTarget)
                move (move target: waypointTarget)
        expression (expression: debug("detected the player"))

    So this tree will patrol until the AI detects a “player” aspect. So if the player never comes around, it will patrol forever.

    Check out the starter kit to see more examples of similar behavior and come back with any questions.


    Sigil
    Keymaster

    OK, well then if everything else is working, all that is left is to add the attack back in. Behavior tree should look like this at this point:

    root
        sequencer
            parallel (fail: any, success: any, tie breaker: fail)
                detect (repeat: Until Success, aspect: "Player", form variable: playerTarget)
                sequencer (repeat: Forever)
                    parallel (fail: any, success: any, tie breaker: fail)
                        detect (repeat: Until Success, aspect: "Food", form variable: foodTarget)
                        sequencer (repeat: Forever)
                            custom action (class: ChooseRandomLocation, target: moveTarget, distance: 20)
                            move (move target: moveTarget)
                            timer (seconds: random(1, 5))
                    move (move target: foodTarget, close enough distance: 1)
                    mecanim parameter (parameter: Eat, parameter type: Trigger), value: true)
                    custom action (class: ConsumeFood, target: foodTarget)
            selector
                parallel (fail: any, success: any, tie breaker: fail)
                    sequencer (repeat: Until Failure)
                        expression (expression: playerTargetPosition = position(playerTarget), returns: Success)
                        detect (aspect: "Player", form variable: playerTarget)
                    sequencer
                        move (move target: playerTarget)
                        move (face target: playerTarget)
                        mecanim parameter (parameter: Attack, parameter type: Trigger), value: true)
                        custom action (class: AttackTarget, target: playerTarget)
                parallel (fail: any, success: any, tie breaker: fail)
                    detect (repeat: Until Success, aspect: "Player", form variable: playerTarget)
                    move (move target: playerTargetPosition)

    Note that I removed the timer that was before the ConsumeFood action, as the action will handle that wait at this point. Also I’m assuming we’re using the AttackTarget custom action originally posted.


    Sigil
    Keymaster

    I think I’m confused as to where we are. Perhaps we went back too far?

    You say you see no anomalies, so what is happening? At the end of the first page there was random wandering, eating food, chasing the player, and resuming the random wandering if he loses the player. Is that what we are seeing at this point?

    Did you remove your changes to the ConsumeFood action as well? The original setup assumed an animation that either looped or was less than the timer I set in the tree (I didn’t clarify this at the time, which was dumb, my mistake). Your modification was a good one if you want to have the entire animation play properly (doesn’t need the ResetTrigger though). If you use your modified version you can remove the timer as well, as your custom action will handle the wait.

    #39200

    Sigil
    Keymaster

    I’ll have to come back and take a look at your tree as it is rather large. I’m glad it is working for you though.

    As for your questions, these answers may lead to even more confusion, but I’ll try anyhow:

    “having a node marked as a loop calls whatever is inside every frame like Update function?”
    When a node is marked to repeat it runs like it always would, but when the node returns SUCCESS or FAILURE the behavior tree “pretends” it returned RUNNING instead, and the next Update it comes back to the same node again, and restarts it as if it was the first time it ran into it.

    “how is a Timer node affected by a loop node?”
    The timer will wait the designated time limit, and then return SUCCESS or FAILURE (depending on settings). If it is set to repeat forever, the tree will ignore the return value (it will return RUNNING instead), and start the timer over again. From the outside this will just look like a timer that is running forever.

    “is there a way of resetting the timer node?”
    A repeat is a good way of resetting a timer node, the following shows that:

    root
        sequencer
            expression (expression: debug("Hi"), return: success)
            sequencer (repeat: forever)
                expression (expression: debug("Hello"), return: success)
                timer (seconds: 5)

    This would print “Hi” to the console, followed by an additional “Hello” every five seconds. Every time the timer finishes and returns success, the repeat on the sequencer kicks in and resets the subtree, allowing it to start the timer again next Update.

    #39194

    LudwigVanKinder
    Participant

    Thnks for the reply, i figured it out by my own. As you may see i took the tree from the example at the tutorial section & expanded it upon my needs, This is the first time i get into Behaviour trees & whatever outside JS & C#. As you may see i’m having a hard time at it. however i got this to work, not in the best possible way, but whatever it works i guess, hehe. I’m open to learn how to program more efficient behavior trees & if you notice something stupid i’m doing (if not all) please let me know.

    Also i have a few questions i’d love to be clarified about, if you don’t mind (the wiki is not very detailed about this)

    having a node marked as a loop calls whatever is inside every frame like Update function?
    how is a Timer node affected by a loop node?
    is there a way of reseting the timer node?

    Thank you very much :)

    Root
        Parallel (repeat: never)
            Detect (repeat: forever, sensor: “Visual Sensor”, aspect: “person”, detect: Best match, form variable: PersonOfInterest)
            Selector (Repeat: forever)  //Select Current State
                Constraint (PersonOfInterest==null)
                    Selector (repeat: never)
                        Constraint (stopSearching==true)  //Patrolling
                            Selector (repeat: never)
                                Constraint (takingBreak==false)
                                    Parallel (repeat: never)
                                        Waypoint Patrol (Waypoint Route: myRoute, loop type: loop, direction: forward, Move Target Variable: moveTarget)
                                            Move (Move Target: moveTarget)
                                        Expression (Expression: countSecondsWalking=true)
                                Constraint (takingBreak==true)
                                    Expression (Expression: countSecondsTakingBreak=true)
                        Constraint (stopSearching==false) //Saw the character not so long ago so still looking for him
                            Selector (repeat: never)
                                Constraint (justSawHim==true)
                                    Parallel (repeat: never)
                                        Expression (Expression: countSecondsToLoseInterest=true)
                                        Expression (justSawHim=false)
                                Constraint (justSawHim==false)
                                    Move (Move Target: character)
                Constraint (PersonOfInterest != null)  //Is watching the character so it’s walking towards him
                    Parallel (repeat: never)
                        Move (Move Target: personOfInterest)
                        Expression (stopSearching==false)
                        Expression (justSawHim = true)
                        Constraint (talkedToHim==false)
                            parallel (repeat: never)
                                Custom Action (triggers a script i made to play a random Audio Fx)
                                Expression (talkedToHim=true)
            Selector (Repeat: forever)
                Constraint (countSecondsToLoseInterest=true) //this is called if the enemy just lost the character from sight
                    Sequencer (Repeat: never)
                        Timer (seconds: secondsToLoseInterest)
                        Parallel (repeat: never)
                            Constraint (stopSearching==false)
                                Expression (stopSearching=true)
                            Expression (talkedToHim=false)
                            Expression (CountSecondsToLoseInterest=false)
            Selector (Repeat : forever) //this is called while walking to then switch to idle or “taking a break”
                Constraint (countSecondsWalking==true)
                    Sequencer (repeat: never)
                        Timer (seconds: secondsWalking)
                            Parallel (repeat: never)
                                Expression (takingBreak=true)
                                Expression (countSecondsWalking=false)
            Selector (Repeat: forever) // this one is called when idle to know when to continue patrolling
                Constraint (countSecondsTakingBreak==true)
                    Sequencer (Repeat:never)
                        Timer (seconds: secondsTakingBreak)
                            Parallel (repeat: never)
                                Expression (countSecondsTakingBreak=false)
                                Expression (takingBreak=false)
    • This reply was modified 2 months, 2 weeks ago by  Sigil. Reason: fixed formatting
    #39170

    Sigil
    Keymaster

    Let’s reorganize your tree a little to get this to work right, and then I’ll add the bit to record the last position of the AI. For my purposes I may be using different variable names, but you can switch them around:

    root
        sequencer
            parallel (succeed: any, failure: any, tie breaker: succeed)
                detect (repeat until success, aspect: "player", form variable: playerTarget)
                waypoint patrol (waypoint route: "Waypoint Route", move target variable: patrolTarget)
                    move (move target: patrolTarget)
            parallel (succeed: any, failure: any, tie breaker: succeed)
                detect (repeat until failure, aspect: "player", form variable: playerTarget)
                move (move target: playerTarget)
                custom action (InstantiateSound)

    So this should pretty much be what your current tree was doing (minus a few things I see in it that look like you were testing something): patrolling while looking for the player, then chasing the player unless they can’t see them anymore.

    So to get the last bit, you need to record the position of the player while you’re chasing them, just in case you lose them. There is an expression function for that called “position”. In the event that we lose the player, we’ll attempt to follow their last good position instead.

    root
        sequencer
            parallel (succeed: any, failure: any, tie breaker: succeed)
                detect (repeat until success, aspect: "player", form variable: playerTarget)
                waypoint patrol (waypoint route: "Waypoint Route", move target variable: patrolTarget)
                    move (move target: patrolTarget)
            selector
                parallel (succeed: any, failure: any, tie breaker: succeed)
                    sequencer (repeat until failure)
                        expression (expression: playerPosition = position(playerTarget), return: success)
                        detect (aspect: "player", form variable: playerTarget)
                    move (move target: playerTarget)
                    custom action (InstantiateSound)
                parallel (succeed: any, failure: any, tie breaker: succeed)
                    detect (repeat until success, aspect: "player", form variable: playerTarget)
                    sequencer
                        move (move target: playerPosition)
                        timer (seconds: random(2, 3))

    So I took the second parallel and put it in a selector to give us a failure case (the case where we lose track of the player). I changed the detect that was repeating until failure to a sequencer, so that I can record the position of the player, before attempting to detect them again.

    In the second part of the selector, where we know we’ve lost sight of our player, I attempt to detect them again, while moving towards their last position. The timer is just to make the AI pause at the position, you could replace that with a look around animation or something similar.

    I recommend you trying to get my first example tree working, then see if you can get the second one going. Let me know if you have questions/problems.


    Mad_Mark
    Participant

    Sigil,

    This is all working, but the Attack part is a bit flaky. SOMETIMES, not always, when I leave the “AttackRange” sensor, the zombie continues to attack. I have had to make this a Bool, both in my AIcontroller, and in the associated scripts/BT. Leaving it as trigger seemed to fire too quickly. It would reset right away after firing, and the zombie would just twitch like it was starting the attack animation, then falling back to the locomotion anim, then firing the attack anim, then the loco again. Timers didn’t seem to help, as the trigger was still too quick to recover.

    So the Bool’s are working, but they don’t seem to change reliably. Once every 4 or 5 times the zombie gets stuck in attack mode. Moving back into range resets it to not attack, and the next BT round sets it back to attack, fixing the issue. I probably need to check status of the Bool, and if its true already, set it to false.

    I am satisfied that a little tweaking will fix this glitch, so what is the next step in our journey?
    Mark

Viewing 15 results - 1 through 15 (of 167 total)