无效的获取索引'1'(基于:'Array')GODOT路径查找

Invalid get index '1' (on base: 'Array') GODOT path finding

我正在尝试制作一只跟随附加到角色的 Position2D 节点的鸟。(Position2D 节点位于名为 birdpos 的组中)当我 运行 鸟出现在屏幕上时(screendetector) 它转到 Position2D 节点。然而,一旦它到达目的地,它就会给我错误消息“无效的获取索引'1'(基于:'Array')。” (当它到达位置时我也会抖动)我相信这是一个简单的修复,这是我的代码

extends KinematicBody2D
export(int) var SPEED: int = 100
var velocity: Vector2 = Vector2.ZERO

var path: Array = []
var levelNavigation: Navigation2D = null
var birdpos = null
onready var line2d = $Line2D #shows pathing
func _ready():
    var tree = get_tree()
    $flyingsprite1/AnimationPlayer.play("flying")
    if tree.has_group("LevelNavigation"):
        levelNavigation = tree.get_nodes_in_group("LevelNavigation")[0]



func move():
    velocity = move_and_slide(velocity)






func _on_screenchecker_area_entered(area):
    $Timer.start()
    print("ligma")
    yield(get_tree(), "idle_frame")
    var tree = get_tree()
    if tree.has_group("LevelNavigation"): #navigation node
        levelNavigation = tree.get_nodes_in_group("LevelNavigation")[0]
    if tree.has_group("birdpos"): #Position2D that is attached to player
        birdpos = tree.get_nodes_in_group("birdpos")[0]


func _on_screenchecker_area_exited(area):
    print("liga")
    $Timer.stop()
    var birdpos = null
    var levelNavigation: Navigation2D = null
    
    
func _on_Timer_timeout():
    line2d.global_position = Vector2.ZERO
    if birdpos and levelNavigation:
        generate_path()
        
        
func _physics_process(delta):
    if Global.player.facing_right == true:
        $flyingsprite1.scale.x = -1
    else:
        $flyingsprite1.scale.x = 1
    if birdpos and levelNavigation:
        navigate()
    move()
    
    

func generate_path():
    if levelNavigation != null and birdpos != null:
        path = levelNavigation.get_simple_path(global_position, birdpos.global_position, false)
        line2d.points = path

func navigate():
    if path.size() > 0:
        velocity = global_position.direction_to(path[1]) * SPEED
        if global_position == path[0]:
            path.pop_front()

编辑:更新代码

extends KinematicBody2D
export(int) var SPEED: int = 200
var velocity: Vector2 = Vector2.ZERO
var path: Array = []
var levelNavigation: Navigation2D = null
var birdpos = null
onready var line2d = $Line2D

func _ready():
    # speed is distance over time
    
    var tree = get_tree()
    $flyingsprite1/AnimationPlayer.play("flying")
    #if tree.has_group("Player"):
        #player = tree.get_nodes_in_group("Player")[0]












func _on_screenchecker_area_exited(area):
    $Timer.stop()
    var birdpos = null
    var levelNavigation: Navigation2D = null
    
    
func _on_Timer_timeout():
    line2d.global_position = Vector2.ZERO
    if birdpos and levelNavigation:
        generate_path()
        
func _physics_process(delta):
    if path.size() == 0:
        return
        var levelNavigation: Navigation2D = null
        var birdpos = null
        var next := global_position.move_toward(path[0], SPEED * delta)
    
        var displacement := next - global_position
        # And divide by it delta to get velocity:
        move_and_slide(displacement/delta)
    if Global.player.facing_right == true:
        $flyingsprite1.scale.x = -1
    else:
        $flyingsprite1.scale.x = 1
    if birdpos and levelNavigation:
        navigate()
    move()
func _input(event):
    if Input.is_key_pressed(KEY_Q):
        var tree = get_tree()
        
func _on_screenchecker_area_entered(area):
    $Timer.start()
    yield(get_tree(), "idle_frame")
    var tree = get_tree()
    if tree.has_group("LevelNavigation"):
        levelNavigation = tree.get_nodes_in_group("LevelNavigation")[0]
    if tree.has_group("birdpos"):
        birdpos = tree.get_nodes_in_group("birdpos")[0]
    

func generate_path():
    if levelNavigation != null and birdpos != null:
        if is_instance_valid(birdpos):
            path = levelNavigation.get_simple_path(global_position, birdpos.global_position, false)
            line2d.points = path
func navigate():
    if path.size() > 1:
        velocity = global_position.direction_to(path[1]) * SPEED
    if path.size() == 0:
        path.pop_front()
        

    

func move():
    if path.size() == 0:
        return
    velocity = move_and_slide(velocity)
    




    
    
        

错误

在此代码中:

    if path.size() > 0:
        velocity = global_position.direction_to(path[1]) * SPEED
        if global_position == path[0]:
            path.pop_front()

你检查 pathpath.size() > 0 的得分是否超过 0。也就是说,您正在检查 path 是否至少有 1 个点。

但要访问path[1],路径必须至少有2个点。

因此,如果path刚好有1点,它将通过检查path.size() > 0,而在读取path[1]时失败。

我不知道路径什么时候正好有一个点。 没有记录这是如何发生的,这可能是导航的问题,甚至可能是 Godot 中的错误。但是,据我所知,它正在发生你.

大概您想要达到 path[0] 而不是 path[1],因为这是您要检查的移除点数。

如果您确实想要 path[1],则检查路径是否至少有 2 个点 path.size() > 1(或 path.size() >= 2,如果您愿意)。


抖动

我在这里假设 path[0] 是目标。

我认为是三件事:

  • 你不能相信向量相等

    向量相等归结为分量相等。这是浮动平等。因此 Vector 相等性具有 float 相等性的所有问题。

    因此,要与您当前的目标进行比较,请使用 is_equal_approx。例如 global_position.is_equal_approx(path[0]).

  • 达到目标就不想动了

    这很简单:如果 path 中没有更多点,请不要移动。也就是说,你可以在 move:

    的开头添加这个
    if path.size() == 0:
        return
    

    如果你的代码在_physics_process而不是move,记得检查那里。

  • 你不想超调

    因此,move_and_slide 将根据物理帧之间的时间 (delta) 尽可能多地移动对象。但这可能超出了实现目标的必要性。因此,它很可能会超过目标。结果,下一个物理框架它必须向相反的方向移动,并再次超调,等等……抖动!

    我给你三个解决方案:

    1. 不要使用 move_and_slide(注意您将放弃物理碰撞):

      # you can use move_toward
      global_position = global_position.move_toward(path[0], SPEED * delta)
      
    2. 让我们保持move_and_slide,但计算我们想要的位移。

      # you can use move_toward
      var next := global_position.move_toward(path[0], SPEED * delta)
      # Then compute the displacement
      var displacement := next - global_position
      # And divide by it delta to get velocity:
      move_and_slide(displacement/delta)
      
    3. 再次使用move_and_slide,但这次我们计算出不超过的最大速度:

      # speed is distance over time
      var max_speed := global_position.distance_to(path[0])/delta
      # And we clamp!
      move_and_slide(velocity.clamped(max_speed))
      

    对于使用 delta 的代码版本,您可以将代码放在 _physics_process 中,或者将 delta 传递给 move 作为一个参数。也不要忘记检查前面提到的 path.size()


附录 如果你使用 path[0] 作为目标,但它等于当前位置,你将获得几乎没有速度,并且不得不浪费一个物理框架.考虑这个重写:

    if path.size() > 0 and global_position.is_equal_approx(path[0]):
        path.pop_front()

    if path.size() > 0:
        velocity = global_position.direction_to(path[0]) * SPEED