Using MultiTargetPath with RichPath

I am modifying the richAI to change the path type to multitarget path but it seem to not be able to go to the shortest path even though all the paths are listed in mp.VectorPaths

Here is my code

`public void OnPathComplete (Path p) {

		MultiTargetPath mp = p as MultiTargetPath;

		for (int i=0; i<mp.vectorPaths.Length; i++) {
			if (mp.vectorPaths [i] == null)
					continue;

			Debug.Log ("path " +  i + ": " + mp.vectorPaths);
			List<Vector3> vpath = mp.vectorPaths [i];
		}

		waitingForPathCalc = false;
		mp.Claim(this);

		if(lastRender == null) return;
		
		if (mp.error) {
			mp.Release(this);
			return;
		}

		if (traversingSpecialPath) {
			delayUpdatePath = true;
		} else {
			if (rp == null) rp = new RichPath();
			rp.Initialize (mySeeker, mp,true, funnelSimplification);
		}
		mp.Release(this);
	}

	public bool TraversingSpecial {
		get {
			return traversingSpecialPath;
		}
	}`

is the initialization of my RichPath done correctly?

rp.Initialize (mySeeker, mp,true, funnelSimplification);

1 Like

Hi

That was a bug.
You fix it quickly by setting A* Inspector -> Settings -> Path Log Mode to “Normal” or “None”.

I tried mySeeker.StartMultiTargetPath (start.position, multitargetpoints.ToArray (), false); but I am getting the error:

NullReferenceException: Object reference not set to an instance of an object
Pathfinding.MultiTargetPath.DebugString (PathLog logMode)

Unhandled exception during pathfinding. Terminating.
UnityEngine.Debug:LogError(Object)

Canceled path because a new one was requested

That might be a bug. Try turning off multithreading and checking if you can get the whole stacktrace (including line numbers).

The thread count is set to NONE so I am assuming multithreading is not turned on.

The whole stacktrace would be

NullReferenceException: Object reference not set to an instance of an object
Pathfinding.MultiTargetPath.DebugString (PathLog logMode) (at Assets/AstarPathfindingProject/Pathfinders/MultiTargetPath.cs:651)
AstarPath.LogPathResults (Pathfinding.Path p) (at Assets/AstarPathfindingProject/Core/AstarPath.cs:629)
AstarPath+c__Iterator9.MoveNext () (at Assets/AstarPathfindingProject/Core/AstarPath.cs:2629)
AstarPath.Update () (at Assets/AstarPathfindingProject/Core/AstarPath.cs:676)
UnityEngine.Debug:LogException(Exception)
AstarPath:Update() (at Assets/AstarPathfindingProject/Core/AstarPath.cs:685)

Unhandled exception during pathfinding. Terminating.
UnityEngine.Debug:LogError(Object)
AstarPath:Update() (at Assets/AstarPathfindingProject/Core/AstarPath.cs:686)

Canceled path because a new one was requested
UnityEngine.Debug:LogError(Object)
Pathfinding.Path:ForceLogError(String) (at Assets/AstarPathfindingProject/Core/Path.cs:369)
Seeker:StartMultiTargetPath(MultiTargetPath, OnPathDelegate, Int32) (at Assets/AstarPathfindingProject/Core/AI/Seeker.cs:535)
Seeker:StartMultiTargetPath(Vector3, Vector3[], Boolean, OnPathDelegate, Int32) (at Assets/AstarPathfindingProject/Core/AI/Seeker.cs:500)
RichAI:UpdatePath() (at Assets/RichAI.cs:137)
Pathfinding.TargetMover:UpdateTargetPosition() (at Assets/TargetMover.cs:83)
Pathfinding.TargetMover:OnGUI() (at Assets/TargetMover.cs:38)

Wherein line 137: mySeeker.StartMultiTargetPath (start.position, multitargetpoints.ToArray (), false);

My TargetMover goes something like this where it just adds a new position to the list

`public List<Vector3> multipoints = new List<Vector3>();
RichAI[] ais;

public void Start () {
			//Cache the Main Camera
			cam = Camera.main;
			ais = FindObjectsOfType(typeof(RichAI)) as RichAI[];
}

public void OnGUI () {
			
			if (onlyOnDoubleClick && cam != null && Event.current.type == EventType.MouseDown && Event.current.clickCount == 2) {
				UpdateTargetPosition ();
			}
}

void Update () {

			Ray ray = Camera.main.ScreenPointToRay (Input.mousePosition);
			
			Vector3 zeroIntersect = ray.origin + ray.direction * (ray.origin.y / -ray.direction.y);
			target.position = zeroIntersect;
			
			if (Input.GetMouseButtonUp(0)) {
					
					if (Input.GetKey (KeyCode.LeftShift)) {
						
						multipoints.Add (zeroIntersect);
						
					}
					
					if (Input.GetKey (KeyCode.LeftControl)) {
						multipoints.Clear ();
					}

				}

			if (!onlyOnDoubleClick && cam != null) {
				UpdateTargetPosition ();
			}
			
}

public void UpdateTargetPosition () {
			//Fire a ray through the scene at the mouse position and place the target where it hits
			RaycastHit hit;
			if (Physics.Raycast	(cam.ScreenPointToRay (Input.mousePosition), out hit, Mathf.Infinity, mask) && hit.point != target.position) {
				target.position = hit.point;
				if (ais != null && onlyOnDoubleClick) {
					for (int i=0;i<ais.Length;i++) {
						if (ais[i] != null) ais[i].UpdatePath();
					}
				}
			}
}`

I actually did something like that but the ai just chooses the last path I add. What am I doing wrong. Should I devlare a multitargetpath construct?

`public virtual void UpdatePath () {
		Debug.Log ("Update Path");
		canSearchPath = true;
		waitingForPathCalc = false;

		multitargetpoints = targetPoints.multipoints;

		MultiTargetPath mp = MultiTargetPath.Construct (start.position, multitargetpoints.ToArray (), null, OnPathComplete);

		Path p = mySeeker.GetCurrentPath();

		//Cancel any eventual pending pathfinding request
		if (mp != null && !mySeeker.IsDone()) {
			mp.Error();
			// Make sure it is recycled. We won't receive a callback for this one since we
			// replace the path directly after this
			mp.Claim (this);
			mp.Release (this);
		}
		
		waitingForPathCalc = true;
		lastRepath = Time.time;

		mySeeker.StartMultiTargetPath (mp);

	}`

Anyone know how to do this or think its possible?

Hi

How do you want to use it?
Do you want to get to the closest target of multiple possible?
If so, you should only have to switch out a single line in RichAI.UpdatePath

`
public virtual void UpdatePath () {
canSearchPath = true;
waitingForPathCalc = false;
Path p = seeker.GetCurrentPath();

//Cancel any eventual pending pathfinding request
if (p != null && !seeker.IsDone()) {
	p.Error();
	// Make sure it is recycled. We won't receive a callback for this one since we
	// replace the path directly after this
	p.Claim (this);
	p.Release (this);
}

waitingForPathCalc = true;
lastRepath = Time.time;

// THIS LINE
//seeker.StartPath (tr.position, target.position);
seeker.StartMultiTargetPath (...);

}`

1 Like