How do I use request_path?

Place to get help with not working mods / modding interface.
brainwave0
Manual Inserter
Manual Inserter
Posts: 1
Joined: Thu Feb 09, 2023 4:51 am
Contact:

How do I use request_path?

Post by brainwave0 »

I'm trying to make a simple mod where the character walks to wherever I click on the map. I'm using request_path for pathfinding, but it keeps giving me paths through things that the character can't walk through, like in this screenshot:

Screenshot from 2023-02-08 21-36-36.png
Screenshot from 2023-02-08 21-36-36.png (870.21 KiB) Viewed 1423 times

Also, some of the paths seem to go the long way to reach the destinations, rather than taking more direct routes. What I'm getting hung up on is this field collision_mask that I'm supposed to pass to request_path. I'm not sure what values to use. None of the combinations I've tried have worked.

Here is my code:

Code: Select all

character_is_moving = false
path_index = 1
path = nil

-- Determines which direction the character should go.
local function get_direction(start_position, end_position)
    local angle = math.atan2(end_position.y - start_position.y, start_position.x - end_position.x)

    -- Given a circle representing the angles, it is divided into eight octants representing the cardinal directions.
    local octant = (angle + math.pi) / (2 * math.pi) * 8 + 0.5

    if octant < 1 then
        return defines.direction.east
    elseif octant < 2 then
        return defines.direction.northeast
    elseif octant < 3 then
        return defines.direction.north
    elseif octant < 4 then
        return defines.direction.northwest
    elseif octant < 5 then
        return defines.direction.west
    elseif octant < 6 then
        return defines.direction.southwest
    elseif octant < 7 then
        return defines.direction.south
    else
        return defines.direction.southeast
    end
end

function positions_approximately_equal(a, b)
    return math.abs(a.x - b.x) < 0.25 and math.abs(a.y - b.y) < 0.25
end

-- Requests a path when the map is clicked.
script.on_event("mouse-click", function (event)
    local surface = game.get_surface("nauvis")
    local character = game.get_player(1).character
    surface.request_path{
        bounding_box = character.bounding_box,
        collision_mask = character.prototype.collision_mask,
        start = character.position,
        goal = event.cursor_position,
        force = "player"
    }
end)

-- Initializes the movement process when the path is received.
script.on_event(defines.events.on_script_path_request_finished, function (event)
    character_is_moving = true
    path = event.path
    path_index = 1
end)

-- Moves the character.
script.on_event(defines.events.on_tick, function (event)
    local character = game.get_player(1).character
    if character_is_moving and path ~= nil then
        if positions_approximately_equal(character.position, path[path_index].position) then
            -- waypoint reached
            path_index = path_index + 1  -- select the next waypoint
        end

        if path_index == #path then
            character_is_moving = false
            path_index = 1
        else
            -- move the character for one tick
            game.get_player(1).walking_state = {
                walking = true,
                direction = get_direction(character.position, path[path_index].position)
            }
        end
    end
end)
Does anyone have an idea as to why this does not work?
User avatar
boskid
Factorio Staff
Factorio Staff
Posts: 3273
Joined: Thu Dec 14, 2017 6:56 pm
Contact:

Re: How do I use request_path?

Post by boskid »

Core of the problem is due to `bounding_box` you are giving to the request_path. LuaEntity::bounding_box gives you a bounding box which is centered around the entity's position and that is most likely far away from the {0,0} position. The request_path needs a bounding_box which is centered at {0,0} because it is moving this bounding box on its own to the check positions based on the pathfinder nodes. If this bounding box is already shifted, then the path you get is correct but the passable tiles are shifted in the opposite direction than the character's position relative to {0,0}.
Attachments
105167.png
105167.png (440.96 KiB) Viewed 1410 times
PFQNiet
Filter Inserter
Filter Inserter
Posts: 289
Joined: Sat Sep 05, 2020 7:48 pm
Contact:

Re: How do I use request_path?

Post by PFQNiet »

I think character.prototype.bounding_box should work, right?

But aside from that your code is prone to issues in a multiplayer setting, since you've hardcoded "player 1" in there. You should instead do game.players[event.player_index], and you should also be checking that objects exist and are valid before you try to use them.
rawls
Manual Inserter
Manual Inserter
Posts: 3
Joined: Tue May 30, 2023 2:46 am
Contact:

Re: How do I use request_path?

Post by rawls »

Did you ever figure this out? I'm having the same problem were request path generates a path over water for the player.
User avatar
boskid
Factorio Staff
Factorio Staff
Posts: 3273
Joined: Thu Dec 14, 2017 6:56 pm
Contact:

Re: How do I use request_path?

Post by boskid »

rawls wrote: Wed May 31, 2023 1:01 am Did you ever figure this out? I'm having the same problem were request path generates a path over water for the player.
Given the other topic (106448) you opened while cross posting here, i will give you an answer here for the part related to this topic: Your problem is related to usage of character's current bounding box which is shifted by the characters position while your expectation of having path with nodes not over water means you want to pass a bounding box which is centered at {0,0} position. Fix here is identical, use LuaEntityPrototype::collision_box from the entity's prototype since that one is not shifted.
Post Reply

Return to “Modding help”