Yeah, that's what I'd do - make a grid and flag each part that has an obstacle. I did have an example of that, could upload the code if you like - works incredibly well and has the added benefit that if enemies are going to the same location, they actually share the work as their fill passes accumulate.
You should check out my codes, it's very minimalist but effective if I do say so myself
sync on : sync rate 0
set text font "arial" : set text size 10
global plx
global plz
global plx#
global plz#
global path_sx=90
global path_sz=90
global paths=51
global npcs=50
global npc_movespd#=0.1
global pl_movespd#=0.1
dim npc_x#(npcs)
dim npc_z#(npcs)
dim npc_dx#(npcs)
dim npc_dz#(npcs)
dim npc_mode(npcs)
dim npc_path(npcs)
dim nodes(path_sx,path_sz,paths)
dim nodes_leak(paths,4)
dim node_movex(9)
dim node_movez(9)
`N=1, Ne=2, E=3, Se=4, S=5, Sw=6, W=7, Nw=8
node_movex(1)=0 : node_movez(1)=0
node_movex(1)=0 : node_movez(1)=1
node_movex(2)=1 : node_movez(2)=1
node_movex(3)=1 : node_movez(3)=0
node_movex(4)=1 : node_movez(4)=-1
node_movex(5)=0 : node_movez(5)=-1
node_movex(6)=-1 : node_movez(6)=-1
node_movex(7)=-1 : node_movez(7)=0
node_movex(8)=-1 : node_movez(8)=1
clear_nodes()
random_nodes()
nodes(1,1)=0
nodes(2,1)=0
nodes(3,1)=0
nodes(4,1)=0
nodes(5,1)=0
nodes(6,1)=0
plx=1 : plx#=1.5
plz=1 : plz#=1.5
ink rgb(255,255,255),0
cls
for z=0 to path_sx-1
for x=0 to path_sx-1
if nodes(x,z,0)=-1 then box x*8,z*8,(x*8)+7,(z*8)+7
next x
next z
text 400,0,"Press shift to show values."
text 400,20,"Press Space to find player values."
text 400,40,"Arrow keys to move."
get image 1,0,0,screen width(),screen height()
ink rgb(255,0,0),0
`make some random npc's
for npc=0 to npcs
`Find some floor first
done=0
while done=0
npc_x#(npc)=rnd(path_sx*100.0)/100.0
npc_z#(npc)=rnd(path_sz*100.0)/100.0
if nodes(int(npc_x#(npc)),int(npc_z#(npc)),0)=0 then done=1
endwhile
npc_mode(npc)=0
npc_path(npc)=0
next npc
do
paste image 1,0,0
`spacekey to find player
mode=0
if spacekey()=1
path_start(0,plx,plz)
mode=1
endif
for npc=0 to npcs
`If idle then go wondering
if rnd(20)=1 and npc_mode(npc)=0 then npc_mode(npc)=1 : npc_path(npc)=-1
`Finding player?
if mode=1
npc_mode(npc)=1
npc_path(npc)=0
npc_dx#(npc)=plx+0.5
npc_dz#(npc)=plz+0.5
endif
npc_ai(npc)
next npc
`Show the node values
if shiftkey()=1 then display_nodes()
oplx#=plx#
oplz#=plz#
dec plx#,(leftkey()-rightkey())*pl_movespd#
dec plz#,(upkey()-downkey())*pl_movespd#
plx=plx#
plz=plz#
oplx=oplx#
oplz=oplz#
`sliding collision
if nodes(plx,plz,0)=-1
if nodes(oplx,plz,0)=-1 then plz#=oplz# : plz=oplz
if nodes(plx,oplz,0)=-1 then plx#=oplx# : plx=oplx
endif
ink rgb(255,255,0),0
box (plx#*8)-3,(plz#*8)-3,(plx#*8)+3,(plz#*8)+3
sync
loop
function clear_nodes()
for zz=0 to (path_sz-1)
for xx=0 to (path_sx-1)
nodes(xx,zz,0)=0
next xx
next zz
endfunction
function clean_nodes()
for zz=0 to (path_sz-1)
for xx=0 to (path_sx-1)
if nodes(xx,zz,0)>0 then nodes(xx,zz,0)=0
next xx
next zz
endfunction
function display_nodes()
ink rgb(0,0,255),0
for zz=0 to (path_sz-1)
for xx=0 to (path_sx-1)
text xx*8,zz*8,str$(nodes(xx,zz,0))
next xx
next zz
endfunction
function random_nodes()
for zz=0 to (path_sz-1)
for xx=0 to (path_sx-1)
if xx=0 or zz=0 or xx=(path_sx-1) or zz=(path_sz-1) or rnd(5)=1
nodes(xx,zz,0)=-1
endif
next xx
next zz
for zz=2 to (path_sz-2)
for xx=2 to (path_sx-2)
if nodes(xx,zz,0)=0 and nodes(xx+1,zz,0)=-1 and nodes(xx,zz+1,0)=-1 then nodes(xx,zz,0)=-1
if nodes(xx,zz,0)=0 and nodes(xx-1,zz,0)=-1 and nodes(xx,zz+1,0)=-1 then nodes(xx,zz,0)=-1
if nodes(xx,zz,0)=0 and nodes(xx+1,zz,0)=-1 and nodes(xx,zz-1,0)=-1 then nodes(xx,zz,0)=-1
if nodes(xx,zz,0)=0 and nodes(xx-1,zz,0)=-1 and nodes(xx,zz-1,0)=-1 then nodes(xx,zz,0)=-1
next xx
next zz
endfunction
function npc_ai(npc)
npc_x=npc_x#(npc)
npc_z=npc_z#(npc)
ink rgb(255,0,0),0
`Following the path
if npc_mode(npc)=2
ink rgb(0,255,0),0
if nodes(npc_x,npc_z,npc_path(npc))>0 and nodes(npc_x,npc_z,npc_path(npc))<10
onx#=npc_x#(npc)
onz#=npc_z#(npc)
npc_x#(npc)=npc_x#(npc)+(node_movex(nodes(npc_x,npc_z,npc_path(npc)))*npc_movespd#)
npc_z#(npc)=npc_z#(npc)+(node_movez(nodes(npc_x,npc_z,npc_path(npc)))*npc_movespd#)
nx=npc_x#(npc)
nz=npc_z#(npc)
onx=onx#
onz=onz#
if npc_colcheck(npc,nx,nz)=1
if npc_colcheck(npc,onx#,npc_z#(npc))=1 then npc_z#(npc)=onz# : nz=onz
if npc_colcheck(npc,npc_x#(npc),onz#)=1 then npc_x#(npc)=onx# : nx=onx
endif
endif
if nodes(npc_x,npc_z,npc_path(npc))=10 then npc_mode(npc)=0
endif
`Calculating the path - if they're finding the player they work together on path 0
if npc_mode(npc)=1
ink rgb(255,255,0),0
if npc_path(npc)=-1
ink rgb(0,0,255),0
`Find some floor
done=0
while done=0
npc_dx#(npc)=rnd(path_sx*100.0)/100.0
npc_dz#(npc)=rnd(path_sz*100.0)/100.0
if nodes(int(npc_dx#(npc)),int(npc_dz#(npc)),0)<>-1 then done=1
endwhile
path_start(npc+1,int(npc_dx#(npc)),int(npc_dz#(npc)))
npc_path(npc)=npc+1
endif
if nodes(npc_x,npc_z,npc_path(npc))=0
d=path_seek(npc_path(npc))
if d=0 then npc_mode(npc)=1 : npc_path(npc)=-1
else
npc_mode(npc)=2
endif
endif
`Show them and a line for their destination
circle npc_x#(npc)*8,npc_z#(npc)*8,3
ink rgb(64,64,64),0
line npc_x#(npc)*8,npc_z#(npc)*8,npc_dx#(npc)*8,npc_dz#(npc)*8
endfunction
function path_start(layer,x,z)
`First copy layer 0, the actual map array where -1 is a wall and 0 is blank
for zz=0 to (path_sz-1)
for xx=0 to (path_sx-1)
if nodes(xx,zz,0)=-1 then nodes(xx,zz,layer)=-1 else nodes(xx,zz,layer)=0
next xx
next zz
nodes_leak(layer,0)=x
nodes_leak(layer,1)=z
nodes_leak(layer,2)=x
nodes_leak(layer,3)=z
nodes(x,z,layer)=10
endfunction
function path_seek(layer)
done=0
`Expand the leak just a bounding box really to keep things speedy
nodes_leak(layer,0)=nodes_leak(layer,0)-1
nodes_leak(layer,1)=nodes_leak(layer,1)-1
nodes_leak(layer,2)=nodes_leak(layer,2)+1
nodes_leak(layer,3)=nodes_leak(layer,3)+1
`Ensure safe leak size
for axis=0 to 3
if nodes_leak(layer,axis)<1 then nodes_leak(layer,axis)=1
if nodes_leak(layer,axis)>(path_sx-1) then nodes_leak(layer,axis)=path_sx-1
next axis
`Scan the map and look for bits of path
for xx=nodes_leak(layer,0) to nodes_leak(layer,2)
for zz=nodes_leak(layer,1) to nodes_leak(layer,3)
if nodes(xx,zz,layer)=0
`Each direction in turn
for compass=1 to 8
nod=nodes(node_movex(compass)+xx,node_movez(compass)+zz,layer)
if nod>0 and nod<100 then nodes(xx,zz,layer)=compass+100 : done=1
next compass
endif
next zz
next xx
`Now replace the new values with checking values (working 1 border at a time)
for xx=nodes_leak(layer,0) to nodes_leak(layer,2)
for zz=nodes_leak(layer,1) to nodes_leak(layer,3)
if nodes(xx,zz,layer)>100 then nodes(xx,zz,layer)=nodes(xx,zz,layer)-100
next zz
next xx
endfunction done
function npc_colcheck(npc,chkx#,chkz#)
if nodes(int(chkx#),int(chkz#),0)=-1 then exitfunction 1
`test npc to npc collision - disabled as it's not very good
for n=0 to npcs
if n<>npc
npcx#=npc_x#(n)
npcz#=npc_z#(n)
if npcx#>(chkx#-0.5)
if npcx#<(chkx#+0.5)
if npcz#>(chkz#-0.5)
if npcz#<(chkz#+0.5)
`exitfunction 1
endif
endif
endif
endif
endif
next n
endfunction 0
Use the arrow keys to move the yellow box, starts at the top left - then press space and all the nodes will find the yellow box. Nodes that are green are moving, yellow means thinking, and red means stopped. There are tweaks that I would do to it if I had the time, like storing a value to represent the number of moves in each grid - so the destination might start at 1, then adjoining cells would be 2, 3, 4 - but the thing is that when a cell has more than one option for the path, it could use the lowest value. This would make it follow the very shortest path instead of the first workable path it finds.