#if GRAPH_DESIGNER using UnityEngine; using Opsive.BehaviorDesigner.Runtime.Tasks; using Opsive.BehaviorDesigner.Runtime.Tasks.Actions; using BaseGames.Enemies; using BaseGames.Enemies.Perception; namespace BaseGames.Enemies.AI { /// /// BD Action:来回踱步巡逻——持续向当前方向移动,遇墙或悬崖时自动翻转方向。 /// /// 若需要按预设路点顺序巡逻,请使用 (支持 Transform 引用和内联坐标)。 /// /// 转向检测优先级: /// /// EnemySensorHub "wall_ahead" / "ledge" 槽(SensorToolkit,已配置时使用) /// Physics2D Raycast 兜底(Prefab 未配置 Sensor 时自动启用) /// /// [TaskName("Patrol (Pace)")] [TaskCategory("BaseGames/Enemy/Movement")] [TaskDescription("来回踱步巡逻:遇墙或悬崖自动翻转方向(SensorToolkit 优先)")] public class BD_Patrol : Action { [Tooltip("(兜底)检测地面边缘的向下射线长度(m)")] public float edgeCheckLength = 1.2f; [Tooltip("(兜底)检测障碍物的水平射线长度(m)")] public float wallCheckLength = 0.4f; [Tooltip("(兜底)边缘检测射线起点相对角色的前向偏移(m)")] public float edgeCheckFwdOffset = 0.3f; [Tooltip("(兜底)边缘检测射线起点相对角色的向下偏移(m)")] public float edgeCheckDownOffset = 0.1f; [Tooltip("(兜底)地面/墙壁 LayerMask")] public LayerMask groundLayer; private EnemyBase _enemy; private EnemySensorHub _hub; private float _dir = 1f; // 缓存:SensorHub 中对应槽位是否已配置(Awake 时查询一次,避免每帧 Dictionary 查找) private bool _hasWallSensor; private bool _hasEdgeSensor; public override void OnAwake() { _enemy = GetComponent(); _hub = GetComponent(); _hasWallSensor = _hub != null && _hub.Get(SensorSlotNames.WallAhead) != null; _hasEdgeSensor = _hub != null && _hub.Get(SensorSlotNames.Ledge) != null; } public override void OnStart() => _enemy?.SetAiPhase(AiPhase.Patrol); public override TaskStatus OnUpdate() { if (_enemy == null) return TaskStatus.Failure; if (ShouldFlip()) _dir = -_dir; _enemy.MoveInDirection(_dir); return TaskStatus.Running; } public override void OnEnd() => _enemy?.StopMovement(); private bool ShouldFlip() { if (_hub != null) { // 有传感器配置:用传感器结果,完全跳过 Raycast if (_hasWallSensor || _hasEdgeSensor) { bool wallHit = _hasWallSensor && _hub.HasAnyDetection(SensorSlotNames.WallAhead); bool edgeHit = _hasEdgeSensor && _hub.HasAnyDetection(SensorSlotNames.Ledge); return wallHit || edgeHit; } } // Raycast 兜底:仅在未配置 Sensor 时执行 Transform t = _enemy.transform; Vector2 pos = t.position; Vector2 edgeOrigin = pos + Vector2.right * (_dir * edgeCheckFwdOffset) + Vector2.down * edgeCheckDownOffset; bool hasGround = Physics2D.Raycast(edgeOrigin, Vector2.down, edgeCheckLength, groundLayer); if (!hasGround) return true; bool hitWall = Physics2D.Raycast(pos, Vector2.right * _dir, wallCheckLength, groundLayer); return hitWall; } } } #endif