A-Star Pathfinding插件学习记录(二)

A* Pathfinding插件学习记录(一) 文章,本文对笔者在项目中重点使用到的做个详细的分享,也欢迎大家交流指正。(别只做个伸手党,我写博客一是为了做个记录,其二还是希望可以得到反馈,相辅相成,共同成长。)

一. AstarPathGraphNode

描述:AstarPathA*寻路系统的核心组件。计算所有路径并存储信息。

重要接口介绍:

AstarPath.active获取实例

AstarPath.active.isScanning:是否有任意一个图形正在扫描

AstarPath.active.data.AddGraph//创建新的Graph

AstarPath.active.AddWorkItem:添加要在路径查找暂停时处理的工作项。这里安全的更新图。

AstarPath.active.GetNearest(transform.position)//获取图中临近的GraphNode节点.

AstarPath.active.data.pointGraph.AddNode((Int3)StartTransform.position)//在graph中添加一个节点

 

node.Walkable = false;//将节点设置不可走的。比如设置jump跳上平台的几率就可以扩展GraphModify中随机EndWalkable的概率。

GraphNode startNode=…; startNode.RemoveConnection(endNode);//移除startNodeEndNode的连接。

startNode.AddConnection(endNode, cost);//设置StartEnd的连接

//node.ClearConnections(true);清理所有link链接。true表示双向都清理

startNode.SetPosition//设置节点坐标

 

 

二. MovementScript

描述:AIPath和AILerp可以用于任何Graph,RichAI只适用于以NavMesh为基础类型的 Graph。

AIPath 和 RichAI 脚本松散地遵循路径, AILerp 脚本使用插值非常精确地沿路径移动。

1.1 AIPath

  • 平滑地遵循路径并响应物理。
  • 支持ROV
  • 支持3d2d
  • 使用所有graph

1.2 RichAI

  • RichAI只适用于以NavMesh为基础类型的 Graph。其他都不支持,包括PointGraph
  • RichAi比AIPath在Navmesh类型的Graph上更好的追随路径。通常更加平稳的遵循路径以及物理。即使没有碰撞体,它也能很好的约束在网格内不发生穿墙,太棒了
  • 而且RichAiAIPath更好的支持NodeLink也称OffsetMeshLinkRichAi在遵循路径时可以检测到链接,知道啥时候进入了Link。处理在Link过程的逻辑。因为它提供了onTraverseOffMeshLink事件,它当Agent开始遍历某个Link时调用,如果onTraverseOffMeshLink==null,那么默认agent将使用线性插值的方式移动到Link上的点。可以参考AnimationLinkTraverser脚本。
    void OnEnable () {
        ai = GetComponent<RichAI>();
        if (ai != null) ai.onTraverseOffMeshLink += TraverseOffMeshLink;
    }
    
    void OnDisable () {
        if (ai != null) ai.onTraverseOffMeshLink -= TraverseOffMeshLink;
    }
    
    IEnumerator TraverseOffMeshLink (RichSpecial link) {
        // Traverse the link over 1 second
        float startTime = Time.time;
    
        while (Time.time < startTime + 1) {
            transform.position = Vector3.Lerp(link.first.position, link.second.position, Time.time - startTime);
            yield return null;
        }
        transform.position = link.second.position;
    }
    

Link

link默认有三种类型,分别是NodeLinkNodeLink2NodeLink3.

NodeLink

NodeLink在遵循路径时,agent不可能检测到该链接,所以它并不支持于RichAI。如果需要检测链接,推荐使用NodeLink2

NodeLink2

这种链接类型可以在跟踪时检测到,因为它在中间有这些特殊的点节点。这两个点是pointGraphpointNode。虽然RichAI不支持PointGraph导航,不过它内部应该是检测nodelinkPointNode来检测是否进入连接。

NodeLink3:

连接两个TriangleMeshNodes,使共享一条边。通常不会使用

Seeker

Seeker.StartPath很傻蛋。有时候不会计算off-MeshLink。同样的逻辑 将startPath替换为destination寻路完美解决。真搞不懂seeker的设计是何用。后处理+seeker更是与AStarPath严重割裂。
路径终点如果是在Link的start上,reachedEndOfPath不会为true。主要是approachingPathEndpoint这个属性不会更新为true。很离谱!

想要停止Agent怎么办?

1. 使用seek.isStoped。不过在下次使用要恢复seek.isStoped=false
显然这种做法很笨很傻。
2. 那使用seek.StartPath(aipath.position) 将寻路目标设置当前路径。
好像没啥问题,不过发现还是会出问题,有时候不会停止,而是缓慢向前挪动。
3. 最好的解决方案就是将MovementScript 禁用再立即开启。其中让其重置了一下?

Path

FakePath

根据描述 这是一个假路径,就是说它不是有真实地图上扫描出来的点组成的。是一个我们人为设定的点,类似与PointGraph。不同的是不能使用Seeker它生成的路径,一般用作路径计算,而不是驱动Agent移动。如果实在要驱动移动,也只能使用AIPath这类移动脚本,通过以下代码驱动,RichAI不支持直接使用 FakePath。

var path = ABPath.FakePath(new List<Vector3> { new Vector3(1, 2, 3), new Vector3(4, 5, 6) });

ai.SetPath(path);
FakePath也可和真实路径点进行合并,得到一个新的路径,示例:
var a = Vector3.zero;
var b = new Vector3(1, 2, 3);
var c = new Vector3(2, 3, 4);
var path1 = ABPath.Construct(a, b);
var path2 = ABPath.Construct(b, c);

AstarPath.StartPath(path1);
AstarPath.StartPath(path2);
path1.BlockUntilCalculated();
path2.BlockUntilCalculated();

// Combine the paths
// Note: Skip the first element in the second path as that will likely be the last element in the first path
var newVectorPath = path1.vectorPath.Concat(path2.vectorPath.Skip(1)).ToList();
var newNodePath = path1.path.Concat(path2.path.Skip(1)).ToList();
var combinedPath = ABPath.FakePath(newVectorPath, newNodePath);

如何获取路径的长度:

在NavMeshAgent中可以直接像系统申请计算CalcuatePath,得到Path信息。
AStarPathFinder使用Construct同样也可以,但是要保证能够符合agent移动轨迹需要向路径Apply modified修改器。(不过即使这样,貌似没法输入agent的radius、height等信息去计算路径。而且在应用时,在某些时候会报错,暂不清楚什么原因)。
要完美做到计算的路径是当前agent的路径轨迹,只能通过seeker来计算。不过seeker的StartPath我们知道会在计算后的下一帧执行移动,这个很操蛋。而且我们还得考虑在计算路径的时候,之前是否在执行计算路径或在移动,确保我们在主线程计算完路径长度后要能够恢复原先状态。

示例代码:

Path pathA = seeker.GetCurrentPath();
Path pathB = seeker.StartPath(seeker.transform.position,target);
pathB.BlockUntilCalculated();
dis += pathB.GetTotalLength();
 if (pathA!=null&&pathA.vectorPath!=null&&pathA.vectorPath.Count>0){
 seeker.StartPath(seeker.transform.position,pathA.vectorPath.Last<Vector3>()); }

 

 

 

作者:Miracle
来源:麦瑞克博客
链接:https://www.playcreator.cn/archives/unity/unity_technologyshare/3714/
本博客所有文章除特别声明外,均采用CC BY-NC-SA 4.0许可协议,转载请注明!
THE END
分享
打赏
海报
A-Star Pathfinding插件学习记录(二)
继A* Pathfinding插件学习记录(一) 文章,本文对笔者在项目中重点使用到的做个详细的分享,也欢迎大家交流指正。(别只做个伸手党,我写博客一是为了做个记录……
<<上一篇
下一篇>>
文章目录
关闭
目 录