News Forums RAIN General Discussion and Troubleshooting detect when path is unreachable

This topic contains 8 replies, has 3 voices, and was last updated by  prime 7 months, 2 weeks ago.

Viewing 9 posts - 1 through 9 (of 9 total)
  • Author
    Posts
  • #36249

    bigfiregames
    Participant

    hi all,

    I’m using the wander and flee custom action from the rain starter kit to make my ai wander around my scene.
    my scene is quite complex and not all of the paths returned by the script are reachable for my ai.
    quite often they try to walk through a wall and become stuck.
    What would be the best way of determining if a path is un reachable and generating a new path? I’ve tried a variety of options on the navmesh (walk radius, step height etc) and also on the nav motor (close enough angle and distance etc.)

    if I have allow off mesh navigation checked the ai tries to walk through the wall.
    if allow off mesh navigation is unchecked my ai spins on the spot.
    I am not using root motion on my animations.
    I have many of the walls tabbed as un walkable and still the problem occurs.
    The navmesh looks ok. it has holes where the obstacles are and the problem seems to occur when the path ends close to one of these regardless of my close enough distance (I’ve tried values ranging from the default 0.1 to 5)

    many thanks

    #36255

    prime
    Keymaster

    In your case you probably want to keep the off mesh movement turned off. If a valid path can’t be found to the target, your move node should be failing (which is maybe why you are spinning in place). Three options:

    1) Handle the failure case for the Move node in the behavior tree.

    2) Add an additional check when searching for a move-to point. Use this method of the AI Navigator to determine if a valid path exists. If it doesn’t find a different point.

    public override bool GetPathTo(Vector3 position, int maxPathfindSteps, bool allowOffGraphMovement, out RAINPath path)

    3) Depending on how your scene is put together, you could potentially create valid wander targets manually, and then randomly choose between them when wandering. This wandering wouldn’t be truly “random”, but you could add additional randomness by adding a timer that causes the AI to choose a new random wander point after some random # of seconds.

    • This reply was modified 10 months ago by  prime.
    #36257

    bigfiregames
    Participant

    thanks.another quick related question, what does max path finding steps do?
    the docs seem very incomplete for a lot of settings.

    #36258

    bigfiregames
    Participant

    and another. sorry, busy day…. I’m having trouble organising my thoughts.
    How would I go about handling failed paths in the BT?

    #36260

    prime
    Keymaster

    RAIN pathfinding isn’t threaded, but instead allows you to break up the pathfinding process across frames. That’s true generally, but not for the GetPathTo call. Instead, GetPathTo attempts to do the entire pathfind in on step. Use MaxPathfindingSteps as a way to limit how long the AI is allowed to run.

    Unfortunately, there’s no real easy way to judge how many steps is a “good” number. A pathfinding step allows the A* algorithm to process a single graph node, so a “step” depends on the complexity and connectivity of the graph.

    Keep in mind that for your case, 100 is probably fine. You don’t need a guaranteed path across the level- you only need a reachable random point that’s probably nearby.

    #36261

    prime
    Keymaster

    Probably the best way to handle a Move failure, again specifically in your case where you probably don’t really care that the move failed, is to ignore it. Unfortunately, there isn’t a simple out-of-the-box way to ignore the results of BT nodes. But you can create a custom decision node that will return a specific value, regardless of what the child returns. Use this node as a parent for your move node and set the return value to “success”:

    using UnityEngine;
    using System.Collections;
    using System.Collections.Generic;
    using RAIN.Action;
    using RAIN.Core;
    using RAIN.Representation;
    [RAINDecision("Force Result Decorator")]
    public class ForceResultDecorator : RAINDecision
    {
        public Expression ReturnValue = new Expression();
        private int _lastRunning = 0;
        public override void Start(RAIN.Core.AI ai)
        {
            base.Start(ai);
            _lastRunning = 0;
        }
        public override ActionResult Execute(RAIN.Core.AI ai)
        {
            ActionResult tResult = ActionResult.SUCCESS;
            for (; _lastRunning < _children.Count; _lastRunning++)
            {
                tResult = _children[_lastRunning].Run(ai);
                if (tResult != ActionResult.SUCCESS)
                    break;
            }
            return GetResult(ReturnValue, ai);
        }
        public ActionResult GetResult(Expression aExpression, AI ai)
        {
            if ((aExpression == null) || !aExpression.IsValid)
                return ActionResult.FAILURE;
            if (aExpression.IsVariable && (aExpression.VariableName.ToLower() == "success"))
                return ActionResult.SUCCESS;
            else if (aExpression.IsVariable && (aExpression.VariableName.ToLower() == "running"))
                return ActionResult.RUNNING;
            else if (aExpression.IsVariable && (aExpression.VariableName.ToLower() == "failure"))
                return ActionResult.FAILURE;
            string tReturnValue = aExpression.Evaluate<string>(ai.DeltaTime, ai.WorkingMemory);
            if (string.IsNullOrEmpty(tReturnValue))
                return ActionResult.FAILURE;
            tReturnValue = tReturnValue.ToLower();
            if (tReturnValue == "success")
                return ActionResult.SUCCESS;
            else if (tReturnValue == "running")
                return ActionResult.RUNNING;
            else
                return ActionResult.FAILURE;
        }
    }
    #36266

    bigfiregames
    Participant

    many thanks for your help prime :)

    #37858

    Alex3D
    Participant

    Hi,
    Is RAINNavigator.GetPathTo() CPU-expensive?
    I want to use it in action similar to FindCover from Squad Command. So every call of this action will generate about 10 path checks for covers. Can it be too expensive for mobile app?
    And if NO - Is 10 find steps (parameter aMaxPathfindingSteps) enough for area 100×100 meters?
    Thanks.

    • This reply was modified 7 months, 3 weeks ago by  Alex3D.
    #37875

    prime
    Keymaster

    It can be expensive. The method will run MaxPathfindSteps (use 0 to force a full graph search) and search up to MaxPathLength length paths. This version does not run over multiple frames.

    10 find steps is probably not enough (depends on the graph complexity) but you could limit it by distance instead (something like 150 would probably be sufficient for that size graph).

    Even then 10 full path searches every frame could be too expensive, especially if there is some likelihood the path find will fail.

Viewing 9 posts - 1 through 9 (of 9 total)

You must be logged in to reply to this topic.