“I am currently using the A* plugin in Unity, but I have encountered a problem. I use distance to represent the attack range of the main character. However, for ranged attacks, although the character can stop at the appropriate attack distance, it doesn’t seem right if there are obstacles in between.”
Are you trying to have ranged attacks “stop” on obstacles, so that the range doesn’t continue past physical objects? If that’s the case, I don’t think Astar is a solution, but rather just a standard Physics.Raycast2D would help there.
Please let me know if I’m misunderstanding your question, would love to help how I can
No, I’m looking for a path where the remote attack won’t be stopped
I think that @tealtxgr is trying to say is that if you make the agent move towards the target, you can just make it continue moving until it has line of sight:
void Update () {
ai.isStopped = ai.remainingDistance < threshold && !Physics.Linecast(ai.position, ai.destination, ...);
}
If you’re looking to make projectiles “pathfind” to a target, Astar can be used for that. If you haven’t already checked out the Get Started Guide, I’d recommend starting there. If you’re still having troubles implementing Astar into your projectiles, we’d be glad to help
Thank you very much. After thinking it over carefully, I realize your method seems correct. However, what if I want to implement a path prediction feature? For example, during my turn, when I hover the mouse over an enemy, there should be a predicted path shown to the player. But it seems that using ai.remainingDistance
won’t work for real-time calculations, so I’m not able to predict where the path will end.
My idea is to use another object to simulate the path quickly and then display the predicted path. Do you have a better suggestion? I’d appreciate your advice!!!
Yeah, I think having a child Game Object, and having them create a path to the destination, then drawing that path with a method of your choosing is how I’d go about that. Don’t quote me on this one, but I’m also pretty sure you wouldn’t even need a new game object or anything- you could just create a new path during runtime, completely separate from your unit’s current path, if it has one.
I’ll actually go ahead and give this a test now and see what I can discover.
@hhyu Yeah I was right, you could generate a path and have it drawn in just a few lines of code:
Here’s a simple bit of code of what I did and why:
// Create and construct a new path. You can use other path types besides an ABPath
ABPath predictedPath = ABPath.Construct(transform.position, target.transform.position);
// Populate the path to the destination, and when it's finished, call SetLineRenderer()
GetComponent<Seeker>().StartPath(predictedPath, SetLineRenderer);
// Give the line renderer the points (and number of points) from the found path
// I used thisPath.vectorPath because then I could use modifiers like smoothing. That's completely preference though.
void SetLineRenderer(Path thisPath){
LineRenderer lineRenderer = GetComponent<LineRenderer>();
lineRenderer.positionCount = thisPath.vectorPath.Count;
lineRenderer.SetPositions(thisPath.vectorPath.ToArray());
}
Thank you very much for your answer. I have finished this aspect. Now I have a question about how to add the operation in update mentioned by aron_granberg, because it is more like real-time operation, which needs to control the object to move forward.
because it is more like real-time operation, which needs to control the object to move forward.
Hm, I’m a little lost at this part, do you mind breaking it down?
void Update () {
ai.isStopped = ai.remainingDistance < threshold && !Physics.Linecast(ai.position, ai.destination, …);
}
This needs to be inside the Update
method because we need to constantly check if ai.remainingDistance
is less than threshold
and if there is a clear line of sight to the enemy using Physics.Linecast
. This is necessary to dynamically pause the AI’s movement. It seems that we can’t calculate the endpoint first and then stop; we need to perform these checks in real-time.
It’s easiest to do this frame-by-frame.
You could use the PathInterpolator
class (or custom code) to sample a bunch of points on the path and do the same check. Then for the first valid point, you set that as the destination instead.
Something like this:
// Create and construct a new path. You can use other path types besides an ABPath
ABPath predictedPath = ABPath.Construct(transform.position, target.transform.position);
// Populate the path to the destination, and when it's finished, call SetLineRenderer()
AstarPath.StartPath(predictedPath);
predictedPath.BlockUntilCalculated();
seeker.PostProcess(predictedPath);
var interpolator = new Pathfinding.Util.PathInterpolator();
interpolator.SetPath(path.vectorPath);
var cursor = interpolator.start;
cursor.remainingDistance = attack range;
while(cursor.remainingDistance > 0) {
if (!Physics.Linecast(cursor.position, target.transform.position)) {
return cursor.position;
}
// Move slightly closer and try again
cursor.remainingDistance -= 0.2f;
}