You need to enable JavaScript to run this app.
优惠活动
大模型
产品
解决方案
定价
更多

Godot Navigation2D.GetSimplePath()返回异常路径问题求助

Godot C#开发中Navigation2D.GetSimplePath寻路结果偏移问题

问题现象

使用Godot引擎进行C#游戏开发时,调用Navigation2D.GetSimplePath方法实现敌人发现玩家后的自动追击寻路逻辑。按照预期,传入起止坐标后该方法应返回存储敌人位置到玩家位置导航路径的Vector2数组,但实际运行时敌人移动方向与预期完全偏离。

已尝试的排查方案

  • 最初直接传入敌人与玩家的Position坐标作为寻路起止点,代码如下:
var from = Enemy.Position;
var to = PlayerRef.Position;
// Nav为场景中挂载的Navigation2D节点
var paths = Nav.GetSimplePath(from, to); 
Enemy.Status.NavPath = new Stack<Vector2>(paths);

运行后得到错误寻路结果,猜测是坐标空间不匹配,尝试将起止点转换为Navigation2D节点下的本地坐标:

// Nav为场景中挂载的Navigation2D节点
var from = Nav.ToLocal(Enemy.GlobalPosition);
var to = Nav.ToLocal(PlayerRef.GlobalPosition);

后续多次测试不同节点间全局坐标与本地坐标的转换组合,均返回错误寻路结果,多日排查未定位到明显疏漏。

补充说明:该问题仅在代码重构后出现,重构前所有寻路逻辑耦合在单个敌人类中时可正常运行。

当前追击逻辑完整代码

using Godot;
using ThemedHorrorJam5.Scripts.Enum;
using ThemedHorrorJam5.Scripts.Patterns.StateMachine;
using ThemedHorrorJam5.Scripts.GDUtils;
using System.Collections.Generic;
using System.Linq;

namespace ThemedHorrorJam5.Entities
{
    public class ChaseEnemyState : State
    {
        private Navigation2D? GetLevelNavigation()
        {
            var nodeTuples = Enemy.GetTree().GetNavigation2dNodes();
            if (nodeTuples.Item1) return nodeTuples.Item2[0];
            return null;
        }

        private Navigation2D Nav { get; set; }
        private EnemyV4 Enemy { get; set; }
        private PlayerV2 PlayerRef { get; set; }

        public ChaseEnemyState(EnemyV4 enemy)
        {
            this.Name = EnemyBehaviorStates.ChasePlayer.GetDescription();
            Enemy = enemy;
            (var hasPlayer, PlayerRef) = Enemy.GetTree().GetPlayerNode();
            if (!hasPlayer)
            {
                Logger.Error("Player ref not found on scene tree");
            }

            (var hasNav, var navNodes) = Enemy.GetTree().GetNavigation2dNodes();
            if (hasNav && navNodes != null)
            {
                Nav = navNodes[0];
            }

            this.OnEnter += () => this.Logger.Debug("ChaseEnemyState OnEnter called");
            this.OnExit += () => this.Logger.Debug("ChaseEnemyState Exit called");
            this.OnFrame += ChasePlayer;
        }

        private void ChasePlayer(float delta)
        {
            if (Enemy.IsDebugging && Enemy.HasNode("Line2D"))
            {
                Enemy.Status.Line = (Line2D)Enemy.GetNode("Line2D");
            }
            if (Nav!=null)
            {
                var from = Nav.ToLocal(Enemy.GlobalPosition);
                var to = Nav.ToLocal(PlayerRef.GlobalPosition);
                var paths = Nav.GetSimplePath(from, to);
                Enemy.Status.NavPath = new Stack<Vector2>(paths);

                if (Enemy.Status.Line != null)
                {
                    Enemy.Status.Line.Points = Enemy.Status.NavPath.ToArray();
                }

                var distance_to_walk = Enemy.MoveSpeed * delta;

                while (distance_to_walk > 0f && Enemy.Status.NavPath.Count > 0f)
                {
                    var distance_to_next_point = Enemy.Position.DistanceTo(Enemy.Status.NavPath.Peek());
                    if (distance_to_walk <= distance_to_next_point)
                    {
                        var newPosition = Enemy.Position.DirectionTo(Enemy.Status.NavPath.Peek()) * distance_to_walk;
                        Enemy.Status.VisionManager.UpdateFacingDirection(newPosition.Normalized());
                        Enemy.Position += newPosition;
                    }
                    else
                    {
                        var newPosition = Enemy.Status.NavPath.Pop();
                        Enemy.Status.VisionManager.UpdateFacingDirection(newPosition.Normalized());
                        if (Enemy.GetSlideCount() > 0)
                        {
                            Enemy.HandleMovableObstacleCollision(newPosition);
                        }
                        Enemy.Position = newPosition;
                    }
                    distance_to_walk -= distance_to_next_point;
                }
            }
            else
            {
                Logger.Error("Navigation2D not found");
            }
            if (Enemy.Status.CurrentCoolDownCounter > 0)
            {
                Enemy.Status.CurrentCoolDownCounter -= delta;
            }
        }
    }
}

附加排查材料

已提供运行效果截图辅助说明问题:图中绿色标识为玩家,蓝色标识为敌人,调试变量from、to为寻路传入的起止坐标,黄色区域为敌人视野锥,指向敌人当前移动方向,Target为玩家节点别名,红色线条为通过Line2D绘制的敌人寻路路径,同时提供了测试关卡、敌人场景的结构截图,寻求问题排查指引。


内容的提问来源于stack exchange,提问作者Terrance

相关产品推荐
方舟 Agent Plan

超全模态模型 × Harness 升级,最新支持 Deepseek-V4.1-Flash、GLM-5.3 系列、Doubao-Seedream-5.0-pro、Kimi-K3 (部分), 限时 9.9 元起

最近更新时间:2026.08.30 14:42:24