Support Forum

Finding a Suitable Destination Node

Hi again! Further along with my turn-based system now, I’m having some trouble with figuring out an algorithm for the opponent AI to find a node to attack the player from. Each attack has a specific integer range that it’s able to reach. The criteria I need for a suitable node are:

  • Node must be able to create an unobstructed raycast from itself to any of the nodes the player is on (typically more than one, as explained in my previous thread)
  • The raycast’s length must be less than or equal to the specified attack’s range
  • The path distance from the opponent to the node must be as small as possible

What’s the best way of going about this? Trying to wrap my head around it is rather headache-inducing. Thanks again!

Hey,

The exact requirements are definitely out of the scope of this project. However you might find some of the wander examples interesting as a starting point. You can read about them here https://arongranberg.com/astar/docs/wander.php

What also could be interesting to you is the TurnBasedAI example, can be found as one of the example scenes included with the project.

Hope that gets you on the right path!

1 Like

Hi

You can use the XPath class. It works like a normal path, but it has a few extra options. Among other things it has a PathEndingCondition which can be used to tell the path which nodes are valid end points of the path. We can do a linecast inside that check to get the correct result.

class RaycastEndingCondition : PathEndingCondition {
	// You may want to change this to an array
	public Vector3 raycastTarget;
	public float maxRange;

	public override bool TargetFound (PathNode node) {
		Vector3 nodePos = (Vector3)node.node.position;
		// Check range
		if (Vector3.Distance(nodePos, raycastTarget) < maxRange) {
			// Check line of sight
			if (!Physics.Raycast(nodePos, raycastTarget)) {
				return true;
			}
		}
		return false;
	}
}
public void SearchPath() {
	// If you have your own movement script
	// Try to reach the targetPosition, but stop once the ending condition is fulfilled
	var path = XPath.Construct(myPosition, targetPosition);
	path.endingCondition = new RaycastEndingCondition {
		raycastTarget = targetPosition,
		maxRange = myPosition,
	};
	var seeker = GetComponent<Seeker>();
	seeker.StartPath(path, SomeCallbackHere);

	// -----------------

	// Or, if you are using one of the built-in movement scripts
	var path = XPath.Construct(myPosition, targetPosition);
	path.endingCondition = new RaycastEndingCondition {
		raycastTarget = targetPosition,
		maxRange = myPosition,
	};
	var ai = GetComponent<IAstarAI>();
	// Disable the built-in path recalculation
	ai.canSearch = false;
	ai.SetPath(path);
}

See also https://arongranberg.com/astar/docs/callingpathfinding.html
and https://arongranberg.com/astar/docs/xpath.html

Hi Aron,
I was so happy that after two weeks I found the solution for melee/range distance but the code you put here seems not to be working. I get an error below:

Preformatted text

UnityException: get_defaultPhysicsScene can only be called from the main thread.
Constructors and field initializers will be executed from the loading thread when loading a scene.
Don't use this function in the constructor or field initializers, instead move initialization code to the Awake or Start function.
UnityEngine.Physics.get_defaultPhysicsScene () (at <7d971898ea0f4307a8eddf491ea76525>:0)
UnityEngine.Physics.Raycast (UnityEngine.Vector3 origin, UnityEngine.Vector3 direction) (at <7d971898ea0f4307a8eddf491ea76525>:0)
Core.TurnBasedPathfinding+RaycastEndingCondition.TargetFound (Pathfinding.PathNode node) (at Assets/Scripts/Core/Location/PathfindingExtentions.cs:50)
Pathfinding.XPath.CalculateStep (System.Int64 targetTick) (at Assets/AstarPathfindingProject/Pathfinders/XPath.cs:84)
Pathfinding.Path.Pathfinding.IPathInternals.CalculateStep (System.Int64 targetTick) (at Assets/AstarPathfindingProject/Core/Path.cs:835)
Pathfinding.PathProcessor.CalculatePathsThreaded (Pathfinding.PathHandler pathHandler) (at Assets/AstarPathfindingProject/Core/Misc/PathProcessor.cs:350)
UnityEngine.Debug:LogException(Exception)
Pathfinding.PathProcessor:CalculatePathsThreaded(PathHandler) (at Assets/AstarPathfindingProject/Core/Misc/PathProcessor.cs:407)
Pathfinding.<>c__DisplayClass24_0:<.ctor>b__0() (at Assets/AstarPathfindingProject/Core/Misc/PathProcessor.cs:110)
System.Threading.ThreadHelper:ThreadStart()

Could you please help with it?

Hi

If you use Physics.Raycast inside a PathEndingCondition it will be run as part of pathfinding. However, raycasts can only be done from the main thread in unity, so pathfinding will also have to be restricted to the main thread. You can do this by setting A* Inspector -> Settings -> Threads to None.

Thank you, I will see to it. However I have found out it might be better to use EndingConditionPriximity for my case (for everyone who strugles as I did - Path into range of target - Support Forum (arongranberg.com))