6

Imagine that an archer needs to be at least 3m away to be able to shoot his target, but he cannot be further away than 10m. So he must find a valid location inside this radius (in 3d of course).

So, what I need is a method that returns me the nearest (reachable) point on my nav mesh with a clear line of sight that is inside the radius.

enter image description here

I was thinking about always using the cirlce edge as an starting point for my calculations. Since this should always be the closest point. But this does not work in this example:

enter image description here

Since there is no direct line of sight at the cirle edge I cannot take it as an starting point.

I was also thinking about just picking random points (like 5000), checking if they have line of sight and checking the distance to the archer. But this is of course a horrible solution.

How can I find this magical point?

(I don't need a script but an idea :D)

Edit: It is not required to have a valid path to the target. If e.g. a river is in the way the archer wont be able to pathfind to his target. But he can still shoot over the river. Meaning he can find a valid spot. enter image description here

  • What's the use case of such algorithm ? You want to spawn enemies at this position ? How many positions would you need per frame ? Is this a 2D plane or there's elevations such floors, hills ? – Not a privileged user Jul 11 '22 at 21:44
  • Interesting question. Where you wanna go in this case? https://i.postimg.cc/7hTL2qyN/Archer-Another-Case.png – yevt Jul 16 '22 at 02:08
  • @Notaprivilegeduser this is a normal unity nav mesh -> 3D space with elevation. There are gonna be about 5-10 Enemies with a few different targets. – GoldenDremora Jul 17 '22 at 15:51
  • @FakeFish it should take the shorter route. (lengthA vs lengthB) the shorter path will be selected. It should be A in this example – GoldenDremora Jul 17 '22 at 15:53
  • @GoldenDremora https://docs.unity3d.com/Manual/nav-AreasAndCosts.html#Area%20Types this should probably resolve river-related aspect of the problem. Is it true? – yevt Jul 18 '22 at 02:03

5 Answers5

1

NavMesh.SamplePosition will return you the closes point on the navmesh with in a radius (your minimal attack distance).

  1. Get path to the closest point to the target (if reachable is the target itself)

(1b. If that doesn't work you could always sample n closest points in a circle around the target)

  1. Along this path (within the attack range): Raycast every step to check visibility
Weezah
  • 44
  • 3
0

Set the destination of the player's navmesh to the center of the sphere.

The following actions are performed every frame:
Raycast from the center of the sphere to the current position of the player. If it directly hits the player without any obstacle between them, the player has reached the nearest position with a clear target.

Geeky Quentin
  • 2,469
  • 2
  • 7
  • 28
0

Not familiar with navmesh but I what I would try:

  1. Get the Plane P:

enter image description here

Easy as you got the normal direction and a point.

  1. Get all the points to the side of the plane of interest. Lookint at the enemy in this case plane's method GetSide. Thats just a dot product, so cannot be cheaper.

  2. Then you can filter out the points that do not have a valid target shoot due to an obstacle with some raycasts.

  3. From those, finally choose the one that is closest to the enemy (AI) position, taking the min Vector3.sqrMagnitude. This is the lowest squared length of the distance, its much cheaper that the distance itself because square roots are not efficient, so when need biggest or shortest distance to use the sqrMagnitude is good practice. Instead of the straight distance, of you have the path distance to the point, that would be the one to look for :)

  4. Guess that if no point is found that meets this requirements the you'd need to check the rest of the points of the mesh.

rustyBucketBay
  • 4,320
  • 3
  • 17
  • 47
0

You could maybe use your "horrible solution" in an Monte-Carlo approach:

  • every frame (if target cannot be shot from the current position):
    1. sample just e.g. 10 random points around the target (instead of 5000)
    2. cast a ray from each point to the target
    3. for all points that did hit: perform pathfinding from the archer to them
    4. if one point is a nearer than the "target point last frame" make this point the "target point last frame" and navigate there

This may introduce a jitter but should yield an acceptable result after just a few frames.

To improve this, you could use a heuristic to bias sampling the random points. Like "first check in quarter of circle pointing towards archer".

Ni2Be
  • 111
  • 7
0
  1. Create a ghost target at the same place as your original target. Let's suppose, our ghost is invisible for human player and can move infinitely fast. Ghosts can do that!
  2. As ghosts can fly, ask your ghost to fly towards your archer. A river shouldn't be a problem. To distinguish different types of obstacles (walls, water) area costs should be helpful
  3. Get a path built by navigation and pathfinding AI (should be accessible immediately after the start of the ghost's movement)
  4. Split the path into linear segments.
  5. Start moving the ghost across the path towards the archer (point by point), while the ghost and the target can see each other, and the distance between them is less than firing range.
  6. As soon as any of the conditions from (6) is false, you already know the segment, the fire point is on. Well, previous point could be a decent fire point already, but imagine that there are no obstacles at all. In this case our path is a straight line segment which beginning coincides with the target position. Obviously we need to be more precise. By the way, let's call the segment - fire segment
  7. Finally to find the fire point within the fire segment we could use bisection with tolerance ε = one_archer's_step. We should keep checking the same things we did in (5) for each bisectional point
yevt
  • 732
  • 1
  • 6
  • 21