path find in ONE script! (FREE! :D)

perhaps was posted in another section, but here perhaps has more visibility …

4 days is that we work
2 only to realize that I had to put the magic word “list ()” in order to change the list without trouble

I think the underlying mechanism may be one. (I had seen a demo of how it worked 10 years ago in GameMaker)

Blender can not get the pathfinding!
and then I did it! : D

it is true that there were already, but those I have seen work well, but with various objects (a bit inconvenient)
but this is all in a script, you must set it to change only the first lines

is not completely finished, I want to join the variable trackpath and path in a single variable.

There is also a small bug that I can not solve.
I do not know why, in the path to “winning”
Sometimes the last cell is wrong (a cell)

the “trick” is to use the dictionary and record the grid as a text.
the variable “compare” just serves to compare the numbers with the text.

This is the code:

ah…the object must be STATIC (or gravity cause problem of corse)

from bge import logic as BG
from bge import events
    
c = BG.getCurrentController()
o = c.owner
sce=BG.getCurrentScene()



key = BG.keyboard.events
FKEY = key[events.FKEY]

if FKEY==1:
    
    ######################################################################
    ##################---SETUP THIS--#####################################
    OBSTACLE="obstacle" #choose the property must be in to object obstacle
    TARGET=  "target"   #choose the property must be in to object target
    gridx=100
    gridy=100
    direction=4 #(4= NSWE)(8= N S W E NW NE SW SE)
    ######################################################################
    ######################################################################
    
    
    
    
    
    recx=xx=round(o.worldPosition[0])
    recy=yy=round(o.worldPosition[1])
    xstart=xx-(gridx//2)
    ystart=yy-(gridy//2)
    
    gridlimitminx=round(recx-(gridx//2))
    gridlimitmaxx=gridlimitminx+gridx
    gridlimitminy=round(recy-(gridy//2))
    gridlimitmaxy=gridlimitminy+gridy
    
    globalpath={}
    
    
    ########## INIT GRID ############## SIGN ALL CELL LIKE(0)
    for i in range(gridy):
        for i2 in range(gridx):
            globalpath[(str(xx)+"|"+str(yy))]=0         
            #print("globalpath",(str(xx)+"|"+str(yy)))
            xx+=1
            if xx==xstart+(gridx):
                xx=xstart
                yy+=1
                if yy==ystart+gridy:
                    yy=ystart
                    
                    
                    
                    
    ########## SIGN GRID ->OBSTACLE(1)->TARGET(3) ###########

    for i in sce.objects:
        if OBSTACLE in i:
            globalpath[str(round(i.worldPosition[0]))+"|"+str(round(i.worldPosition[1]))]=1
        if TARGET in i:
            globalpath[str(round(i.worldPosition[0]))+"|"+str(round(i.worldPosition[1]))]=3
            dist=o.getDistanceTo(i)

    
    
    ########## INIT PATH (p)
    playerxy=[recx,recy]

    winpath=0
    p=[[]]
    p[0].append(list(playerxy))
    
    compare=str(str(recx)+"|"+str(recy))
    
    
    if dist<max(gridx,gridy) and globalpath[compare]==0:
        globalpath[compare]=1

        exitStrategy=1
        for r in range(gridx*gridy):
            
            if exitStrategy==0:
                break
            
            exitStrategy=0
            cont=len(p)
            for i in range(cont):
                if winpath!=0:
                    break

                if p[i]!="X":
                    lastlast=len(p[i])-1
                    recell=list(p[i][lastlast])
                    foundcell=0
                                        
                    for i4 in range(direction):
                        tryy=list(recell)
                        
                        if direction==4:
                            if i4==0:
                                tryy[1]+=1
                            elif i4==1:
                                tryy[1]-=1
                            elif i4==2:
                                tryy[0]-=1
                            elif i4==3:
                                tryy[0]+=1
                        
                        if direction==8:
                            if i4==0:
                                tryy[1]+=1;
                            elif i4==1:
                                tryy[1]-=1
                            elif i4==2:
                                tryy[0]-=1
                            elif i4==3:
                                tryy[0]+=1
                                
                            elif i4==4:
                                tryy[1]+=1;tryy[0]-=1
                            elif i4==5:
                                tryy[1]-=1;tryy[0]+=1
                            elif i4==6:
                                tryy[0]-=1;tryy[1]-=1
                            elif i4==7:
                                tryy[0]+=1;tryy[1]+=1
                                
                        limitgrid=0
                        if tryy[1]<gridlimitmaxy:
                            if tryy[1]>gridlimitminy:
                                if tryy[0]>gridlimitminx:
                                    if tryy[0]<gridlimitmaxx:
                                        limitgrid=1
                        
                        if limitgrid==0:
                            exitStrategy+=1
                                 
                        if limitgrid==1:
                            compare=str(str(tryy[0])+"|"+str(tryy[1])) 
                            if globalpath[compare]!=1: 
                                exitStrategy+=1
                                if globalpath[compare]==0:
                                    globalpath[compare]=1
                                    foundcell+=1                                       
                                    if foundcell>0:
                                        if foundcell==1:
                                            p[i].append(list(tryy))
                                        if foundcell>1:   
                                            foundcell=1
                                            p.append(list(p[i]))
                                            lastlast=len(p[i])-1
                                            del(p[i][lastlast])
                                            p[i].append(list(tryy))

                                if globalpath[compare]==3:
                                    if foundcell>1:
                                        foundcell=1
                                        lastlast=len(p[i])-1
                                        del(p[i][lastlast])
                                        p[i].append(list(tryy))
                                    
                                    if foundcell==1:
                                        p[i].append(list(tryy))
                                        
                                    winpath=list(p[i])
                                    o["path"]=list(winpath)
                            
                        if i4==direction-1:
                            if foundcell==0: 
                                p[i]="X"     

        print("-----LIGHT DEBUG----")
        if winpath!=0:
            print("")
            print("")
            patvalid=0
            patwrong=0
            for v in p:
                if v =="X":
                    patwrong+=1
            patvalid=len(p)-patwrong
            
            print("-----PATH FOUND-----")
            print("pattotal=     ",len(p))
            print("patvalid=     ",patvalid)
            print("patwrong=     ",patwrong)
            print("path winner-->",o["path"])
            
            if len(p)<100:
                print("     ALL PATH OF  p :",p)
        else:
            print("PATH NO FOUND: situation: ",p)


       
if not "path" in o:
    o["path"]=0
    o["trackpath"]=0
    
if o["path"]!=0:
    tar=o["path"]
    v=o["trackpath"]
    vv=tar[v]
    v=[vv[0],vv[1],o.worldPosition[2]]
    
    vec=o.getVectTo(v)
    o.alignAxisToVect(vec[1],1,0.5)
    o.applyMovement([0,0.2,0],1)
    dist=o.getDistanceTo(v)
    if dist<0.5:
        o["trackpath"]+=1
    if o["trackpath"]>len(tar)-1:
        o["trackpath"]=0
        o["path"]=0
        

"""
DKEY = key[events.DKEY]
if DKEY==1:
    if o["path"]!=0:
        print(v)
"""
    

Regards at all!

You can be proud that you managed this :D.

I want to give you some feedback that crosses my mind while reading this.

You should not expect a user to change code (a general guideline for every code).
It is much better to let the user use the GUI (e.g. configure properties).
You can provide default values in case the user does not setup correctly/completely.

A demo blend would be good for presentation.
Some words on configuration/documentation would be good too. Even as an experienced user I do not want to analyze the code just to find out how to use it.

You should mention that your algorithm runs on a grid.
Is it a static grid or dynamic (can it change over time)?
How is the grid projected into the BGE and back (How can I see your grid when running the BGE)?
What is your pathfinding algorithm/what is the strategy (shortest path/easiest path/ nearest to target …)?

Monster

Hello Monster!
(thanks for the reply the other day!)

in fact is not very easy, but I had already tried some many time ago but I was not successful.

blender demo: I was in a hurry and I could not, now put … to come

I had done, a code explained line by line, but I’m not sure that we understand better than I can do …

yes, then the grid is not exactly dynamic, a static / local.
in the sense that the values ​​are relative to the position of the object, but is not dynamic: the grid is created and destroyed in a single step.
only “winning path” is saved in a property of the [“path”]

the grid is a dictionary, which makes a list of all cells, in text form
to see the grid you need to print (print (globalpath))

but the list, you have saved in an orderly way, the numbers seem to put the case …
(but not) now upload the demo!..

PATH FIND DEMO

:eek::eyebrowlift2::eyebrowlift:

Attachments

pathfind-ONEPYTHON-demo.blend (1.28 MB)

how work:

start only one path (predefinited) from the player’s cell(this can duplicate after)
first loop run the all path (path=list)
is taken the last list of actual list (last position) like reference valid
try in new position(up down left right)
if new position is inside the grid …OK else not (this is must important , if is out of range get big error)

this can find 1/2/3/4 free cell…
if found 1 free cell , extends his path (path is one list of 2 numbers) and stop
if found more cell in more complex!
in this case must duplicate it , the new path is adding to end of list, plus must clear his last cell,and at the end
re-extend his path
so, the new path id adding at the first, the old at the end…

this if found 2/3 or 4 cell…

if not found any , in 4 time , i m mark it with “X” (this mean not valid path, path closed): originally i would clear it , but is not possible:
change also the order of other path .

the scipth check if path is mark with X , if yes , jump it .

variable must important

globalpath: (make a grid in text form with value 0/1/3)
compare: become the number in to string to compare potential new cell position with grid
p (store all list, all potential path)
exitStrategy , this is the last adding for exit from script, when path not found otherwise gridx*gridy is too largest and slow much

Hi,
with the demo it is much more clear what you are talking about :D.
Your description is not really understandable (at least to me). But this does not matter.

What pathfinding algorithm are you implementing?
A*, backtracking, an own one?

I think your code does this (my interpretation):
Part A: Path finding

  • it creates an internal model = a grid
  • uses the controller’s owner as player and creates a representation in the model
  • searches through the scene to find obstacles and creates representations in the model
  • searches the scene for targets and creates representations in the model
  • performs a path finding algorithm at the model -> the result is a list of positions

Part B: Path following

  • moves the player through all positions of the path

I suggest to split the logic. It is better to keep path finding and path following separate. The advantages are obvious:

  • cleaner code
  • less dependencies
  • easier to replace with other implementations
  • better readability

Other recommendations for coding:

  • place parts of your code into well named functions
    [LIST]

  • e.g. findPath()

  • e.g. initalizeGrid()

  • e.g. transformObjectsIntoGrid()

  • e.g. createNewPath()

  • this increases readability

  • this reduces complexity

  • it does not change the processing (see refactoring)

  • avoid numbers as states - better use strings or aliases

  • e.g. 1 vs. OBSTACLE ( when OBSTACLE=1 )

  • e.g. what is exitStrategy==0 ?

  • increases readability

  • avoid short meaningless variable names if not used in a very very short context

  • e.g. the meaning of o is not obvious

  • e.g. the meaning of i changes during the code

  • increases readability

  • avoids confusion

  • prevents ambiguous variables

[/LIST]I hope I do not confuse you to much :wink:

excellent!!! Gratulations to manage it! I tried a few times, with less success…
I would also recommend to split logic.
Would be nice to have a function, that inputs the player position, gets the grid, calculate the path and overwrite this to the player[‘path’].
Like this, multibots are possible and and path calculation is separatetd to the followrs logic.
Good work anyway!

agree:yes:, even I like the code “dirty”
or unreadable (because I myself can hardly understand what I wrote after 2 days)
but that was a beta version

now I have found the bug (it was easy to find)
and I added a cleaner path, and obsoletes other variables …
I put everything in [“path”] as I wanted to do.
I shortened the lines and put a little clearer variable. :slight_smile:
:rolleyes:

code with explanation line by line

from bge import logic as BG
from bge import events

c   = BG.getCurrentController()
o   = c.owner
sce = BG.getCurrentScene()
key = BG.keyboard.events
FKEY= key[events.FKEY]

if FKEY==1:
    
        ##################---SETUP THIS--#####################################
    OBSTACLE="obstacle" #choose the property must be in to object obstacle
    TARGET=  "target"   #choose the property must be in to object target
    gridLenX=100        #default is 100 (equal to 100 meter)
    gridLenY=100        #default is 100 (equal to 100 meter)
    direction=4         #default is 4 can change in to 8 
    
    playerX=xx=round(o.worldPosition[0])       ;gridStartX=xx-(gridLenX//2) 
    playerY=yy=round(o.worldPosition[1])       ;gridStartY=yy-(gridLenY//2)
    gridLimitMinX=round(playerX-(gridLenX//2)) ;gridLimitMaxX=gridLimitMinX+gridLenX
    gridLimitMinY=round(playerY-(gridLenY//2)) ;gridLimitMaxY=gridLimitMinY+gridLenY #this variable work for choose the range of grid
    
    
    
    ########## INIT GRID ##############
    localGrid={} #this var store a list (virtual grid 2D)
    for i in range(gridLenY):       #repeat for time equale at gridLenY (100 in this case)
        for i2 in range(gridLenX):  # idem but for the axis X of grid
            localGrid[(str(xx)+"|"+str(yy))]=0 ;xx+=1 # this line is the real writer of grid
            # ;print("localGrid",(str(xx)+"|"+str(yy)))
            
            if xx==gridStartX+gridLenX: #check if xx is out of range prestabilited
                xx=gridStartX ;yy+=1    #if yes return to left and restart
                if yy==gridStartY+gridLenY: #check if yy is out of range
                    yy=gridStartY       #?????????? this not serves a anyting..forune which i loop are perfect(to clean)
                    
    for i in sce.objects:
        if OBSTACLE in i: #shearc in all object: if in this are object with property OBSTACLE(see above OBSTACLE="obstacle") mark the cell of grid as 1
            localGrid[str(round(i.worldPosition[0]))+"|"+str(round(i.worldPosition[1]))]=1
        if TARGET in i:   #shearc in all object: if in this are object with property TARGET(see above TARGET="target") mark the cell of grid as 3(i can place 55,66..but i know which 3 is target)
            localGrid[str(round(i.worldPosition[0]))+"|"+str(round(i.worldPosition[1]))]=3
            dist=o.getDistanceTo(i) #utilize thi opportunity for get the distance from the target(this serves bit after)
    ###################################
    
    winnerPath=0 #variable sentinel , if is not 0 means which the target is found (so end of all loop)
    path=[[]] ;path[0].append(list([playerX,playerY])) #init the var path ,place in this the first position valid, for the loop this is unique reference with grid
    compare=str(str(playerX)+"|"+str(playerY)) #become the position(number) on the text, only in this mode can compare with grid
    
    if dist<max(gridLenX,gridLenY) and localGrid[compare]==0:#first comparison , this check if player is in one free position (bit useless) but work like point of start
        print("-"*30) ;print("      ","PATH FIND START") ;print("-"*30) # simply make better readibily the debug
        localGrid[compare]=1 #this overwrite the cell of grid and place 1 (not free)
        
        WIP=1 #WORK IN PROGRESS check if the script miss time or work(bit useless with -cleanPath- (new:D) see below)
        nPathClosed=0 # init new var , this archive the path closed (for cleanPath)
        Nloop=0 #anyting is only una variable for check approximate the lenght of loop (for future improve test)
        for r in range(gridLenX*gridLenY): # this is the first loop, the number is absolutly huge , but ever come to end 
            if WIP==0: # like before say, if is 0,means which the path is all closed and the loop continue at run useleess(but now this is deprecated)
                break

            cont=clean=len(path)# for debug
            if nPathClosed>50: # if yes more 50 path continue to run , but non work 
                print("*WARNING* START cleaner--->>>len(path)",len(path))
                ##cleanlist
                cont=len(path) ;cont2=0
                for i in range(cont): #much difficult setup this loop
                    if path[cont2]=="X": 
                        del(path[cont2]) ;cont2+=0
                    else: 
                        cont2+=1
                    if cont2>cont: 
                        print(clean-len(path),"path ceaning")
                        break
                ##cleanlist 
                print("*WARNING* after cleaner......len(path)",len(path))
                nPathClosed=0# after clening operation not remain more path zombies
                
            WIP=0 ;cont=len(path)
            for i in range(cont):#why not use directly the for in in path? simply, i is not un number , and cannot duplicate the path
                pathN=int(i)     #how counsill Monster , better if the variable is clear
                Nloop+=1         #test
                if Nloop>10000:   #test
                    break
                if winnerPath!=0:#if is different to 0 exit from loop now
                    break

                if path[pathN]!="X": # if is not "X" mean whic is path valid
                    lastlast=len(path[pathN])-1 ;recCell=list(path[pathN][lastlast]) #befire the next loop save the position of last position of actual path
                    foundcell=0
                                        
                    for i4 in range(direction): # loop 4 time (if direction is 4 like default)
                        tryPos=list(recCell)    # try pos get the position which before saved (not serves at first time ,but 2/3/4 yes
                        
                        if direction==4:
                            if   i4==0: tryPos[1]+=1 #try to up (y+1)
                            elif i4==1: tryPos[1]-=1 #try to down (y-1)
                            elif i4==2: tryPos[0]-=1 #try to left (x-1)
                            elif i4==3: tryPos[0]+=1 #try to right (x+1)
                        
                        elif direction==8:
                            if   i4==0: tryPos[1]+=1
                            elif i4==1: tryPos[1]-=1
                            elif i4==2: tryPos[0]-=1
                            elif i4==3: tryPos[0]+=1
                            elif i4==4: tryPos[1]+=1 ;tryPos[0]-=1
                            elif i4==5: tryPos[1]-=1 ;tryPos[0]+=1
                            elif i4==6: tryPos[0]-=1 ;tryPos[1]-=1
                            elif i4==7: tryPos[0]+=1 ;tryPos[1]+=1
                                
                        inRangeGrid=0 # check if is the new position is inside of grid
                        if tryPos[1]<gridLimitMaxY and tryPos[1]>gridLimitMinY and tryPos[0]>gridLimitMinX and tryPos[0]<gridLimitMaxX:
                            inRangeGrid=1 #above.. is the limit of grid
                        
                        if inRangeGrid==0:
                            WIP+=1 #deprecated
                                 
                        if inRangeGrid==1:
                            compare=str(str(tryPos[0])+"|"+str(tryPos[1])) #become the pos in number
                            if localGrid[compare]!=1:                      #if !=0 =cell free
                                foundcell+=1 ;WIP+=1                       #mark which found a free cell
                                if localGrid[compare]==0:                  #more precisely, free,but not target
                                    localGrid[compare]=1                   #mark like not free
                                    if foundcell>0:                        
                                        if foundcell==1:                    
                                            path[pathN].append(list(tryPos))#if have found only one cell can expand the path with cell found
                                            
                                        if foundcell>1:   #not can separate only one piece of path 
                                            foundcell=1 ;path.append(list(path[pathN])) ;lastlast=len(path[pathN])-1 #duplicate(this add one ideantical path at the end of list)
                                            del(path[pathN][lastlast]) ;path[pathN].append(list(tryPos)) #clean the last position (sure not perfectly with this last), after this extend path

                                elif localGrid[compare]==3:#target found
                                    if foundcell>1:        #exatly the same of above 
                                        foundcell=1 ;lastlast=len(path[pathN])-1
                                        del(path[pathN][lastlast]) ;path[pathN].append(list(tryPos))
                                    
                                    else: path[pathN].append(list(tryPos))#this mean which is only one the found cell(cannot be 0)
                                        
                                    winnerPath=list(path[pathN])# if come a this line means target have found
                                    v1=0 ;v2=len(winnerPath)-1 ;v3=list(winnerPath) #this var go in the ["path"]
                                    o["path"]=[v1,v2,v3] ;report=list(path) #["path"]is make .report=debug
                                    
                        if i4==direction-1:
                            if foundcell==0: 
                                path[pathN]="X"#if in 4 direction not have found 1 cell , the path is closed ,not can found after
                                nPathClosed+=1 #this work for -clean path-

NEW CODE bug-free and clean :yes:

from bge import logic as BG
from bge import events

c   = BG.getCurrentController()
o   = c.owner
sce = BG.getCurrentScene()
key = BG.keyboard.events
FKEY= key[events.FKEY]

if FKEY==1:
    
    ######################################################################
    ##################---SETUP THIS--#####################################
    OBSTACLE="obstacle" #choose the property must be in to object obstacle
    TARGET=  "target"   #choose the property must be in to object target
    gridLenX=100        #default is 100 (equal to 100 meter)
    gridLenY=100        #default is 100 (equal to 100 meter)
    direction=4         #default is 4 can change in to 8 
    ######################################################################
    ######################################################################
    
    
    playerX=xx=round(o.worldPosition[0])       ;gridStartX=xx-(gridLenX//2)
    playerY=yy=round(o.worldPosition[1])       ;gridStartY=yy-(gridLenY//2)
    gridLimitMinX=round(playerX-(gridLenX//2)) ;gridLimitMaxX=gridLimitMinX+gridLenX
    gridLimitMinY=round(playerY-(gridLenY//2)) ;gridLimitMaxY=gridLimitMinY+gridLenY
    
    
    ########## INIT GRID ##############
    localGrid={}
    for i in range(gridLenY):
        for i2 in range(gridLenX):
            localGrid[(str(xx)+"|"+str(yy))]=0 ;xx+=1
            # ;print("localGrid",(str(xx)+"|"+str(yy)))
            
            if xx==gridStartX+gridLenX:
                xx=gridStartX ;yy+=1
                if yy==gridStartY+gridLenY:
                    yy=gridStartY
                    
    for i in sce.objects:
        if OBSTACLE in i:
            localGrid[str(round(i.worldPosition[0]))+"|"+str(round(i.worldPosition[1]))]=1
        if TARGET in i:
            localGrid[str(round(i.worldPosition[0]))+"|"+str(round(i.worldPosition[1]))]=3
            dist=o.getDistanceTo(i)
    ###################################
    
    winnerPath=0
    path=[[]] ;path[0].append(list([playerX,playerY]))
    compare=str(str(playerX)+"|"+str(playerY))
    
    if dist<max(gridLenX,gridLenY) and localGrid[compare]==0:
        print("PATH FIND START");print("-"*30);print("-"*30)
        localGrid[compare]=1
        
        WIP=1
        nPathClosed=0
        for r in range(gridLenX*gridLenY):
            if WIP==0:
                break

            cont=len(path)
            if nPathClosed>1000:
                print("*WARNING* START cleaner--->>>len(path)",len(path))
                ##cleanlist
                cont=len(path) ;cont2=0
                for i in range(cont):
                    if path[cont2]=="X": 
                        del(path[cont2]) ;cont2+=0
                    else: 
                        cont2+=1
                    if cont2>cont: 
                        break
                ##cleanlist
                print("*WARNING* after cleaner......len(path)",len(path))
                nPathClosed=0
                
            WIP=0 ;cont=len(path)
            for i in range(cont):
                pathN=int(i)
                if winnerPath!=0:
                    break

                if path[pathN]!="X":
                    lastlast=len(path[pathN])-1 ;recCell=list(path[pathN][lastlast])
                    foundcell=0
                                        
                    for i4 in range(direction):
                        tryPos=list(recCell)
                        
                        if direction==4:
                            if   i4==0: tryPos[1]+=1
                            elif i4==1: tryPos[1]-=1
                            elif i4==2: tryPos[0]-=1
                            elif i4==3: tryPos[0]+=1
                        
                        elif direction==8:
                            if   i4==0: tryPos[1]+=1
                            elif i4==1: tryPos[1]-=1
                            elif i4==2: tryPos[0]-=1
                            elif i4==3: tryPos[0]+=1
                            elif i4==4: tryPos[1]+=1 ;tryPos[0]-=1
                            elif i4==5: tryPos[1]-=1 ;tryPos[0]+=1
                            elif i4==6: tryPos[0]-=1 ;tryPos[1]-=1
                            elif i4==7: tryPos[0]+=1 ;tryPos[1]+=1
                                
                        inRangeGrid=0
                        if tryPos[1]<gridLimitMaxY and tryPos[1]>gridLimitMinY and tryPos[0]>gridLimitMinX and tryPos[0]<gridLimitMaxX:
                            inRangeGrid=1
                        
                        if inRangeGrid==0:
                            WIP+=1
                                 
                        if inRangeGrid==1:
                            compare=str(str(tryPos[0])+"|"+str(tryPos[1])) 
                            if localGrid[compare]!=1: 
                                foundcell+=1 ;WIP+=1
                                if localGrid[compare]==0:
                                    localGrid[compare]=1   
                                    if foundcell>0:
                                        if foundcell==1:
                                            path[pathN].append(list(tryPos))
                                            
                                        if foundcell>1:   
                                            foundcell=1 ;path.append(list(path[pathN])) ;lastlast=len(path[pathN])-1
                                            del(path[pathN][lastlast]) ;path[pathN].append(list(tryPos))

                                if localGrid[compare]==3:
                                    if foundcell>1:
                                        foundcell=1 ;lastlast=len(path[pathN])-1
                                        del(path[pathN][lastlast]) ;path[pathN].append(list(tryPos))
                                    
                                    elif foundcell==1:
                                        path[pathN].append(list(tryPos))
                                        
                                    winnerPath=list(path[pathN])
                                    v1=0 ;v2=len(winnerPath)-1 ;v3=list(winnerPath)
                                    o["path"]=[v1,v2,v3] ;report=list(path)
                                    
                        if i4==direction-1:
                            if foundcell==0: 
                                path[pathN]="X"
                                nPathClosed+=1
        ##########################          
        if winnerPath!=0: 
            print("--REPORT--") ;print() ;print()       ;print("N tot path       ->",len(report))
            print("lenght patwinner ->",len(winnerPath));print("patwinner        ->",winnerPath ) 
        else: print() ;print() ;print("--PATH NOT FOUND--")
        ###########################

if not "path" in o: o["path"]=0
    
if o["path"]!=0: 
    p=o["path"] ;p0=p[0] ;p1=p[1] ;p2=p[2] 
    x=p2[p0][0] ;y=p2[p0][1];z=round(o.worldPosition[2]) 
    pathPos=[x,y,z]
    vec=o.getVectTo(pathPos) ;dist=vec[0] # ;print(dist)
    o.alignAxisToVect(vec[1],1,0.5) ;o.applyMovement([0,0.2,0],1)
    if dist<0.5:
        if o["path"][0]<o["path"][1]: 
            o["path"][0]+=1
        elif dist<0.2: 
            o["path"]=0

now perhaps it’s better if somebody moves the TD in the right room if not, I can not update

how work l’algoritm?

i think thi is the mode more simply
basic mechanism

this work very well in the contort labirint ,but much bad(slow) in the place open!
paradoxically

I think you can do in other ways more open spaces but the structure changes very

However, this is the mechanism (theoretical)
at each step all the terminals looking into all possible directions while avoiding the obstacles and the cells where a path has already passed.
This method expands the paths like wildfire
and the first path which finds the target is also automatically the shortest path that can be;)

Attachments


I wonder how hard it would be to adapt this to use nodes instead of a grid with simple raycasting to ensure the object doesn’t run into walls or moving objects in the way, it might be faster because you’re only connecting an existing arrangement of nodes instead of spidering the path across dozens or even hundreds of grid squares.

For the more complex pathfinding, the BGE in the later revisions now has recast and detour for that, but I think it comes with a few new python functions that would allow you to work it into a more complex AI structure.

So it is a A* algorithms an a grid ;).

The grid implementation is quite a special implementation. As it works with some assumptions that nodes can met, it is not that easy to port. I think it would be better to grab one of the pseudo code implementations from the Wikipedia and implement it in Python. The most work is to convert the BGE world into the internal model (node graph). MarcoIT did that conversion very nice (BGE objects -> “python array”).

Moderation:

moved to resources

I made a small mess in the first lines :mad:

this is wrong:

playerX=xx=round(o.worldPosition[0])       ;gridStartX=xx-(gridLenX//2)
playerY=yy=round(o.worldPosition[1])       ;gridStartY=yy-(gridLenY//2)
gridLimitMinX=round(playerX-(gridLenX//2)) ;gridLimitMaxX=gridLimitMinX+gridLenX
gridLimitMinY=round(playerY-(gridLenY//2)) ;gridLimitMaxY=gridLimitMinY+gridLenY

this is right

playerX=round(o.worldPosition[0])           ;gridStartX=xx=playerX-(gridLenX//2)
playerY=round(o.worldPosition[1])           ;gridStartY=yy=playerY-(gridLenY//2)
gridLimitMinX=round(playerX-(gridLenX//2))  ;gridLimitMaxX=gridLimitMinX+gridLenX
gridLimitMinY=round(playerY-(gridLenY//2))  ;gridLimitMaxY=gridLimitMinY+gridLenY

how work the nodes?
are complex list?
have nothing to do with the mesh I hope?:confused::stuck_out_tongue: this is more powerful :RocknRoll: why using this mesh??

danke :wink:

this is the last version(for more simmetrical grid) and without useless line:

    ######################################################################
    ##################---SETUP THIS--#####################################
    OBSTACLE="obstacle" #choose the property must be in to object obstacle
    TARGET=  "target"   #choose the property must be in to object target
    gridLenX=20         #default is 100 (equal to 100 meter)
    gridLenY=20         #default is 100 (equal to 100 meter)
    direction=4         #default is 4 can change in to 8 
    ######################################################################
    ######################################################################
    
    if gridLenX%2==0: gridLenX+=1
    if gridLenY%2==0: gridLenY+=1
    
    playerX=round(o.worldPosition[0])           ;gridStartX=xx=playerX-(gridLenX//2)
    playerY=round(o.worldPosition[1])           ;gridStartY=yy=playerY-(gridLenY//2)
    gridLimitMinX=round(playerX-(gridLenX//2))  ;gridLimitMaxX=gridLimitMinX+gridLenX
    gridLimitMinY=round(playerY-(gridLenY//2))  ;gridLimitMaxY=gridLimitMinY+gridLenY
    
    
    ########## INIT GRID ##############
    localGrid={}
    for i in range(gridLenY):
        for i2 in range(gridLenX):
            localGrid[(str(xx)+"|"+str(yy))]=0 ;xx+=1
            #print((str(xx)+"|"+str(yy)))
            if xx==gridStartX+gridLenX:
                xx=gridStartX ;yy+=1
                    
    for i in sce.objects:
        if OBSTACLE in i:
            localGrid[str(round(i.worldPosition[0]))+"|"+str(round(i.worldPosition[1]))]=1
        if TARGET in i:
            localGrid[str(round(i.worldPosition[0]))+"|"+str(round(i.worldPosition[1]))]=3
            dist=o.getDistanceTo(i)
    ###################################

but this nodes cannot make whit python? who is ?

The model the search algorithm is running on is usually a graph. According to Wikipedia a graph consists of vertices + edges. This is the mathematical definition, to ensure we do not mix vertices of a 3d Model (wich is a graph too) we better call them nodes.

What is a grid: A (2D) grid is a graph with:

  • 1…4 edges of the same length
  • with diagonals 1…4 diagonal edges with the length of appr. 1.4
  • if stored in an array you can access the nodes via indexing [1,3]

Common graphs can have any number of edges with any length.
The model they represent does not even need to be geometric (state graph).

While a each grid is a graph (or can easily be transformed into one), it is not all graphs can be a grid.

I believe I have done, now I see no other possibility of improvements

then will post a game based on this type of script,
labyrinths

now I want to try to make the branches of the path