Fix navigation issue
This commit is contained in:
parent
5cf70ccf4b
commit
fcf4121cbe
@ -54,6 +54,7 @@ public partial class CampusController : Node2D
|
|||||||
private Rect2I _astarRegion;
|
private Rect2I _astarRegion;
|
||||||
private int _astarMapIteration;
|
private int _astarMapIteration;
|
||||||
private Rid _astarMap;
|
private Rid _astarMap;
|
||||||
|
private readonly List<Vector2I> _astarWalkableCells = new();
|
||||||
private const int GridSearchRadius = 6;
|
private const int GridSearchRadius = 6;
|
||||||
|
|
||||||
// Called when the node enters the scene tree for the first time.
|
// Called when the node enters the scene tree for the first time.
|
||||||
@ -365,18 +366,25 @@ public partial class CampusController : Node2D
|
|||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
SpawnStudents(map);
|
if (!EnsureAStarGrid() || _astarWalkableCells.Count == 0)
|
||||||
_spawnPending = false;
|
{
|
||||||
|
return;
|
||||||
|
}
|
||||||
|
|
||||||
|
if (SpawnStudents())
|
||||||
|
{
|
||||||
|
_spawnPending = false;
|
||||||
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
private void SpawnStudents(Rid map)
|
private bool SpawnStudents()
|
||||||
{
|
{
|
||||||
_coveragePoints.Clear();
|
_coveragePoints.Clear();
|
||||||
_coveragePoints.AddRange(BuildCoveragePoints());
|
_coveragePoints.AddRange(BuildCoveragePoints());
|
||||||
if (_coveragePoints.Count == 0)
|
if (_coveragePoints.Count == 0)
|
||||||
{
|
{
|
||||||
GD.PushWarning("未采样到可行走区域,跳过学生生成。");
|
GD.PushWarning("未采样到可行走区域,跳过学生生成。");
|
||||||
return;
|
return false;
|
||||||
}
|
}
|
||||||
|
|
||||||
for (int i = 0; i < StudentCount; i++)
|
for (int i = 0; i < StudentCount; i++)
|
||||||
@ -390,15 +398,15 @@ public partial class CampusController : Node2D
|
|||||||
}
|
}
|
||||||
|
|
||||||
_studentsRoot.AddChild(student);
|
_studentsRoot.AddChild(student);
|
||||||
student.SetNavigationMap(map);
|
|
||||||
student.MoveSpeed = AgentMoveSpeed;
|
student.MoveSpeed = AgentMoveSpeed;
|
||||||
student.GridWalkableTolerance = GridWalkableTolerance;
|
|
||||||
|
|
||||||
// 随机放置在可行走区域,并交给行为系统控制
|
// 随机放置在可行走区域,并交给行为系统控制
|
||||||
var randomIndex = _random != null
|
if (!TryGetRandomWalkableGridPoint(out var gridPoint))
|
||||||
? _random.Next(0, _coveragePoints.Count)
|
{
|
||||||
: (int)GD.RandRange(0, _coveragePoints.Count - 1);
|
GD.PushWarning("AStarGrid2D 未准备好,无法放置学生。");
|
||||||
student.GlobalPosition = _coveragePoints[randomIndex];
|
return false;
|
||||||
|
}
|
||||||
|
student.GlobalPosition = gridPoint;
|
||||||
student.ApplyRandomTheme();
|
student.ApplyRandomTheme();
|
||||||
|
|
||||||
var runtime = BuildRandomAgentRuntime(i);
|
var runtime = BuildRandomAgentRuntime(i);
|
||||||
@ -417,6 +425,8 @@ public partial class CampusController : Node2D
|
|||||||
_behaviorAgents.Add(agent);
|
_behaviorAgents.Add(agent);
|
||||||
LogSpawn(runtime);
|
LogSpawn(runtime);
|
||||||
}
|
}
|
||||||
|
|
||||||
|
return true;
|
||||||
}
|
}
|
||||||
|
|
||||||
private static readonly CampusTaskType[] TaskTypePool =
|
private static readonly CampusTaskType[] TaskTypePool =
|
||||||
@ -703,6 +713,21 @@ public partial class CampusController : Node2D
|
|||||||
return result;
|
return result;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
private bool TryGetRandomWalkableGridPoint(out Vector2 point)
|
||||||
|
{
|
||||||
|
point = Vector2.Zero;
|
||||||
|
if (!EnsureAStarGrid() || _astarWalkableCells.Count == 0)
|
||||||
|
{
|
||||||
|
return false;
|
||||||
|
}
|
||||||
|
|
||||||
|
var index = _random != null
|
||||||
|
? _random.Next(0, _astarWalkableCells.Count)
|
||||||
|
: (int)GD.RandRange(0, _astarWalkableCells.Count - 1);
|
||||||
|
point = GridToWorld(_astarWalkableCells[index]);
|
||||||
|
return true;
|
||||||
|
}
|
||||||
|
|
||||||
private bool EnsureAStarGrid()
|
private bool EnsureAStarGrid()
|
||||||
{
|
{
|
||||||
if (!IsNavigationMapReady(out var map))
|
if (!IsNavigationMapReady(out var map))
|
||||||
@ -737,6 +762,7 @@ public partial class CampusController : Node2D
|
|||||||
_astarGrid.DiagonalMode = AStarGrid2D.DiagonalModeEnum.Never;
|
_astarGrid.DiagonalMode = AStarGrid2D.DiagonalModeEnum.Never;
|
||||||
_astarGrid.Update();
|
_astarGrid.Update();
|
||||||
|
|
||||||
|
_astarWalkableCells.Clear();
|
||||||
for (var x = region.Position.X; x < region.Position.X + region.Size.X; x++)
|
for (var x = region.Position.X; x < region.Position.X + region.Size.X; x++)
|
||||||
{
|
{
|
||||||
for (var y = region.Position.Y; y < region.Position.Y + region.Size.Y; y++)
|
for (var y = region.Position.Y; y < region.Position.Y + region.Size.Y; y++)
|
||||||
@ -745,6 +771,10 @@ public partial class CampusController : Node2D
|
|||||||
var center = GridToWorld(cell);
|
var center = GridToWorld(cell);
|
||||||
var walkable = IsCellWalkable(center, map);
|
var walkable = IsCellWalkable(center, map);
|
||||||
_astarGrid.SetPointSolid(cell, !walkable);
|
_astarGrid.SetPointSolid(cell, !walkable);
|
||||||
|
if (walkable)
|
||||||
|
{
|
||||||
|
_astarWalkableCells.Add(cell);
|
||||||
|
}
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
@ -973,6 +1003,7 @@ public partial class CampusController : Node2D
|
|||||||
_astarGrid = null;
|
_astarGrid = null;
|
||||||
_astarMap = new Rid();
|
_astarMap = new Rid();
|
||||||
_astarMapIteration = 0;
|
_astarMapIteration = 0;
|
||||||
|
_astarWalkableCells.Clear();
|
||||||
_navBakePending = false;
|
_navBakePending = false;
|
||||||
_navBakeReady = true;
|
_navBakeReady = true;
|
||||||
RequestDebugGridRedraw();
|
RequestDebugGridRedraw();
|
||||||
|
|||||||
@ -54,10 +54,6 @@ public partial class CampusStudent : CharacterBody2D
|
|||||||
/// </summary>
|
/// </summary>
|
||||||
private Vector2 _lastPosition;
|
private Vector2 _lastPosition;
|
||||||
|
|
||||||
/// <summary>
|
|
||||||
/// 导航代理
|
|
||||||
/// </summary>
|
|
||||||
private NavigationAgent2D _navigationAgent;
|
|
||||||
/// <summary>
|
/// <summary>
|
||||||
/// 服装精灵
|
/// 服装精灵
|
||||||
/// </summary>
|
/// </summary>
|
||||||
@ -83,10 +79,6 @@ public partial class CampusStudent : CharacterBody2D
|
|||||||
/// </summary>
|
/// </summary>
|
||||||
private float _stuckTimer;
|
private float _stuckTimer;
|
||||||
/// <summary>
|
/// <summary>
|
||||||
/// 导航地图RID
|
|
||||||
/// </summary>
|
|
||||||
private Rid _navigationMap;
|
|
||||||
/// <summary>
|
|
||||||
/// 当前目标点
|
/// 当前目标点
|
||||||
/// </summary>
|
/// </summary>
|
||||||
private Vector2 _currentTarget = Vector2.Zero;
|
private Vector2 _currentTarget = Vector2.Zero;
|
||||||
@ -156,10 +148,6 @@ public partial class CampusStudent : CharacterBody2D
|
|||||||
/// </summary>
|
/// </summary>
|
||||||
[Export] public bool Use16X16Sprites { get; set; } = true;
|
[Export] public bool Use16X16Sprites { get; set; } = true;
|
||||||
/// <summary>
|
/// <summary>
|
||||||
/// 是否启用避让
|
|
||||||
/// </summary>
|
|
||||||
[Export] public bool EnableAvoidance { get; set; }
|
|
||||||
/// <summary>
|
|
||||||
/// 卡住重新寻路时间
|
/// 卡住重新寻路时间
|
||||||
/// </summary>
|
/// </summary>
|
||||||
[Export] public float StuckRepathSeconds { get; set; } = 0.6f;
|
[Export] public float StuckRepathSeconds { get; set; } = 0.6f;
|
||||||
@ -168,18 +156,6 @@ public partial class CampusStudent : CharacterBody2D
|
|||||||
/// </summary>
|
/// </summary>
|
||||||
[Export] public float StuckDistanceEpsilon { get; set; } = 2.0f;
|
[Export] public float StuckDistanceEpsilon { get; set; } = 2.0f;
|
||||||
/// <summary>
|
/// <summary>
|
||||||
/// 导航网格吸附距离
|
|
||||||
/// </summary>
|
|
||||||
[Export] public float NavMeshClampDistance { get; set; } = 6.0f;
|
|
||||||
/// <summary>
|
|
||||||
/// 是否使用网格寻路
|
|
||||||
/// </summary>
|
|
||||||
[Export] public bool UseGridPathfinding { get; set; } = true;
|
|
||||||
/// <summary>
|
|
||||||
/// 网格可行走容差
|
|
||||||
/// </summary>
|
|
||||||
[Export] public float GridWalkableTolerance { get; set; } = 2.0f;
|
|
||||||
/// <summary>
|
|
||||||
/// 网格重新寻路间隔
|
/// 网格重新寻路间隔
|
||||||
/// </summary>
|
/// </summary>
|
||||||
[Export] public float GridRepathInterval { get; set; } = 0.25f;
|
[Export] public float GridRepathInterval { get; set; } = 0.25f;
|
||||||
@ -201,7 +177,6 @@ public partial class CampusStudent : CharacterBody2D
|
|||||||
/// </summary>
|
/// </summary>
|
||||||
public override void _Ready()
|
public override void _Ready()
|
||||||
{
|
{
|
||||||
_navigationAgent = GetNodeOrNull<NavigationAgent2D>("NavigationAgent2D");
|
|
||||||
_animationPlayer = GetNodeOrNull<AnimationPlayer>("AnimationPlayer");
|
_animationPlayer = GetNodeOrNull<AnimationPlayer>("AnimationPlayer");
|
||||||
_campusController = GetTree()?.CurrentScene as CampusController;
|
_campusController = GetTree()?.CurrentScene as CampusController;
|
||||||
CacheSprites();
|
CacheSprites();
|
||||||
@ -212,22 +187,7 @@ public partial class CampusStudent : CharacterBody2D
|
|||||||
_animationPlayer.AnimationFinished += OnAnimationFinished;
|
_animationPlayer.AnimationFinished += OnAnimationFinished;
|
||||||
}
|
}
|
||||||
|
|
||||||
if (_navigationAgent != null)
|
if (_patrolConfigured) AdvanceTarget();
|
||||||
{
|
|
||||||
// 强制关闭避让,学生之间直接穿过
|
|
||||||
EnableAvoidance = false;
|
|
||||||
|
|
||||||
// 让寻路点更“贴近目标”,避免走到边缘时抖动
|
|
||||||
_navigationAgent.PathDesiredDistance = TargetReachDistance;
|
|
||||||
_navigationAgent.TargetDesiredDistance = TargetReachDistance;
|
|
||||||
_navigationAgent.AvoidanceEnabled = EnableAvoidance;
|
|
||||||
|
|
||||||
if (EnableAvoidance)
|
|
||||||
// 开启避让时使用安全速度回调进行移动
|
|
||||||
_navigationAgent.VelocityComputed += OnVelocityComputed;
|
|
||||||
|
|
||||||
if (_patrolConfigured) AdvanceTarget();
|
|
||||||
}
|
|
||||||
|
|
||||||
PlayIdleAnimation();
|
PlayIdleAnimation();
|
||||||
_lastPosition = GlobalPosition;
|
_lastPosition = GlobalPosition;
|
||||||
@ -251,40 +211,27 @@ public partial class CampusStudent : CharacterBody2D
|
|||||||
if (_phoneExitLocked)
|
if (_phoneExitLocked)
|
||||||
{
|
{
|
||||||
Velocity = Vector2.Zero;
|
Velocity = Vector2.Zero;
|
||||||
if (!EnableAvoidance && _usePhysicsMovement)
|
if (_usePhysicsMovement)
|
||||||
{
|
{
|
||||||
MoveAndSlide();
|
MoveAndSlide();
|
||||||
}
|
}
|
||||||
return;
|
return;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
var hasPatrolTarget = !_behaviorControlEnabled && _patrolPoints.Count > 0;
|
||||||
if (_behaviorControlEnabled && _behaviorHasTarget)
|
if (_behaviorControlEnabled && _behaviorHasTarget)
|
||||||
{
|
{
|
||||||
TryBuildPendingGridPath();
|
TryBuildPendingGridPath();
|
||||||
if (_gridPathActive)
|
|
||||||
{
|
|
||||||
if (ProcessGridPathMovement(delta))
|
|
||||||
{
|
|
||||||
return;
|
|
||||||
}
|
|
||||||
}
|
|
||||||
else if (UseGridPathfinding && _gridPathPending)
|
|
||||||
{
|
|
||||||
Velocity = Vector2.Zero;
|
|
||||||
if (!EnableAvoidance && _usePhysicsMovement)
|
|
||||||
{
|
|
||||||
MoveAndSlide();
|
|
||||||
}
|
|
||||||
|
|
||||||
if (!_phoneIdleActive && !_phoneExitLocked)
|
|
||||||
{
|
|
||||||
PlayIdleAnimation();
|
|
||||||
}
|
|
||||||
UpdateStuckTimer(delta);
|
|
||||||
return;
|
|
||||||
}
|
|
||||||
}
|
}
|
||||||
if (_navigationAgent == null || (!_behaviorControlEnabled && _patrolPoints.Count == 0) || (_behaviorControlEnabled && !_behaviorHasTarget))
|
else if (hasPatrolTarget)
|
||||||
|
{
|
||||||
|
if (!_hasTarget || (!_gridPathPending && !_gridPathActive))
|
||||||
|
{
|
||||||
|
AdvanceTarget();
|
||||||
|
}
|
||||||
|
TryBuildPendingGridPath();
|
||||||
|
}
|
||||||
|
else
|
||||||
{
|
{
|
||||||
if (!_phoneIdleActive && !_phoneExitLocked)
|
if (!_phoneIdleActive && !_phoneExitLocked)
|
||||||
{
|
{
|
||||||
@ -293,35 +240,23 @@ public partial class CampusStudent : CharacterBody2D
|
|||||||
return;
|
return;
|
||||||
}
|
}
|
||||||
|
|
||||||
// 到达目标点或无路可走时,切换到下一个巡游点
|
if (_gridPathActive)
|
||||||
if (_navigationAgent.IsNavigationFinished())
|
|
||||||
{
|
{
|
||||||
if (_behaviorControlEnabled)
|
if (ProcessGridPathMovement(delta))
|
||||||
{
|
{
|
||||||
Velocity = Vector2.Zero;
|
if (hasPatrolTarget && !_gridPathActive)
|
||||||
if (!EnableAvoidance && _usePhysicsMovement)
|
|
||||||
{
|
{
|
||||||
MoveAndSlide();
|
AdvanceTarget();
|
||||||
}
|
}
|
||||||
|
|
||||||
if (!_phoneIdleActive && !_phoneExitLocked)
|
|
||||||
{
|
|
||||||
PlayIdleAnimation();
|
|
||||||
}
|
|
||||||
UpdateStuckTimer(delta);
|
|
||||||
return;
|
return;
|
||||||
}
|
}
|
||||||
|
|
||||||
AdvanceTarget();
|
|
||||||
}
|
}
|
||||||
|
|
||||||
var nextPosition = _navigationAgent.GetNextPathPosition();
|
if (_gridPathPending)
|
||||||
var toNext = nextPosition - GlobalPosition;
|
|
||||||
if (toNext.LengthSquared() < 0.01f)
|
|
||||||
{
|
{
|
||||||
if (!EnableAvoidance && _usePhysicsMovement)
|
Velocity = Vector2.Zero;
|
||||||
|
if (_usePhysicsMovement)
|
||||||
{
|
{
|
||||||
Velocity = Vector2.Zero;
|
|
||||||
MoveAndSlide();
|
MoveAndSlide();
|
||||||
}
|
}
|
||||||
|
|
||||||
@ -333,21 +268,9 @@ public partial class CampusStudent : CharacterBody2D
|
|||||||
return;
|
return;
|
||||||
}
|
}
|
||||||
|
|
||||||
var direction = toNext.Normalized();
|
if (!_phoneIdleActive && !_phoneExitLocked)
|
||||||
var desiredVelocity = direction * MoveSpeed;
|
|
||||||
|
|
||||||
if (EnableAvoidance)
|
|
||||||
{
|
{
|
||||||
// 交给导航系统做群体避让
|
PlayIdleAnimation();
|
||||||
_navigationAgent.Velocity = desiredVelocity;
|
|
||||||
}
|
|
||||||
else
|
|
||||||
{
|
|
||||||
// 未启用避让时直接移动
|
|
||||||
Velocity = ClampVelocityToNavMesh(desiredVelocity);
|
|
||||||
ApplyMovement(delta);
|
|
||||||
UpdateFacingAnimation(Velocity);
|
|
||||||
UpdateStuckTimer(delta);
|
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
@ -386,7 +309,7 @@ public partial class CampusStudent : CharacterBody2D
|
|||||||
_patrolConfigured = true;
|
_patrolConfigured = true;
|
||||||
ApplyRandomTheme();
|
ApplyRandomTheme();
|
||||||
|
|
||||||
if (_navigationAgent != null) AdvanceTarget();
|
AdvanceTarget();
|
||||||
}
|
}
|
||||||
|
|
||||||
/// <summary>
|
/// <summary>
|
||||||
@ -407,28 +330,9 @@ public partial class CampusStudent : CharacterBody2D
|
|||||||
public void SetBehaviorTarget(Vector2 target)
|
public void SetBehaviorTarget(Vector2 target)
|
||||||
{
|
{
|
||||||
_behaviorControlEnabled = true;
|
_behaviorControlEnabled = true;
|
||||||
target = ClampTargetToNavMesh(target);
|
|
||||||
_behaviorTarget = target;
|
_behaviorTarget = target;
|
||||||
_behaviorHasTarget = true;
|
_behaviorHasTarget = true;
|
||||||
_currentTarget = target;
|
BeginGridTarget(target);
|
||||||
_hasTarget = true;
|
|
||||||
_stuckTimer = 0.0f;
|
|
||||||
_gridPathActive = false;
|
|
||||||
_gridPathPending = false;
|
|
||||||
_gridPathIndex = 0;
|
|
||||||
_gridPathRetryTimer = 0.0f;
|
|
||||||
_gridPath.Clear();
|
|
||||||
|
|
||||||
if (UseGridPathfinding)
|
|
||||||
{
|
|
||||||
_gridPathPending = true;
|
|
||||||
TryBuildPendingGridPath();
|
|
||||||
}
|
|
||||||
|
|
||||||
if (!UseGridPathfinding && _navigationAgent != null)
|
|
||||||
{
|
|
||||||
_navigationAgent.TargetPosition = target;
|
|
||||||
}
|
|
||||||
}
|
}
|
||||||
|
|
||||||
/// <summary>
|
/// <summary>
|
||||||
@ -447,6 +351,23 @@ public partial class CampusStudent : CharacterBody2D
|
|||||||
_gridPath.Clear();
|
_gridPath.Clear();
|
||||||
}
|
}
|
||||||
|
|
||||||
|
/// <summary>
|
||||||
|
/// 设置网格寻路目标
|
||||||
|
/// </summary>
|
||||||
|
/// <param name="target">目标位置</param>
|
||||||
|
private void BeginGridTarget(Vector2 target)
|
||||||
|
{
|
||||||
|
_currentTarget = target;
|
||||||
|
_hasTarget = true;
|
||||||
|
_stuckTimer = 0.0f;
|
||||||
|
_gridPathActive = false;
|
||||||
|
_gridPathPending = true;
|
||||||
|
_gridPathIndex = 0;
|
||||||
|
_gridPathRetryTimer = 0.0f;
|
||||||
|
_gridPath.Clear();
|
||||||
|
TryBuildPendingGridPath();
|
||||||
|
}
|
||||||
|
|
||||||
/// <summary>
|
/// <summary>
|
||||||
/// 是否已到达行为目标
|
/// 是否已到达行为目标
|
||||||
/// </summary>
|
/// </summary>
|
||||||
@ -462,8 +383,7 @@ public partial class CampusStudent : CharacterBody2D
|
|||||||
{
|
{
|
||||||
return false;
|
return false;
|
||||||
}
|
}
|
||||||
if (_navigationAgent == null) return true;
|
return true;
|
||||||
return _navigationAgent.IsNavigationFinished();
|
|
||||||
}
|
}
|
||||||
|
|
||||||
/// <summary>
|
/// <summary>
|
||||||
@ -515,16 +435,6 @@ public partial class CampusStudent : CharacterBody2D
|
|||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
/// <summary>
|
|
||||||
/// 设置导航地图
|
|
||||||
/// </summary>
|
|
||||||
/// <param name="map">地图RID</param>
|
|
||||||
public void SetNavigationMap(Rid map)
|
|
||||||
{
|
|
||||||
// 由校园控制器传入导航地图,供本地边界夹紧使用
|
|
||||||
_navigationMap = map;
|
|
||||||
}
|
|
||||||
|
|
||||||
/// <summary>
|
/// <summary>
|
||||||
/// 应用随机主题
|
/// 应用随机主题
|
||||||
/// </summary>
|
/// </summary>
|
||||||
@ -572,7 +482,7 @@ public partial class CampusStudent : CharacterBody2D
|
|||||||
/// </summary>
|
/// </summary>
|
||||||
private void AdvanceTarget()
|
private void AdvanceTarget()
|
||||||
{
|
{
|
||||||
if (_patrolPoints.Count == 0 || _navigationAgent == null) return;
|
if (_patrolPoints.Count == 0) return;
|
||||||
if (_behaviorControlEnabled) return;
|
if (_behaviorControlEnabled) return;
|
||||||
|
|
||||||
// 避免当前点过近导致原地抖动,最多尝试一轮
|
// 避免当前点过近导致原地抖动,最多尝试一轮
|
||||||
@ -582,40 +492,12 @@ public partial class CampusStudent : CharacterBody2D
|
|||||||
_patrolIndex = (_patrolIndex + 1) % _patrolPoints.Count;
|
_patrolIndex = (_patrolIndex + 1) % _patrolPoints.Count;
|
||||||
if (GlobalPosition.DistanceTo(target) > TargetReachDistance * 1.5f)
|
if (GlobalPosition.DistanceTo(target) > TargetReachDistance * 1.5f)
|
||||||
{
|
{
|
||||||
_currentTarget = target;
|
BeginGridTarget(target);
|
||||||
_hasTarget = true;
|
|
||||||
_navigationAgent.TargetPosition = target;
|
|
||||||
_stuckTimer = 0.0f;
|
|
||||||
return;
|
return;
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
_currentTarget = _patrolPoints[_patrolIndex];
|
BeginGridTarget(_patrolPoints[_patrolIndex]);
|
||||||
_hasTarget = true;
|
|
||||||
_navigationAgent.TargetPosition = _currentTarget;
|
|
||||||
_stuckTimer = 0.0f;
|
|
||||||
}
|
|
||||||
|
|
||||||
/// <summary>
|
|
||||||
/// 计算避让速度时的回调
|
|
||||||
/// </summary>
|
|
||||||
/// <param name="safeVelocity">安全速度</param>
|
|
||||||
private void OnVelocityComputed(Vector2 safeVelocity)
|
|
||||||
{
|
|
||||||
if (_phoneExitLocked)
|
|
||||||
{
|
|
||||||
Velocity = Vector2.Zero;
|
|
||||||
if (_usePhysicsMovement)
|
|
||||||
{
|
|
||||||
MoveAndSlide();
|
|
||||||
}
|
|
||||||
return;
|
|
||||||
}
|
|
||||||
// 使用安全速度移动,避免与其它角色硬碰硬卡住
|
|
||||||
Velocity = ClampVelocityToNavMesh(safeVelocity);
|
|
||||||
ApplyMovement(_lastDelta);
|
|
||||||
UpdateFacingAnimation(Velocity);
|
|
||||||
UpdateStuckTimer(_lastDelta);
|
|
||||||
}
|
}
|
||||||
|
|
||||||
/// <summary>
|
/// <summary>
|
||||||
@ -652,20 +534,11 @@ public partial class CampusStudent : CharacterBody2D
|
|||||||
{
|
{
|
||||||
if (!_hasTarget) return;
|
if (!_hasTarget) return;
|
||||||
|
|
||||||
if (UseGridPathfinding)
|
_gridPathActive = false;
|
||||||
{
|
_gridPathPending = true;
|
||||||
_gridPathActive = false;
|
_gridPathIndex = 0;
|
||||||
_gridPathPending = true;
|
_gridPath.Clear();
|
||||||
_gridPathIndex = 0;
|
TryBuildPendingGridPath();
|
||||||
_gridPath.Clear();
|
|
||||||
TryBuildPendingGridPath();
|
|
||||||
return;
|
|
||||||
}
|
|
||||||
|
|
||||||
if (_navigationAgent == null) return;
|
|
||||||
|
|
||||||
// 重新请求到同一目标点的路径,避免“固定时间换目的地”
|
|
||||||
_navigationAgent.TargetPosition = _currentTarget;
|
|
||||||
}
|
}
|
||||||
|
|
||||||
/// <summary>
|
/// <summary>
|
||||||
@ -673,9 +546,8 @@ public partial class CampusStudent : CharacterBody2D
|
|||||||
/// </summary>
|
/// </summary>
|
||||||
private void TryBuildPendingGridPath()
|
private void TryBuildPendingGridPath()
|
||||||
{
|
{
|
||||||
if (!UseGridPathfinding || !_gridPathPending) return;
|
if (!_gridPathPending) return;
|
||||||
if (_gridPathRetryTimer > 0.0f) return;
|
if (_gridPathRetryTimer > 0.0f) return;
|
||||||
if (!IsNavigationMapReady()) return;
|
|
||||||
|
|
||||||
var path = BuildGridPath(GlobalPosition, _currentTarget);
|
var path = BuildGridPath(GlobalPosition, _currentTarget);
|
||||||
if (path == null || path.Count == 0)
|
if (path == null || path.Count == 0)
|
||||||
@ -695,59 +567,6 @@ public partial class CampusStudent : CharacterBody2D
|
|||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
/// <summary>
|
|
||||||
/// 导航地图是否准备就绪
|
|
||||||
/// </summary>
|
|
||||||
/// <returns>准备就绪返回true</returns>
|
|
||||||
private bool IsNavigationMapReady()
|
|
||||||
{
|
|
||||||
return _navigationMap.IsValid && NavigationServer2D.MapGetIterationId(_navigationMap) > 0;
|
|
||||||
}
|
|
||||||
|
|
||||||
/// <summary>
|
|
||||||
/// 将速度限制在导航网格内
|
|
||||||
/// </summary>
|
|
||||||
/// <param name="velocity">目标速度</param>
|
|
||||||
/// <returns>限制后的速度</returns>
|
|
||||||
private Vector2 ClampVelocityToNavMesh(Vector2 velocity)
|
|
||||||
{
|
|
||||||
if (!IsNavigationMapReady()) return velocity;
|
|
||||||
if (_lastDelta <= 0.0) return velocity;
|
|
||||||
|
|
||||||
// 预测下一帧位置,若偏离导航网格过远则夹回网格内
|
|
||||||
var candidate = GlobalPosition + velocity * (float)_lastDelta;
|
|
||||||
var closest = NavigationServer2D.MapGetClosestPoint(_navigationMap, candidate);
|
|
||||||
if (closest.DistanceTo(candidate) > NavMeshClampDistance)
|
|
||||||
{
|
|
||||||
var corrected = closest - GlobalPosition;
|
|
||||||
if (corrected.LengthSquared() < 0.01f)
|
|
||||||
{
|
|
||||||
return Vector2.Zero;
|
|
||||||
}
|
|
||||||
return corrected / (float)_lastDelta;
|
|
||||||
}
|
|
||||||
|
|
||||||
return velocity;
|
|
||||||
}
|
|
||||||
|
|
||||||
/// <summary>
|
|
||||||
/// 将目标点限制在导航网格内
|
|
||||||
/// </summary>
|
|
||||||
/// <param name="target">目标点</param>
|
|
||||||
/// <returns>限制后的目标点</returns>
|
|
||||||
private Vector2 ClampTargetToNavMesh(Vector2 target)
|
|
||||||
{
|
|
||||||
if (!IsNavigationMapReady()) return target;
|
|
||||||
|
|
||||||
var closest = NavigationServer2D.MapGetClosestPoint(_navigationMap, target);
|
|
||||||
if (closest.DistanceTo(target) <= 0.01f)
|
|
||||||
{
|
|
||||||
return target;
|
|
||||||
}
|
|
||||||
|
|
||||||
return closest;
|
|
||||||
}
|
|
||||||
|
|
||||||
/// <summary>
|
/// <summary>
|
||||||
/// 应用移动
|
/// 应用移动
|
||||||
/// </summary>
|
/// </summary>
|
||||||
@ -875,7 +694,7 @@ public partial class CampusStudent : CharacterBody2D
|
|||||||
if (_gridPathIndex >= _gridPath.Count)
|
if (_gridPathIndex >= _gridPath.Count)
|
||||||
{
|
{
|
||||||
Velocity = Vector2.Zero;
|
Velocity = Vector2.Zero;
|
||||||
if (!EnableAvoidance && _usePhysicsMovement)
|
if (_usePhysicsMovement)
|
||||||
{
|
{
|
||||||
MoveAndSlide();
|
MoveAndSlide();
|
||||||
}
|
}
|
||||||
@ -885,6 +704,7 @@ public partial class CampusStudent : CharacterBody2D
|
|||||||
PlayIdleAnimation();
|
PlayIdleAnimation();
|
||||||
}
|
}
|
||||||
UpdateStuckTimer(delta);
|
UpdateStuckTimer(delta);
|
||||||
|
_gridPathActive = false;
|
||||||
return true;
|
return true;
|
||||||
}
|
}
|
||||||
|
|
||||||
@ -903,18 +723,6 @@ public partial class CampusStudent : CharacterBody2D
|
|||||||
|
|
||||||
var axisVelocity = ToAxisVelocity(toNext);
|
var axisVelocity = ToAxisVelocity(toNext);
|
||||||
var step = axisVelocity * MoveSpeed * (float)delta;
|
var step = axisVelocity * MoveSpeed * (float)delta;
|
||||||
var candidate = GlobalPosition + step;
|
|
||||||
if (!IsWorldWalkable(candidate))
|
|
||||||
{
|
|
||||||
Velocity = Vector2.Zero;
|
|
||||||
if (!EnableAvoidance && _usePhysicsMovement)
|
|
||||||
{
|
|
||||||
MoveAndSlide();
|
|
||||||
}
|
|
||||||
RepathToCurrentTarget();
|
|
||||||
UpdateStuckTimer(delta);
|
|
||||||
return true;
|
|
||||||
}
|
|
||||||
|
|
||||||
Velocity = step / (float)delta;
|
Velocity = step / (float)delta;
|
||||||
ApplyMovement(delta);
|
ApplyMovement(delta);
|
||||||
@ -1024,24 +832,4 @@ public partial class CampusStudent : CharacterBody2D
|
|||||||
return simplified;
|
return simplified;
|
||||||
}
|
}
|
||||||
|
|
||||||
/// <summary>
|
|
||||||
/// 世界坐标是否可行走
|
|
||||||
/// </summary>
|
|
||||||
/// <param name="world">世界坐标</param>
|
|
||||||
/// <returns>如果可行走返回true</returns>
|
|
||||||
private bool IsWorldWalkable(Vector2 world)
|
|
||||||
{
|
|
||||||
if (!IsNavigationMapReady()) return false;
|
|
||||||
var closest = NavigationServer2D.MapGetClosestPoint(_navigationMap, world);
|
|
||||||
return closest.DistanceTo(world) <= GetGridTolerance();
|
|
||||||
}
|
|
||||||
|
|
||||||
/// <summary>
|
|
||||||
/// 获取网格容差
|
|
||||||
/// </summary>
|
|
||||||
/// <returns>网格容差</returns>
|
|
||||||
private float GetGridTolerance()
|
|
||||||
{
|
|
||||||
return Mathf.Max(1.0f, GridWalkableTolerance);
|
|
||||||
}
|
|
||||||
}
|
}
|
||||||
|
|||||||
Loading…
Reference in New Issue
Block a user