Search code examples
navigationpath-findinggodot

Limit movement using pathfinding navigation Godot


I want to limit the distance that my character can walk by the number of movements available

As I drag the mouse, a path finding line is drawn showing the path to be followed.when I click, the character follows the path, that is working fine.

How do I limit the distance to the a variable.

Code so far

func _process(delta): # executes the pathfinding
    var direction = Vector3()
    var step_size = delta * SPEED
    if can_move:
        get_parent().get_node("Draw").visible = false
        curr_state = "moving"
        var destination = path[0]
        direction = destination - character.translation
        if step_size > direction.length():
            step_size = direction.length()
            path.remove(0)
        if path.size() <=0:
            can_move = false
            curr_state = "idle"
        character.translation += direction.normalized() * step_size
        print(character.translation.direction_to(destination))
        direction.y = 0
        if direction:
            var look_at_point = character.translation + direction.normalized()
            character.look_at(look_at_point, Vector3.UP)


func _unhandled_input(event): 
    if event is InputEventMouseMotion and curr_state == "idle":
        path = navi.get_simple_path(character.translation, mouse_catcher(event), true)
        draw_path(path, mouse_catcher(event))
        get_parent().get_node("Draw").visible = true
    if event.is_action_pressed("ui_confirm") and curr_state =="idle":
        can_move = true



func mouse_catcher(event):
    var from = $Camera.project_ray_origin(event.position)
    var to = from + $Camera.project_ray_normal(event.position) * 10000
    var target_point = get_parent().get_node("Navi").get_closest_point_to_segment(from, to)
    return target_point


func draw_path(path_array, target_point, visi = true):
    var im = get_parent().get_node("Draw")
    if visi:
        im.visible = true
    else: 
        im.visible = false
    im.set_material_override(m)
    im.clear()
    im.begin(Mesh.PRIMITIVE_POINTS, null)
    im.add_vertex(path_array[0])
    im.add_vertex(path_array[path_array.size() - 1])
    im.end()
    im.begin(Mesh.PRIMITIVE_LINE_STRIP, null)
    print(path_array)
    for x in path:
        im.add_vertex(x)
    im.end()

Solution

  • If you want to limit the character movement

    You have a variable step_size which holds how much the character moved on the frame. You can accumulate them to have how much the character has moved in total:

    character.translation += direction.normalized() * step_size
    total_walked = total_walked + step_size
    

    Declare total_walked with initial value of 0.

    You can check if that total will exceed the amount you want the character to move, and if that is the case, don't move:

    if total_walked + step_size < maximum:
        character.translation += direction.normalized() * step_size
        total_walked = total_walked + step_size
    

    Declare maximum with some value that makes sense for your case.

    And, of course, you would have to reset the accumulated value (total_walked = 0) when you want to allow the character to move again (perhaps you want to change maximum too).


    You may or may not limit the last move to make sure the character moved exactly the maximum:

    if total_walked + step_size >= maximum:
        step_size = maximum - total_walked
    
    character.translation += direction.normalized() * step_size
    total_walked = total_walked + step_size
    

    If you want to limit the length of the path

    The path you get is a list of points. You can iterate over them and get the distance:

    var total:float = 0.0
    for index in path.size() - 1
        var a:Vector3 = path[index]
        var b:Vector3 = path[index + 1]
        var step:float = a.distance_to(b)
        total = total + step
    

    I'm assuming these are Vector3, given that you are raycasting.

    You truncate as soon as that goes over the maximum:

    var total:float = 0.0
    for index in path.size() - 1
        var a:Vector3 = path[index]
        var b:Vector3 = path[index + 1]
        var step:float = a.distance_to(b)
        total = total + step
        if total > maximum:
            path.resize(index)
            break
    

    You may or may not want to insert a point at the end to make sure the distance is exactly the maximum:

    var total:float = 0.0
    for index in path.size() - 1
        var a:Vector3 = path[index]
        var b:Vector3 = path[index + 1]
        var step:float = a.distance_to(b)
        if total + step >= maximum:
            path.resize(index)
            path.append(a + a.direction_to(b) * (maximum - total))
            break
    
        total = total + step