News Forums RAIN General Discussion and Troubleshooting Find Next Position Prior to Movement

This topic contains 5 replies, has 2 voices, and was last updated by  prime 1 month, 2 weeks ago.

Viewing 6 posts - 1 through 6 (of 6 total)
  • Author
    Posts
  • #34997

    Velathora
    Participant

    Hello all,

    As discussed a while back with @prime , I have been able to create a Pedestrian Traffic Manager Controller to be able to control my AI within a pedestrian system.
    I have been able to get everything working in regards to avoidance with obstacles and other AI, but I am at a snag with a cross-walk understanding.

    From what I have been able to gather, it seems the AI will walk towards a particular Traffic Post which has an entity node. The entity node will then have access to two directions, either left, or right. In which case, it is able to know which direction is available for travel.

    The issue lies within this particular portion. I have an AI that will walk up to the Traffic Post and want to get to a navigation target that is located somewhere on the map. The Vector3 of the Navigation Target and the AI current position are both exposed and available. I seem to see that the AI will take the shortest path along the Navigation Mesh to be able to get to the position, however, when at a Traffic Post, I don’t know how to get the direction that it will be going. Now, if I know that it is going on one path versus another, I will be able to solve the issue.

    Is there a way that I am able to expose and use a particular “next position” that has been possibly plotted by the AI?

    I.E.: At any moment, am I able to get the position that the AI will be going to next along its path toward the Navigation Target.

    If these are easily answered, how would I go about making the decision, as I’m not sure if my approach is even 100% accurate.

    Current Code: (Needs cleaning up)

    using UnityEngine;
    using System.Collections;
    using System.Collections.Generic;
    using RAIN.Core;
    using RAIN.Action;
    using RAIN.Navigation;
    using RAIN.Navigation.Waypoints;
    using RAIN.Entities;
    using RAIN.Navigation.Targets;
    public class PedestrianControlManager : MonoBehaviour
    {
    		//Single Pedestrian Node For Instantiation
    		public GameObject pedestrianNode;
    		//Pedestrians on Map
    		public GameObject[] peopleUnits;
    		//Navigation Possibilities
    		public GameObject[] navPoints;
    		//AIRig Components 
    		private List<AIRig> aiRigs;
    		void Awake ()
    		{
    				//Init
    				aiRigs = new List<AIRig> ();
    		}
    		// Use this for initialization
    		void Start ()
    		{
    				//Init
    				int currPoint = 0;
    				for (int i = 0; i < peopleUnits.Length; i++) {
    						//create pedestrian entity nodes with aspect and assign
    						GameObject currPosNode = Instantiate (pedestrianNode, peopleUnits [i].transform.position, Quaternion.identity) as GameObject;
    						currPosNode.transform.parent = peopleUnits [i].transform;
    						currPosNode.GetComponent<EntityRig> ().Entity.Form = peopleUnits [i];
    						currPosNode.GetComponent<EntityRig> ().Entity.GetAspect ("Pedestrian").MountPoint = peopleUnits [i].transform;
    						//add each entity to list
    						aiRigs.Add (peopleUnits [i].GetComponentInChildren<AIRig> ());
    						//assign random path for each person
    						currPoint = Random.Range (0, navPoints.Length);
    						aiRigs [i].AI.WorkingMemory.SetItem<Vector3> ("varPoint", navPoints [currPoint].GetComponent<NavigationTargetRig> ().Target.PositionOffset);
    						aiRigs [i].AI.WorkingMemory.SetItem<bool> ("varDetectingOthers", false);
    						peopleUnits [i].GetComponent<LocationData> ().myTarget = navPoints [currPoint].GetComponent<NavigationTargetRig> ().Target.PositionOffset;
    				}
    		}
    		// Update is called once per frame
    		void Update ()
    		{
    				//tDetected (if Detected)
    				GameObject tDetected;
    				for (int i = 0; i < aiRigs.Count; i++) {
    						if (aiRigs [i].AI.WorkingMemory.GetItem<bool> ("varDetectingOthers")) {
    								tDetected = aiRigs [i].AI.WorkingMemory.GetItem<GameObject> ("varPedestrian");
    								if (tDetected != null) {
    										if (!aiRigs [i].AI.WorkingMemory.GetItem <bool> ("amPaused")) {
    												//Not paused, but need to turn to avoid
    												peopleUnits [i].GetComponent<LocationData> ().needToTurn = true;
    												//original position
    												peopleUnits [i].GetComponent<LocationData> ().theOrigRotation = peopleUnits [i].transform.eulerAngles;
    												float customMovement;
    												RaycastHit hit;
    												if (Physics.SphereCast (peopleUnits [i].transform.position, 
    				                       peopleUnits [i].transform.localScale.y / 2f, 
    				                       peopleUnits [i].transform.forward, 
    				                       out hit, 15f)) {
    														//if units near, take movement and offset (lerp in LocationData Script)
    														customMovement = Vector3.Angle (peopleUnits [i].transform.position, hit.collider.gameObject.transform.position);
    														peopleUnits [i].GetComponent<LocationData> ().theNewRotation = new Vector3 (peopleUnits [i].transform.eulerAngles.x,
    						                                                                            peopleUnits [i].transform.eulerAngles.y + (2f * 2f * customMovement),
    						                                                                            peopleUnits [i].transform.eulerAngles.z);
    												}
    										} else {
    												//otherwise turn anyways (clean this up later)
    												peopleUnits [i].GetComponent<LocationData> ().needToTurn = true;
    												peopleUnits [i].GetComponent<LocationData> ().theOrigRotation = peopleUnits [i].transform.eulerAngles;
    												float customMovement;
    												RaycastHit hit;
    												if (Physics.SphereCast (peopleUnits [i].transform.position, 
    						                        peopleUnits [i].transform.localScale.y / 2f, 
    						                        peopleUnits [i].transform.forward, 
    						                        out hit, 20f)) {
    														customMovement = Vector3.Angle (peopleUnits [i].transform.position, 
    							                                hit.collider.gameObject.transform.position);
    														peopleUnits [i].GetComponent<LocationData> ().theNewRotation = new Vector3 (peopleUnits [i].transform.eulerAngles.x,
    							                                                                            peopleUnits [i].transform.eulerAngles.y + (customMovement + 10f),
    							                                                                            peopleUnits [i].transform.eulerAngles.z);
    												}
    										}
    								} else {
    										peopleUnits [i].GetComponent<LocationData> ().needToTurn = false;
    								}
    								if (Vector3.Distance (aiRigs [i].AI.WorkingMemory.GetItem<Vector3> ("varPoint"), peopleUnits [i].transform.position) < 1) {
    										Debug.Log ("I'm Close!");
    										int currPoint = Random.Range (0, navPoints.Length);
    										while (navPoints [currPoint].GetComponent<NavigationTargetRig> ().Target.PositionOffset == 
    				       peopleUnits [i].GetComponent<LocationData> ().myPos) {
    												currPoint = Random.Range (0, navPoints.Length);
    										}
    										aiRigs [i].AI.WorkingMemory.SetItem<Vector3> ("varPoint", 
    				                                              navPoints [currPoint].GetComponent<NavigationTargetRig> ().Target.PositionOffset);
    								}
    						}
    				}
    		}
    }
    <?xml version="1.0" encoding="UTF-8"?>
    <behaviortree version="1.1" repeatuntil="" name="NewPatrolRealAtt" debugbreak="False">
      <parallel tiebreaker="fail" succeed="all" repeatuntil="" name="root" fail="any" debugbreak="False">
        <detect sensor=""eyeDetection"" repeatuntil="running" name="detect" entityobjectvariable="varPost" debugbreak="False" aspectvariable="" aspectobjectvariable="" aspect=""Post"" />
        <detect sensor=""eyeDetection"" repeatuntil="running" name="detect" entityobjectvariable="varPedestrian" debugbreak="False" aspectvariable="" aspectobjectvariable="" aspect=""Pedestrian"" />
        <selector usepriorities="False" repeatuntil="" name="selector" debugbreak="False">
          <constraint repeatuntil="" priority="" name="constraint" debugbreak="False" constraint="varPost != null">
            <selector usepriorities="False" repeatuntil="" name="selector" debugbreak="False">
              <constraint repeatuntil="" priority="" name="constraint" debugbreak="False" constraint="amPaused">
                <parallel tiebreaker="fail" succeed="all" repeatuntil="" name="parallel" fail="any" debugbreak="False">
                  <move turnspeed="" repeatuntil="" name="move" movetarget="varPoint" movespeed="2" facetarget="" debugbreak="False" closeenoughdistance="" closeenoughangle="" />
                  <animate repeatuntil="running" name="animate" debugbreak="False" animationstate="Walk" />
                </parallel>
              </constraint>
              <constraint repeatuntil="" priority="" name="constraint" debugbreak="False" constraint="!amPaused">
                <parallel tiebreaker="fail" succeed="all" repeatuntil="" name="parallel" fail="any" debugbreak="False">
                  <move turnspeed="" repeatuntil="" name="move" movetarget="varPoint" movespeed="2" facetarget="" debugbreak="False" closeenoughdistance="" closeenoughangle="" />
                  <animate repeatuntil="running" name="animate" debugbreak="False" animationstate="Walk" />
                </parallel>
              </constraint>
            </selector>
          </constraint>
          <constraint repeatuntil="" priority="" name="constraint" debugbreak="False" constraint="varPost == null">
            <selector usepriorities="False" repeatuntil="" name="selector" debugbreak="False">
              <constraint repeatuntil="" priority="" name="constraint" debugbreak="False" constraint="varPedestrian != null">
                <expression returnvalue="evaluate" repeatuntil="" name="expression" expression="varDetectingOthers = true" debugbreak="False" />
                <expression returnvalue="evaluate" repeatuntil="" name="expression" expression="amPaused = true" debugbreak="False" />
                <selector usepriorities="False" repeatuntil="" name="selector" debugbreak="False">
                  <constraint repeatuntil="" priority="" name="constraint" debugbreak="False" constraint="amPaused">
                    <parallel tiebreaker="fail" succeed="all" repeatuntil="" name="parallel" fail="any" debugbreak="False">
                      <animate repeatuntil="running" name="animate" debugbreak="False" animationstate="Walk" />
                    </parallel>
                  </constraint>
                </selector>
              </constraint>
              <constraint repeatuntil="" priority="" name="constraint" debugbreak="False" constraint="varPedestrian == null">
                <parallel tiebreaker="fail" succeed="all" repeatuntil="" name="parallel" fail="any" debugbreak="False">
                  <expression returnvalue="evaluate" repeatuntil="" name="expression" expression="varDetectingOthers = true" debugbreak="False" />
                  <move turnspeed="" repeatuntil="" name="move" movetarget="varPoint" movespeed="2" facetarget="" debugbreak="False" closeenoughdistance="" closeenoughangle="" />
                  <animate repeatuntil="running" name="animate" debugbreak="False" animationstate="Walk" />
                </parallel>
              </constraint>
            </selector>
          </constraint>
        </selector>
      </parallel>
    </behaviortree>
    #35007

    prime
    Keymaster

    I’m a little confused about what problem you are solving. You would like the AI to compute a path to the target, then query the AI to determine which direction it intends to go before it starts moving (i.e., will it go left or right)?

    You will have to remind me - is the AI following a Waypoint Network or is it just pathfinding along a navmesh?

    #35014

    Velathora
    Participant

    Basically, it chooses Navigation Targets that are located on the NavMesh.

    But yes, you are correct in the AI heading towards target and then I wish to query the path that it has plotted (hopefully).

    #35015

    Velathora
    Participant

    Figured I’d do a quick update.

    I was reading through the API like crazy to figure out different ways to go about selecting the correct route.

    I came across aiRig.AI.Navigator.CurrentPath.Points[index] which I can find by GetNextWaypointIndex(myPosition, 0f,0) <Not Sure if this is the correct way to do this>.

    By doing this, I can at least find out where the AI is going to next within world space.

    So the logic is as follows:

    • AI Walks up to light post, checks where it is attempting to travel
    • AI finds distance between the two possible options at the post (crosswalk on left or crosswalk on right)
    • AI determines that crosswalk (left or right) is the one that will be traveled
    • AI checks if the light will allow this
    • If light allows travel in that direction, do so
    • Otherwise, wait until light allows travel

    Still not certain how to get the distance between two nodes and selecting them within the aiRig obj.

    • This reply was modified 1 month, 2 weeks ago by  Velathora.
    #35018

    Velathora
    Participant

    Update:

    I just want to make note as to how this was solved.

    I was able to get the next point as stated within the aiRig.AI.Navigator.CurrentPath.Points[index] and getting ‘index’ by using GetNextWaypointIndex(aCurrentPosition, aMinForwardDistance, aLastWaypointIndex).

    Using this, I could calculate difference of the two Vector3 (currPosition, nextPoint)

    Afterward, I simply had to calculate which way I wished to go through the lights, and check their color.

    Thanks for community support regardless, even though I ended up figuring it out.

    Note:

    The RAIN system is fantastic, I have run into a few issues in using it, but all of which were easily solvable with Unity if I couldn’t figure out the entirety of RAIN.
    Thanks again.

    #35021

    prime
    Keymaster

    Nice job figuring that out. We do something very similar in our Squad Command package - a path is calculated from soldiers taking cover behind buildings to various hotspots in the scene. We then use the path to determine which direction the soldier should face while taking cover.

    One more thing to consider - although the path is smoothed, it is still possible that the first few steps in the path don’t lead in the direction of the final target. You might want to analyze the points for some distance along the path (maybe the distance traveled in a couple of seconds) to make sure the next waypoint isn’t a small detour or outlier.

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

You must be logged in to reply to this topic.