I have an NPC that is capable of opening doors. The only problem is, most of the time the door is shut, therefore blocking a path to the player. How would I get the pathfinding algorithm to ignore the doors?
Maybe split the path into smaller paths, with the NPC halting just before the doors, opening them, then continuing?
You could maybe create a table with all of the doors in it and every time your pathfindig system runs, loop through the table to check that you arenāt counting a door block?
Iām not sure what algorithm youāre using or how youāve implemented it so this might not work at all.
Iāll give my usual pathfinding response: write your own pathfinder. It is rather trivial once youāve built one to not include some parts or add a check to see if a condition is met and if not factor in the time to make that condition true. (Possibly requiring a trip to go grab a key, waiting for another NPC with the key, or taking a moment to open / hack the door.)
Man, that seems like a pretty daunting task. I remember a post about someone doing it and some weird things came up like āA*ā. Do you have any potential resources I could use?
A* is a type of path finding algorithm. There are many tutorials for implementing this in other languages that Iām sure you could easily convert to Roblox. Iām also fairly sure that there is an A* tutorial on the wiki.
For pathfinding algorithms, Wikipedia is often surprisingly useful. Most of the time it provides pseudo code that can be used to make a robust system.
(This is some fairly simple pseudo code I found on A*)
Experiment and see what suits you best. A* is just one of a few pathfinding algorithms. See which one works best for you.
What kind are there that can be implemented in roblox other than A*? Iām kind of looking for the best performance.
Maybe you can try making the doors local models instead of being server sided? That way the NPC will completely ignore them but will still be visible to players, and then just fire a remote event that opens the door on the client side.
Thisāll be a multiplayer game. Iāve also settled to omit the feature until I can finish my A* pathfinding.
I wrote an example A* implementation that just needs to be filled in with a couple of your game-specific details here:
Youāll find the that code has variables with āRoomā in their names. This can be simply replaced by āNodeā or any other object that is connected to other objects to form any graph. It is intentionally implemented in a way to require the game author to fill in the details for the specific type of object they use.
For simplicity Iāll post the code here:
-- Returns the room that the point is in. This point will often be
-- a character's humanoid root part position.
local function getRoom(point)
end
-- Returns a table. Each key is a room adjacent to the given room,
-- an the value is the cost of walking from one room to another.
-- You can use the straight line distance between room centers
-- for a rough estimate.
local function getAdj(room)
end
-- Returns a number, the minimum cost it will take to get to a point.
-- The more accurate, the faster the algorithm will run. Overestimating
-- will make A* not always find the minimum path. When in doubt, the
-- straight line distance can be used.
local function getDistance(room, gRoom)
end
local function getMin(list)
local minKey, minVal = next(list)
for key, val in next, list, minKey do
if val < minVal then
minKey = key
minVal = val
end
end
return minKey
end
local function getPath(start, goal)
local sRoom = getRoom(start)
local gRoom = getRoom(goal)
local fringe = {[sRoom] = getDistance(sRoom, gRoom)}
local closed = {}
local ancestry = {}
local costsToGoal = {[sRoom] = fringe[sRoom]}
local costsToStart = {[sRoom] = 0}
local curRoom = sRoom
while curRoom ~= gRoom do
closed[curRoom] = fringe[curRoom]
fringe[curRoom] = nil
for adjRoom, addCost in next, getAdj(curRoom) do
local newCost = costsToStart[curRoom] + addCost
local curCost = costsToStart[adjRoom]
if closed[adjRoom] then
elseif curCost then
if newCost < curCost then
ancestry[adjRoom] = curRoom
costsToStart[adjRoom] = newCost
fringe[adjRoom] = newCost + costsToGoal[adjRoom]
end
else
ancestry[adjRoom] = curRoom
costsToStart[adjRoom] = newCost
costsToGoal[adjRoom] = getCost(adjRoom, gRoom)
fringe[adjRoom] = newCost + costsToGoal[adjRoom]
end
end
curRoom = getMin(fringe)
if curRoom == nil then
curRoom = getMin(costsToGoal)
-- or getMin(closed) to account for travel time to there
break
end
end
local path = {}
while curRoom do
path[#path + 1] = curRoom
curRoom = ancestry[curRoom]
end
-- [1] is closest to the goal, [#path] is close to start
return path
end
I have a semi solution if you donāt want to use the above.
Using that and combining it with pathfinding you can make a brick appear āWalkableā for the bot.
You could also use a node for doors to be scripted and do it manually.