Unity导航网格:在圆上找到最近位置

6
想象一下,一个弓箭手需要距离目标至少3米才能射击,但他不能超过10米。因此,他必须在这个半径内找到一个有效的位置(当然是在3D中)。
所以,我需要一个方法,返回最近(可达)的点在我的导航网格上,具有明确的视线,并且在半径内。

enter image description here

我在考虑始终将圆边作为计算的起点。因为这应该是最接近的点。但在这个例子中不起作用:

enter image description here

由于在圆的边缘没有直接的视线,我不能把它作为起点。

我也考虑过随机选择点(比如5000个),检查它们是否有视线,并检查与弓箭手的距离。但这当然是一个可怕的解决方案。

我如何找到这个神奇的点呢?

(我不需要一个脚本,只需要一个想法:D)

编辑: 不需要到达目标点的有效路径。例如,如果河流挡路,弓箭手就无法找到通往目标的路径。但他仍然可以射过河流。这意味着他可以找到一个有效的位置。 enter image description here


这种算法的用例是什么?你想在这个位置生成敌人吗?每帧需要多少个位置?这是一个2D平面还是有高度差,例如楼层、山丘等? - Not a privileged user
有趣的问题。在这种情况下,你想去哪里?https://i.postimg.cc/7hTL2qyN/Archer-Another-Case.png - yevt
@Notaprivilegeduser 这是一个普通的Unity导航网格->带高度的3D空间。将会有大约5-10个敌人,每个敌人都有几个不同的目标。 - GoldenDremora
@FakeFish,应该选择较短的路径(长度A与长度B进行比较),选择较短的路径。在这个例子中应该选择A。 - GoldenDremora
@GoldenDremora https://docs.unity3d.com/Manual/nav-AreasAndCosts.html#Area%20Types 这可能会解决与河流相关的问题。这是真的吗? - yevt
5个回答

1

NavMesh.SamplePosition函数会在半径范围内返回最靠近导航网格的点(即您的最小攻击距离)。

  1. 获取到目标最接近点的路径(如果可达,则为目标本身)

(1b. 如果无法实现,您可以在目标周围的圆形区域中采样n个最接近的点)

  1. 沿着该路径(攻击范围内):每步进行射线检测以检查可见性

0

将玩家的导航网格目标设置为球体中心。

每帧执行以下操作:
从球体中心向玩家当前位置进行Raycast。如果直接命中玩家且两者之间没有任何障碍物,则表示玩家已到达最近的具有清晰目标的位置。


这样做是行不通的,因为可能存在障碍物,但视线仍然保持完好。例如,弓箭手站在悬崖边缘,他的目标在悬崖的另一侧。他甚至无法找到路径到达目标,但由于他可以从这个位置射击,所以这是一个有效的位置。 - GoldenDremora
我没有完全理解,你能否添加一个大致的图像示例? - Geeky Quentin
我已经编辑了我的帖子。现在有一张新图片。 - GoldenDremora
好的,我明白我哪里出了问题。 - Geeky Quentin

0

你可以在蒙特卡罗方法中使用你的“可怕解决方案”:

  • 每一帧(如果当前位置无法射击目标):
    1. 仅对目标周围的10个随机点进行采样(而不是5000个)
    2. 从每个点向目标发射一条射线
    3. 对于所有被击中的点:从弓箭手到它们执行路径规划
    4. 如果一个点比“上一帧的目标点”更近,将该点作为“上一帧的目标点”,并导航到那里

这可能会引入抖动,但在几帧后应该会产生可接受的结果。

为了改进这一点,您可以使用启发式方法来偏向采样随机点。例如,“首先检查指向弓箭手的四分之一圆形区域”。


0
  1. 在与原始目标相同的位置创建一个幽灵目标。假设我们的幽灵对于人类玩家是不可见的,并且可以无限快地移动。幽灵可以做到这一点!
  2. 由于幽灵可以飞行,因此请让您的幽灵飞向您的弓箭手。河流不应该是问题。为了区分不同类型的障碍物(墙壁、水),区域成本应该有所帮助。
  3. 通过导航和路径规划 AI建立一个路径(应该在幽灵开始移动后立即访问)
  4. 将路径分成线性段。
  5. 在幽灵和目标可以看到彼此,并且它们之间的距离小于射程的情况下,开始沿着路径将幽灵向弓箭手移动(逐点)。
  6. 一旦(6)中的任何条件不成立,您已经知道开火点所在的线性段。前一个点可能已经是一个不错的开火点,但是想象一下根本没有障碍物的情况。在这种情况下,我们的路径是一个直线段,其起点与目标位置重合。显然,我们需要更精确。顺便说一句,让我们称这个线性段为开火线性段
  7. 最后,要在开火线性段中找到开火点,我们可以使用二分法容差ε=一个弓箭手的步长。对于每个二分点,我们应该继续检查我们在(5)中所做的相同事情。

0

虽然我不熟悉导航网格,但我会尝试以下方法:

  1. 获取平面 P:

enter image description here

简单来说,只需获取正常方向和一个点。

  1. 将所有点移动到所关注平面的一侧。在这种情况下,观察敌机的方法 GetSide 。这只是一个点积,所以很省钱。

  2. 然后,可以通过一些光线投射筛选出由于障碍物而没有有效目标射击的点。

  3. 从中选择最靠近敌人(AI)位置的点,取最小值 Vector3.sqrMagnitude。这是距离的最小平方长度,它比距离本身更便宜,因为平方根不太高效,因此当需要使用最大或最短距离时,使用sqrMagnitude是很好的做法。 如果您已经知道到该点的路径距离,则应该选择直接距离,而不是最短的路径距离:)

  4. 如果找不到满足此要求的点,则需要检查网格的其余点。


你打算如何获取所有的点?像在一个数组中吗? - Geeky Quentin
不熟悉导航网格。放弃这个想法吧。使用数组会是最好的选择。 - rustyBucketBay
你有没有关于这个数组的长度的任何想法?我认为如果区域太大,这种方法不起作用。 - Geeky Quentin

网页内容由stack overflow 提供, 点击上面的
可以查看英文原文,
原文链接