☰
Unity A* Pathfinding Pro插件:从算法原理到工程实践,构建高效寻路系统
2026/10/11 19:19:27 网站建设 项目流程

1. 项目概述:从算法到工程,为什么我们需要一个专业的寻路插件?

在游戏开发里,让角色“聪明地”从一个点移动到另一个点,是AI行为最基础也最核心的一环。无论是开放世界里NPC的闲逛,塔防游戏中敌人的进攻路线,还是RTS里上百个单位的大规模调度,背后都离不开一套稳定、高效、灵活的寻路系统。Unity引擎自带的NavMesh系统,对于简单的、静态的场景来说,开箱即用,确实方便。但一旦你的游戏世界变得复杂起来——地形高低起伏、障碍物动态出现消失、需要支持2D和3D混合、或者有成百上千个单位需要同时计算路径——内置方案就会立刻显得捉襟见肘。

这时候,A* Pathfinding Project Pro(下文简称APP)就登场了。它不是一个简单的A算法实现,而是一个完整的、工程级的寻路解决方案。我用了它快十年,从独立小游戏到大型商业项目,它几乎是我Unity工具箱里的“标配”。它的核心价值在于,把经典的A*算法从一个学术概念,封装成了一个能应对真实游戏开发中各种刁钻需求的强大工具链。你不用再从零开始写寻路算法、处理线程安全、设计动态更新逻辑,而是可以直接站在巨人的肩膀上,专注于游戏玩法本身。

简单来说,如果你想让游戏里的角色移动得更“智能”、更“自然”,同时又不希望寻路系统成为性能瓶颈或者开发噩梦,那么深入理解并使用APP,是一个性价比极高的选择。这篇文章,我会结合我踩过的无数个坑和总结的经验,带你从A算法的基本原理出发,一步步拆解A*PP这个庞然大物,直到你能在项目中游刃有余地实现一个健壮的寻路系统。

2. 核心寻路理论:不只是A*,更是工程化的基石

在直接上手插件之前,我们必须先打好地基。A*PP的强大,源于它对经典寻路理论的深刻理解和工程化扩展。理解这些,你才能明白插件里每个参数、每个选项背后的“为什么”,而不是盲目地复制粘贴配置。

2.1 A*算法再探:启发式搜索的艺术

很多人知道A*算法是“最优路径”算法,但它的精髓在于“启发式”。你可以把它想象成一个有经验的登山向导。他从起点(A点)出发,目标是山顶(B点)。他不会像无头苍蝇一样乱撞(盲目搜索),也不会只盯着直线距离(贪心算法)。他会做两件事:

  1. 计算实际成本(G值):记录从起点走到当前位置已经花了多少力气(距离、时间等)。
  2. 估算剩余成本(H值):根据地图和经验,估算从当前位置到山顶大概还要花多少力气。

总代价 F = G + H。向导每一步都选择当前F值最小的方向去探索。这个H值,就是“启发函数”,是A高效的关键。APP支持多种启发函数,你需要根据游戏类型来选择:

  • 曼哈顿距离:你的角色只能像国际象棋里的车一样,横平竖直地走格子。计算方式是 |dx| + |dy|。在标准的2D网格RPG或策略战棋游戏中很常用。
  • 对角线距离(切比雪夫距离):角色可以走横、竖、斜八个方向。计算方式是 max(|dx|, |dy|)。这是网格游戏中更常见的选择,移动更自然。
  • 欧几里得距离:就是两点间的直线距离 sqrt(dx² + dy²)。当你的角色可以在2D或3D空间中朝任意方向自由移动时(比如使用NavMesh或点阵图),这就是最自然的选择。

实操心得:在A*PP的网格图(Grid Graph)设置里,Heuristic这个下拉菜单就是让你选这个。大部分3D自由移动场景选Euclidean;标准的2D网格游戏,如果允许斜向移动,选Diagonal或Manhattan。选错了不会报错,但寻路效率会降低,计算出的路径也可能不是最直观的。

2.2 寻路图的灵魂:数据结构决定能力

A算法需要在一种叫做“图”的数据结构上运行。图由“节点”和“边”组成。APP的强大之处在于,它提供了多种“图”类型来建模你的游戏世界,而不仅仅是Unity NavMesh那种单一的导航网格。

1. 网格图:最通用和强大的选择这是我最常用,也推荐新手首选的图类型。它把你的游戏世界划分成一个均匀的二维网格(在3D中,是投影到水平面的网格)。每个格子就是一个节点,相邻的格子之间自动生成边。

  • 优点:设置简单,自动生成,对复杂不规则地形的适应性好,动态更新(如炸毁一堵墙)非常高效。
  • 缺点:内存和计算量随网格精度(节点数)平方级增长。一个1000x1000的地图,如果用精细的网格,节点数会非常恐怖。
  • 应用场景:几乎涵盖所有情况,特别是开放世界、RTS、ARPG等需要处理复杂动态地形的游戏。

2. 点阵图:精确控制的路径你需要手动在场景中放置一系列“路点”,插件会在一定距离内自动连接这些点,或者你也可以手动连接。

  • 优点:节点数极少,性能极高。路径完全由设计师控制,可以确保AI严格按照预设的巡逻路线、道路行走。
  • 缺点:设置繁琐,无法应对动态变化(新增一个障碍物,所有连接关系可能都要重新检查)。缺乏灵活性。
  • 应用场景:固定路线的塔防游戏、赛车游戏的AI路径、室内场景中沿着走廊行走的NPC。

3. Recast Graph:对付复杂几何体的利器这是A*PP中一个非常高级的功能。它有点像Unity的NavMesh,但更强大。它能够从一个复杂的3D场景网格(比如一个布满桌椅的房间模型)中,自动生成一个覆盖在模型表面的、简化的导航网格。

  • 优点:能完美处理复杂的高低落差、斜坡、洞穴等,生成的路径非常精确,且内存效率通常比高精度的网格图要好。
  • 缺点:扫描(Bake)时间较长,配置参数更复杂,对动态障碍物的支持不如网格图直接。
  • 应用场景:大型3D MMORPG、第一/第三人称游戏,需要角色在复杂建筑内部或崎岖地形表面精确行走。

4. 分层网格图:多层建筑的解决方案专门为多层建筑设计,比如一栋大楼。你可以为每一层楼创建一个独立的网格图,然后通过特定的“连接”来定义楼梯、电梯的位置,角色就可以自动在楼层间寻路。

  • 优点:逻辑清晰,能很好地处理垂直空间的寻路。
  • 缺点:设置相对复杂,需要明确划分楼层区域。
  • 应用场景:室内FPS、潜行游戏、任何有明确楼层概念的场景。

避坑指南:项目初期,如果你不确定用哪种,无脑先用网格图。它的灵活性和动态更新能力能帮你应对前期大量的玩法迭代。等到后期性能出现瓶颈或确有特殊需求时,再考虑引入点阵图(用于固定高速路)或Recast Graph(用于复杂静态地形)。

2.3 动态避障:让移动充满“灵魂”

计算出一条全局路径只是第一步。想象一下,你的士兵排着队沿着路径前进,结果在拐角处全部挤成一团,或者直接穿过了彼此的身体——这非常出戏。动态避障(Local Avoidance)就是为了解决这个问题,它让每个移动单元在遵循大方向的同时,能实时、平滑地避开路上的其他移动单位和动态小障碍物。

A*PP内置了基于RVO(互惠速度障碍)的避障系统。它的思想很巧妙:每个AI单元不仅考虑自己怎么走,还会预测周围其他单元的运动,并做出“礼让”的决策,从而产生非常自然、协调的群体移动效果,而不是简单的“硬碰撞”或“穿模”。

你需要给每个需要避障的游戏对象添加一个RVOController组件,并理解几个关键参数:

  • Radius:这个单位的“个人空间”半径。两个单位的半径之和决定了它们之间会开始避让的距离。
  • Agent Time Horizon:预测与其他移动单位发生碰撞的时间范围(秒)。值越大,越早开始避让,行为越保守。
  • Obstacle Time Horizon:预测与静态障碍物发生碰撞的时间范围。通常可以设得比Agent的小一些。
  • Max Speed:避障计算时考虑的最大速度,一般等于或略大于移动组件的最大速度。

经验之谈:调优RVO是个细活。如果单位们总是“犹犹豫豫”不敢靠近,可以适当减小Radius和Time Horizon。如果他们还是经常撞上,可能是Max Speed设低了,或者单位密度实在太大,这时可能需要结合路径查找的“排队”逻辑,或者使用更高级的“流场”技术。

3. 工程实践:搭建你的第一个A*PP寻路系统

理论说再多,不如动手搭一个。我们来一步步构建一个最基础的、包含动态避障的AI寻路单元。

3.1 环境准备与初始配置

首先,从Asset Store导入A* Pathfinding Project Pro。导入后,你的Unity编辑器菜单栏会多出一个“A*”的菜单项。

第一步:创建寻路数据容器在Unity中,寻路系统需要一个“大脑”来管理所有的图和计算。这个大脑就是AstarPath组件。

  1. 在Hierarchy中右键 ->Create->Astar->Pathfinder。这会创建一个名为“A*”的GameObject,上面挂载了AstarPath脚本。
  2. 选中这个GameObject,在Inspector里,我建议先进行一个关键设置:启用缓存(Caching)。在Optimization折叠栏下,找到Path Cache并勾选。这会缓存最近计算过的路径,当多个单位请求相同或相似的路径时,能极大提升性能。对于中小型项目,缓存大小设为500-1000就足够了。

第二步:创建你的第一张网格图

  1. 在AstarPath组件的Inspector中,点击Graphs标签页下的Add Graph按钮。
  2. 选择Grid Graph。一个网格图的配置面板就出现了。
  3. 关键配置速查:
    • Width&Depth:网格的尺寸(单位:节点数)。先别设太大,比如50x50。
    • Node Size:每个节点的世界单位大小。这是平衡精度和性能最重要的参数。值越小,寻路越精确,但节点数呈平方增长,性能越差。对于一个人形角色,我通常从0.5到1.0开始尝试。
    • Center:网格图中心的世界坐标。你可以把它设在你场景地形的中心。
    • Rotation:通常不需要动,除非你的地图是倾斜的。
    • Collision Testing:必须开启。它决定了哪些节点是不可行走的(如墙壁、悬崖)。
      • Type:选Ray或Sphere。Ray更精确,Sphere更快且对不规则地形容错性更好。初学者用Sphere。
      • Mask:选择哪些层级的物体会被当作障碍物。通常你会有个“Obstacle”层。
      • Height&Radius:检测用的胶囊体或射线的高度/半径,应略大于你的角色碰撞体。
    • Max Slope:角色能爬的最大坡度(角度)。超过这个坡度的节点会被标记为不可行走。
    • Max Climb:角色能跨越的最大高度差(如台阶高度)。

配置完后,点击下方的Scan按钮。如果一切正常,你在Scene视图中会看到一片覆盖地形的网格,其中可行走的区域是绿色(或你设置的颜色),障碍物区域是红色。

3.2 让角色动起来:Seeker与移动控制器

现在地图有了,我们需要让角色在上面寻路。

第一步:添加Seeker组件Seeker是“寻路请求者”。任何需要寻路的GameObject,都需要挂载Seeker组件。它负责向AstarPath系统发起“从A到B”的路径计算请求。

  1. 选中你的AI角色(比如一个胶囊体)。
  2. 添加组件Seeker(A* Pathfinding Project -> Seeker)。

第二步:添加移动逻辑组件A*PP提供了几种现成的移动控制器,最常用的是AIPath和RichAI。

  • AIPath:轻量、简单,适用于大多数地面移动场景。它直接朝着路径上的下一个路点(Waypoint)移动。
  • RichAI:更强大、更智能,专门为在复杂网格(NavMesh或Recast Graph)上移动的角色设计。它内置了更多的路径平滑、边缘处理和坡度适应逻辑,移动更自然,但开销也稍大。

对于我们的网格图,先使用AIPath。

  1. 添加组件AIPath(A* Pathfinding -> AIPath)。
  2. 进行关键配置:
    • Target:拖拽一个代表目标点的Transform(比如一个空物体)到这里。这是角色要移动到的位置。
    • Max Speed:最大移动速度。
    • Rotation Speed:转向速度。如果角色是刚体或需要平滑转身,这个值很重要。
    • Orientation:朝向模式。ZAxisForward是3D模型的常规设置(面朝Z轴正方向移动)。

第三步:编写简单的目标设置脚本为了让角色能动态寻找目标(比如玩家),我们写一个简单的脚本。

using UnityEngine; using Pathfinding; // 引入A*PP命名空间 public class SimpleAITarget : MonoBehaviour { public Transform target; // 在Inspector中拖入玩家对象 private IAstarAI ai; // 移动控制器的接口 void Start() { // 获取AIPath或RichAI组件,统一用IAstarAI接口操作 ai = GetComponent<IAstarAI>(); if (ai != null) { // 设置初始目标 ai.destination = target.position; // 开始寻路 ai.SearchPath(); } } void Update() { // 持续更新目标位置(例如追击玩家) if (target != null && ai != null) { // 只有当目标移动了一定距离后才重新寻路,避免每帧计算 if ((ai.destination - target.position).sqrMagnitude > 1.0f) { ai.destination = target.position; } } } }

把这个脚本挂到你的AI角色上,并把玩家角色拖给target变量。运行游戏,你的AI就会开始向玩家移动了!

3.3 实现动态避障(RVO)

让单个角色移动只是开始,让一群角色不撞在一起才是挑战。

  1. 选中你的AI角色,添加组件RVOController(A* Pathfinding -> RVOController)。
  2. 配置参数(初始可以这样设):
    • Radius: 0.5f (根据你的角色模型大小调整)
    • Agent Time Horizon: 2.0
    • Obstacle Time Horizon: 2.0
    • Max Speed: 这个值必须大于或等于AIPath组件中的Max Speed,否则避障计算会出问题。
  3. 关键一步:在AIPath组件中,找到Local Avoidance区域,将Enable Local Avoidance勾选上,并将Controller拖拽指向我们刚添加的RVOController组件。

现在,复制出多个AI角色,让他们都去追同一个目标。你会看到他们在接近时,会自然地左右分开,绕过彼此,而不是挤成一团或发生穿透。

踩坑实录:RVO避障和全局路径查找是两套独立的系统。有时你会看到角色为了避让,暂时离开了计算好的全局路径,这很正常。但如果角色“卡住”不动了,通常是Radius设得太大,或者场景通道过于狭窄,导致RVO计算不出可行的避让速度。此时需要检查场景设计,或者调小Radius,或者考虑使用RVONavmesh来提供更精确的静态障碍物信息给RVO系统。

4. 高级特性与性能调优实战

当你的游戏从原型走向正式开发,从几个AI变成成百上千个时,基础功能就不够用了。你需要掌握A*PP的高级特性来应对复杂场景和性能压力。

4.1 多图系统与区域管理

对于大型开放世界,把整个地图做成一张巨大的网格图是不现实的。A*PP支持同时使用多个图,并且可以动态加载和卸载。

场景:一个包含平原、山脉和地下城的开放世界。

  1. 创建图组:在AstarPath组件中,你可以创建多个网格图,分别对应平原、山脉等区域。给每个图起一个清晰的名字。
  2. 使用图掩码:每个Seeker在寻路时,可以指定它能在哪些图上寻路。通过GraphMask来实现。
    // 假设平原图的索引是0,山脉图是1 public GraphMask平原和山脉Mask; void Start() { // 在Inspector中,通过下拉菜单为平原和山脉Mask选择对应的图 // 或者通过代码设置 seeker.graphMask = GraphMask.FromGraphName(“平原”) | GraphMask.FromGraphName(“山脉”); // 这样,这个AI就只能在平原和山脉上寻路,无法进入地下城图 }
  3. 动态加载图:当玩家靠近山脉区域时,再通过代码加载山脉的寻路图数据,远离时卸载。这需要你自行管理图的Scan和Clear状态,或者使用A*PP的GraphUpdateScene组件配合触发器来实现区域的动态启用/禁用。

4.2 路径后处理:让移动更平滑

A算法计算出的原始路径是由网格节点中心点连接而成的折线,角色沿着它走会有明显的“卡顿”感。APP提供了Path Modifiers(路径修改器)来优化路径。

给Seeker添加修改器:

  1. 选中带有Seeker组件的AI角色。
  2. 添加组件Simple Smooth(A* Pathfinding -> Modifiers -> Simple Smooth)。
  3. 调整参数:
    • Iterations:平滑迭代次数。次数越多越平滑,但计算量越大。通常2-3次就够了。
    • Smoothness:每次迭代的平滑强度。
    • Bezier:启用贝塞尔曲线平滑,效果更好但计算稍复杂。

另一个神器:Funnel Modifier对于网格图,Funnel Modifier(漏斗算法)比平滑修改器更高效。它能将节点路径转换成一条最简化的、拐角最少的通道。对于需要精确沿墙根移动或通过狭窄通道的场景特别有用。你可以尝试同时使用Funnel和Simple Smooth。

4.3 性能优化:应对大规模寻路的策略

当屏幕上同时有大量单位需要寻路时,性能优化至关重要。

策略一:降低寻路频率不要每帧都为每个AI重新计算路径。这是最常见的性能杀手。

public class OptimizedAI : MonoBehaviour { public float repathRate = 0.5f; // 每0.5秒寻路一次 private float lastRepathTime = -9999f; private IAstarAI ai; void Start() { ai = GetComponent<IAstarAI>(); } void Update() { // 检查是否到了该重新寻路的时间 if (Time.time - lastRepathTime > repathRate && ai != null) { lastRepathTime = Time.time; // 只有目标移动了足够远,才值得重新寻路 if ((ai.destination - target.position).sqrMagnitude > 1.0f) { ai.destination = target.position; ai.SearchPath(); } } // 移动逻辑由AIPath组件在后台自动处理,无需在Update中调用 } }

策略二:使用路径缓存如前所述,确保在AstarPath组件中启用了Path Cache。对于大量单位共享少数几条路径的场景(如塔防敌人),性能提升是立竿见影的。

策略三:分帧计算如果你有上百个单位在同一帧请求寻路,会造成CPU尖峰。可以将请求分散到多帧。

// 在一个管理类中 List<IAstarAI> unitsNeedingPath = new List<IAstarAI>(); int currentIndex = 0; void Update() { if (unitsNeedingPath.Count == 0) return; // 每帧只处理N个单位的寻路请求 int unitsThisFrame = Mathf.Min(5, unitsNeedingPath.Count); for (int i = 0; i < unitsThisFrame; i++) { var ai = unitsNeedingPath[currentIndex]; ai.SearchPath(); currentIndex = (currentIndex + 1) % unitsNeedingPath.Count; } }

策略四:简化网格,增大节点这是最根本的优化。在满足游戏性要求的前提下,尽量使用更大的Node Size。将节点大小从0.5增加到1.0,节点数量会减少到原来的1/4,寻路计算量会大幅下降。同时,合理设置Max Slope和Max Climb,避免生成不必要的可行走节点。

4.4 调试与可视化:开发者的眼睛

A*PP提供了极其强大的内置调试工具,一定要善用。

  • 在Scene视图调试:运行游戏后,在Scene视图左上角的“Gizmos”下拉菜单中,你可以找到A* Pathfinding的选项。勾选Graph、Connections、Paths等,可以实时看到寻路网格、连接线、计算出的路径(绿色线)、AI的下一步目标点(小圆球)等。这是排查寻路问题(比如为什么AI卡住、为什么路径绕远)最直观的方式。
  • 使用AInspector*:在Play模式下,选中AstarPath游戏对象,在Inspector中可以看到实时的性能统计,如“Paths Per Second”(每秒寻路次数)、“Total Path Time”(总寻路耗时)等。如果“Total Path Time”持续很高,说明你的寻路系统是性能瓶颈。
  • 自定义绘制:你可以在OnDrawGizmos或OnDrawGizmosSelected中绘制自定义的调试信息,比如AI的视野范围、攻击范围、当前状态等,与A*PP的调试信息叠加,让你对AI的行为了如指掌。

5. 常见问题排查与实战技巧

即使理解了所有原理,在实际开发中还是会遇到各种奇怪的问题。这里记录一些我高频遇到的坑和解决方法。

5.1 AI卡在角落或门口

现象:AI移动到墙角、门框等狭窄处时,反复抖动或卡住不动。原因:

  1. 节点大小问题:Node Size设置得比角色的碰撞体还大,导致角色“认为”自己所在的节点和要去的下一个节点是同一个(因为都在一个节点内),路径计算结束。
  2. RVO参数过激:RVOController的Radius设得太大,在狭窄空间内计算不出可行的避障速度。
  3. 路径终点不可达:目标点被放在了不可行走的节点上(如紧贴墙壁),Seeker的StartEndModifier设置可能有问题。

排查与解决:

  1. 确保Node Size小于角色碰撞体的最小尺寸(通常是半径或宽度的一半)。
  2. 在Seeker组件上,检查是否有StartEndModifier,并确保Exact Start/End Point设置为ClosestOnNode或Interpolate,而不是Original。这会让寻路的起点和终点吸附到最近的可行走节点上。
  3. 调小RVOController的Radius,或暂时关闭局部避障看是否解决问题。如果关闭后正常,就是避障参数问题。
  4. 在Scene视图打开调试,观察AI的路径(绿线)和下一个路点(小圆球)。看路径是否在障碍物前就结束了,或者路点是否在墙里。

5.2 寻路性能突然下降

现象:游戏运行一段时间后,帧率下降,Profiler显示寻路占用大量CPU。原因:

  1. 动态更新过多:频繁使用GraphUpdateObject更新大量网格节点(比如大量可破坏的物体)。
  2. 内存泄漏:自定义的路径回调或事件没有正确注销。
  3. 路径请求堆积:大量AI在短时间内请求寻路,且没有做分帧或频率限制。

排查与解决:

  1. 使用Profiler:Unity Profiler的CPU使用率面板,查看AstarPath.Update和AstarPath.CalculatePaths的耗时。如果CalculatePaths耗时很高,说明是寻路计算本身的问题;如果Update耗时高,可能是动态更新或内部管理开销大。
  2. 优化动态更新:
    • 将多个小范围的更新合并成一个大的GraphUpdateObject进行批量更新。
    • 使用GraphUpdateObject的updatePhysics参数,如果只是修改可行走性而不需要重新进行物理碰撞检测,可以设为false。
    • 对于频繁移动的障碍物(如其他玩家),考虑使用RVO避障来处理,而不是实时更新寻路图。
  3. 检查脚本:确保所有通过seeker.StartPath注册的回调函数,在对象销毁时(OnDestroy)都被正确清理。或者使用Lambda表达式,它会自动管理生命周期。
  4. 实施分帧与缓存:如前文所述,强制实施寻路频率限制和分帧计算。

5.3 2D游戏中的Z轴问题

现象:在2D游戏中,AI计算出的路径Z轴不为0,导致角色飘在空中或沉入地下。原因:A*PP默认在3D空间工作,网格图的Y轴对应世界空间的Y轴(高度)。但在2D游戏中,我们通常使用XY平面,Z轴是深度,应该固定。解决:

  1. 配置网格图:在网格图的设置中,找到Rotation区域。将Rotation设置为 (90, 0, 0) 或 (-90, 0, 0),这取决于你的2D视角是顶视图还是侧视图。这相当于把网格图“放倒”在XY平面上。
  2. 使用2D物理检测:在Collision Testing中,将Type从Capsule或Ray改为2D,并使用2D的物理层 (Physics2D) 进行碰撞检测。
  3. 调整移动脚本:如果你使用AIPath,确保其Orientation设置正确(例如在2D顶视图中,可能设置为YAxisForward)。或者,你可以写一个简单的2D移动脚本来替代AIPath,直接操作Rigidbody2D.velocity。

5.4 如何实现“巡逻”、“追击”、“逃跑”等行为模式

A*PP提供了基础的寻路能力,但高级的AI行为需要你自己在状态机(如Animator、行为树或简单枚举状态)中组合调用。

public enum AIState { Idle, Patrol, Chase, Flee } public class AdvancedAI : MonoBehaviour { public AIState currentState = AIState.Patrol; public Transform[] patrolPoints; private int currentPatrolIndex = 0; private IAstarAI ai; public Transform player; public float chaseRange = 10f; public float fleeRange = 5f; void Start() { ai = GetComponent<IAstarAI>(); } void Update() { float distToPlayer = Vector3.Distance(transform.position, player.position); switch (currentState) { case AIState.Patrol: // 巡逻逻辑 if (ai.reachedEndOfPath || !ai.pathPending) { currentPatrolIndex = (currentPatrolIndex + 1) % patrolPoints.Length; ai.destination = patrolPoints[currentPatrolIndex].position; ai.SearchPath(); } // 状态转换:发现玩家 if (distToPlayer < chaseRange) currentState = AIState.Chase; break; case AIState.Chase: // 追击逻辑:持续更新目标为玩家位置 ai.destination = player.position; // 状态转换:玩家跑远或进入逃跑状态 if (distToPlayer > chaseRange * 1.2f) currentState = AIState.Patrol; if (distToPlayer < fleeRange) currentState = AIState.Flee; // 假设太近了要逃跑 break; case AIState.Flee: // 逃跑逻辑:计算远离玩家的方向 Vector3 fleeDir = (transform.position - player.position).normalized; ai.destination = transform.position + fleeDir * 20f; // 向远处跑20个单位 // 状态转换:跑出一定距离 if (distToPlayer > fleeRange * 2f) currentState = AIState.Chase; break; } } }

这个简单的状态机框架,结合A*PP的寻路能力,就能构建出相当复杂的AI行为。关键在于理解,寻路系统只负责解决“怎么去”的问题,而AI逻辑负责决定“去哪里”和“什么时候去”。

需要专业的网站建设服务?

联系我们获取免费的网站建设咨询和方案报价,让我们帮助您实现业务目标

立即咨询