Support Forum

RayCast incompatible with A*Pathfinder? Forming a People Queue rather than Local Avoidance

Hello,

I’m trying to use A* to walk people, and want their speed to slow down if they are stuck behind a slower moving person in front. I tried local avoidance but this makes them walk around rather than stay in a queue. I’ve tried attaching the below to the people walking, all of whom are on a layer called “passenger” and tagged “passenger”. I can’t see to figure it out.

If there’s a better way please do let me know.

The goal is to have people walk to the DestinationSetter defined spot, but if a person is in front of them with a slower maxSpeed, then they will reduce their maxSpeed to match and maintain a reasonable distance behind, which will form a queue.

Thank you for your time and any advice you can give!

Below is my last day of code:

using System.Collections;
using System.Collections.Generic;
using UnityEngine;
using Pathfinding;

public class PassengerBehaviour : MonoBehaviour
{
    //This class is to ensure passengers don't walk through each other, but rather slow down and queue behind slower passengers
    //Help from: https://arongranberg.com/astar/docs/patrolexamplecs.html

    //Th A* Pathfinder Object for calling other class values
    //Help from: https://arongranberg.com/astar/docs/iastarai.html
    IAstarAI agent;

    //Variable to store the original max speed of the agent (passenger)
    float originalMaxSpeed;

    //Store the info of the raycast hitting
    RaycastHit hitInfo;

    //Create our Ray
    Ray ray;

    //LayerMask to identify which objects on a certain layer the ray can hit
    public LayerMask canHit;

    //The distance that th Raycast should show
    private float rayReach = 2.0f;

    void Awake()
    {
        //Store the component
        agent = GetComponent<IAstarAI>();

        //Store the target layer for the raycast
        //canHit = LayerMask.GetMask("Passenger"); --Not used anymore as I can select the layer in the editor
    }

    // Start is called before the first frame update
    void Start()
    {
        //Get the passengers original configured max speed (differs for child, adult and elderly)
        originalMaxSpeed = agent.maxSpeed;
    }

    // Update is called once per frame
    void Update()
    {
        //Using Raycasts to detect if and how far something is in front of the passenger,
        //rather than colliders which require contact to be made

        //Get the vector3 forward from the passenger
        var forward = transform.TransformDirection(Vector3.forward);
        //For debuggng purposes display a red line for the ray
        Debug.DrawRay(transform.position, forward * rayReach, Color.red);

        //Originally was detecting evreything but then I realised its just fellow passengers I want rather than walls, etc
        //So a slight change where layers are also used to reduce the gameobjects the raycast will interact with
        //Help from: https://stackoverflow.com/questions/56756046/unity-raycasthit-doesnt-recognized-object-with-tag
        //Help from: http://www.theappguruz.com/blog/collision-detection-without-rigid-body-in-unity
        //Help from: https://stackoverflow.com/questions/46788149/raycast-to-specific-layers-in-unity

        //Create a Ray starting at the passengers curent position and going forward
        ray = new Ray(transform.position, transform.forward);
        //If that Ray of a defined length (reach) hits something on an allowed layer (can hit Passenger layer)
        if (Physics.Raycast(ray, out hitInfo, rayReach, canHit))
        {
            //If that gameobject the ray hit is also tagged with Passenger
            if (hitInfo.collider.tag == "Passenger")
            {
        
                print("Detected " + hitInfo.collider.tag + ". It's " + hitInfo.distance + "m away.");


                //If another passenger is less than 1.2 distance infront of this passenger
                //Help from: https://answers.unity.com/questions/537673/raycast-object-tag-check.html
                if (hitInfo.distance < 1.2 && hitInfo.transform.gameObject.CompareTag("Passenger"))
                {
                    Debug.Log("There is something less than 1.2m infront of passenger. It's " + hitInfo.distance + "m away.");
                    //Gradually slow down this passenger to ensure a collision doesn't occur to the passenger in front,
                    agent.maxSpeed = agent.maxSpeed - 0.01f;
                    Debug.Log("The max speed of this " + gameObject.name + " passenger is reduced to: " + agent.maxSpeed);

                }
                //otherwise this passenger can walk at its normal max speed (varries on if adult, child or elderly)
                else if (agent.maxSpeed != originalMaxSpeed)
                {
                    agent.maxSpeed = originalMaxSpeed;
                    Debug.Log("The max speed of this " + gameObject.name + " passenger is reset to: " + agent.maxSpeed);
                }


            }
        }

            

            
       

        
    }
}

Hello,

In the end I got help on Fiverr which cost a bit but well worth it for what I learnt.
For anyone else, the problem was that the ray being cast was from the bottom of the prefab (the peoples feet) so this wasn’t always accurate. By creating a child object and positioning this in the center of my person and sending the ray casting from this child object rather than the transform of the parent, resulted in much more accurate results!

I would still like to feedback that a feature allowing agents to queue instead of always trying to push past to get their destination would be good to have.

Or perhaps I missed it and is this functionality already available please?

Thanks for your time!

1 Like