2025-10-03 00:31:34 +08:00
|
|
|
|
using Data;
|
|
|
|
|
|
using Managers;
|
|
|
|
|
|
using UnityEngine;
|
|
|
|
|
|
|
|
|
|
|
|
namespace AI
|
|
|
|
|
|
{
|
|
|
|
|
|
public class JobNode_MoveToAttackRange : LeafNodeBase
|
|
|
|
|
|
{
|
2025-10-10 14:08:23 +08:00
|
|
|
|
// 卡住检测的常量
|
|
|
|
|
|
private const int MAX_STUCK_FRAMES = 10; // 实体在多少帧内没有显著移动,则认为卡住
|
|
|
|
|
|
private const float STUCK_POSITION_THRESHOLD_SQ = 0.00001f; // 位置变化的平方距离阈值
|
|
|
|
|
|
|
|
|
|
|
|
// 新增的偏移尝试常量
|
|
|
|
|
|
private const int _maxOffsetAttempts = 5; // 尝试偏移的最大次数
|
|
|
|
|
|
private const float _offsetDistance = 0.5f; // 每次偏移的距离
|
2025-10-03 00:31:34 +08:00
|
|
|
|
private bool _isPathSet; // 指示当前是否已设置路径
|
|
|
|
|
|
private Vector3 _lastKnownSelfPosition; // 上次已知自身位置
|
|
|
|
|
|
|
|
|
|
|
|
private int _stuckFrameCount; // 卡住帧计数
|
2025-10-10 14:08:23 +08:00
|
|
|
|
private Entity.Entity _targetHostileEntity; // 目标敌对实体
|
|
|
|
|
|
private Vector3 _targetMovePosition; // 目标移动位置
|
2025-10-03 00:31:34 +08:00
|
|
|
|
|
|
|
|
|
|
// 便利属性,获取实体的攻击范围
|
|
|
|
|
|
private float AttackRange => SelfEntity.AttributesNow.attackRange;
|
|
|
|
|
|
|
|
|
|
|
|
/// <summary>
|
2025-10-10 14:08:23 +08:00
|
|
|
|
/// 执行移动到攻击范围的逻辑。
|
2025-10-03 00:31:34 +08:00
|
|
|
|
/// </summary>
|
|
|
|
|
|
/// <returns>行为树节点状态。</returns>
|
|
|
|
|
|
protected override Status ExecuteLeafLogic()
|
|
|
|
|
|
{
|
|
|
|
|
|
// 如果路径尚未设置,或目标实体无效(null或死亡),则需要重新寻找目标并设置路径
|
|
|
|
|
|
if (!_isPathSet || !_targetHostileEntity || _targetHostileEntity.IsDead)
|
|
|
|
|
|
{
|
|
|
|
|
|
// 1. 寻找最近的敌对实体
|
|
|
|
|
|
var hostileEntityRecord = EntityManager.Instance.FindNearestEntityByRelation(
|
|
|
|
|
|
SelfEntity.currentDimensionId,
|
|
|
|
|
|
SelfEntity.entityPrefab,
|
|
|
|
|
|
Relation.Hostile);
|
|
|
|
|
|
|
|
|
|
|
|
// 如果没有找到敌对目标,任务失败
|
2025-10-10 14:08:23 +08:00
|
|
|
|
if (!hostileEntityRecord || !hostileEntityRecord.entity) return Status.Failure;
|
|
|
|
|
|
|
|
|
|
|
|
_targetHostileEntity = hostileEntityRecord.entity;
|
|
|
|
|
|
|
|
|
|
|
|
var dir = (SelfEntity.Position - _targetHostileEntity.Position);
|
|
|
|
|
|
if (dir.sqrMagnitude<=AttackRange*AttackRange)
|
2025-10-03 00:31:34 +08:00
|
|
|
|
{
|
2025-10-10 14:08:23 +08:00
|
|
|
|
return Status.Success;
|
2025-10-03 00:31:34 +08:00
|
|
|
|
}
|
2025-10-10 14:08:23 +08:00
|
|
|
|
|
|
|
|
|
|
// 计算目标攻击范围边缘的位置
|
|
|
|
|
|
var directionToSelf = dir.normalized;
|
|
|
|
|
|
// 这次计算出的目标点是最初的精确临界点
|
|
|
|
|
|
var initialTargetMovePosition = _targetHostileEntity.Position + directionToSelf * AttackRange;
|
|
|
|
|
|
_targetMovePosition = initialTargetMovePosition; // 暂时设置,可能被偏移后的点更新
|
2025-10-03 00:31:34 +08:00
|
|
|
|
|
2025-10-10 14:08:23 +08:00
|
|
|
|
// 3. 通知 SelfEntity 设置路径目标,并检查是否成功
|
|
|
|
|
|
if (SelfEntity.SetTarget(initialTargetMovePosition))
|
|
|
|
|
|
{
|
|
|
|
|
|
// 路径成功生成,可以开始移动
|
|
|
|
|
|
_isPathSet = true;
|
|
|
|
|
|
_lastKnownSelfPosition = SelfEntity.Position; // 初始化上次已知位置,用于卡住检测
|
|
|
|
|
|
_stuckFrameCount = 0; // 重置卡住计数器
|
|
|
|
|
|
return Status.Running; // 路径已设置,开始移动
|
|
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
|
|
var pathFoundAfterOffset = false;
|
|
|
|
|
|
for (var i = 0; i < _maxOffsetAttempts; i++)
|
|
|
|
|
|
{
|
|
|
|
|
|
// 生成随机偏移向量,确保在二维平面内 (假设Z轴不变)
|
|
|
|
|
|
var randomOffsetCircle = Random.insideUnitCircle * _offsetDistance;
|
|
|
|
|
|
var potentialOffsetTarget = initialTargetMovePosition +
|
|
|
|
|
|
new Vector3(randomOffsetCircle.x, randomOffsetCircle.y, 0);
|
2025-10-03 00:31:34 +08:00
|
|
|
|
|
2025-10-10 14:08:23 +08:00
|
|
|
|
// 再次尝试设置目标
|
|
|
|
|
|
if (SelfEntity.SetTarget(potentialOffsetTarget))
|
|
|
|
|
|
{
|
|
|
|
|
|
// 偏移后路径成功生成
|
|
|
|
|
|
_targetMovePosition = potentialOffsetTarget; // 更新节点内部的目标为成功的偏移点
|
|
|
|
|
|
pathFoundAfterOffset = true;
|
|
|
|
|
|
break; // 跳出偏移尝试循环
|
|
|
|
|
|
}
|
|
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
|
|
if (pathFoundAfterOffset)
|
|
|
|
|
|
{
|
|
|
|
|
|
// 偏移后找到路径,初始化状态并返回Running
|
|
|
|
|
|
_isPathSet = true;
|
|
|
|
|
|
_lastKnownSelfPosition = SelfEntity.Position;
|
|
|
|
|
|
_stuckFrameCount = 0;
|
|
|
|
|
|
return Status.Running;
|
|
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
|
|
_isPathSet = false; // 确保路径标志为false
|
|
|
|
|
|
return Status.Failure; // 最终无法设置路径,任务失败
|
2025-10-03 00:31:34 +08:00
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
|
|
// 路径已设置,继续管理移动和卡住检测
|
2025-10-10 14:08:23 +08:00
|
|
|
|
// 实体已到达目标点,或已经进入目标的攻击范围
|
|
|
|
|
|
if (SelfEntity.OnTargetPoint || (SelfEntity.Position - _targetHostileEntity.Position).sqrMagnitude <
|
|
|
|
|
|
SelfEntity.AttributesNow.attackRange * SelfEntity.AttributesNow.attackRange)
|
2025-10-03 00:31:34 +08:00
|
|
|
|
return Status.Success; // 成功移动到攻击范围
|
|
|
|
|
|
|
2025-10-10 14:08:23 +08:00
|
|
|
|
if (SelfEntity.AttributesNow.moveSpeed <= 0)
|
|
|
|
|
|
return Status.Failure;
|
|
|
|
|
|
|
|
|
|
|
|
// 检查是否卡住
|
2025-10-03 00:31:34 +08:00
|
|
|
|
// 计算当前位置与上次已知位置的平方距离,避免开方运算,提高性能
|
2025-10-10 14:08:23 +08:00
|
|
|
|
var currentPositionChangeSq = (SelfEntity.Position - _lastKnownSelfPosition).sqrMagnitude;
|
2025-10-03 00:31:34 +08:00
|
|
|
|
if (currentPositionChangeSq < STUCK_POSITION_THRESHOLD_SQ)
|
|
|
|
|
|
{
|
|
|
|
|
|
_stuckFrameCount++;
|
|
|
|
|
|
if (_stuckFrameCount >= MAX_STUCK_FRAMES)
|
|
|
|
|
|
{
|
2025-10-10 14:08:23 +08:00
|
|
|
|
_isPathSet = false;
|
|
|
|
|
|
|
|
|
|
|
|
return Status.Running;
|
2025-10-03 00:31:34 +08:00
|
|
|
|
}
|
|
|
|
|
|
}
|
|
|
|
|
|
else
|
|
|
|
|
|
{
|
|
|
|
|
|
// 实体有移动,重置卡住计数器
|
|
|
|
|
|
_stuckFrameCount = 0;
|
|
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
|
|
_lastKnownSelfPosition = SelfEntity.Position;
|
|
|
|
|
|
|
|
|
|
|
|
SelfEntity.TryMove();
|
2025-10-10 14:08:23 +08:00
|
|
|
|
return Status.Running;
|
2025-10-03 00:31:34 +08:00
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
|
|
/// <summary>
|
2025-10-10 14:08:23 +08:00
|
|
|
|
/// 重置此移动节点的所有内部状态。
|
2025-10-03 00:31:34 +08:00
|
|
|
|
/// </summary>
|
|
|
|
|
|
public override void Reset()
|
|
|
|
|
|
{
|
|
|
|
|
|
base.Reset(); // 调用基类的 Reset,重置 CurrentStatus 和 _elapsedFrames
|
|
|
|
|
|
_targetHostileEntity = null;
|
|
|
|
|
|
_targetMovePosition = Vector3.zero;
|
|
|
|
|
|
_isPathSet = false;
|
|
|
|
|
|
_lastKnownSelfPosition = Vector3.zero;
|
|
|
|
|
|
_stuckFrameCount = 0;
|
|
|
|
|
|
}
|
|
|
|
|
|
}
|
2025-10-10 14:08:23 +08:00
|
|
|
|
}
|