a* pathfinding

Source-code only - please, don't post questions here.
dumbledore
Posts: 680
Joined: May 28, 2005 1:11
Contact:

a* pathfinding

Postby dumbledore » Jun 30, 2005 6:40

there've been a few threads about this on qbasicnews, i thought i'd add mine to the jumble ;P it doesn't save the path, it's probably best for monster movements 'n stuff like that, it's a lot faster than calculating the entire path and picking that apart ;) i could add route optimizing pretty easy if i add path saving, then again ai's shouldn't be too smart imo

Code: Select all

#include once "crt.bi"
#define WALL 4
#define FINISH 5
#define START 6

option explicit

type coord
    x as ubyte
    y as ubyte
end type
type node
    x as ubyte
    y as ubyte
    g as integer
    f as integer
    p as node ptr
end type

declare function timesvisited( byval x as integer, byval y as integer ) as byte
declare function outofbounds( byval x as integer, byval y as integer ) as byte
declare function onclosedlist( byref what as coord ) as byte
declare function removefromopenlist( byval idx as integer ) as byte
declare function onopenlist( byref what as coord ) as byte

redim preserve shared openlist( 0 ) as node ptr, closedlist( 1 ) as coord, allnodes( 0 ) as node ptr
dim as integer rx, ry, cx, cy, ex, ey, i

cls
dim shared as integer mx, my
read mx
read my
dim as ubyte room( mx * my )
for ry = 0 to my - 1
    for rx = 0 to mx - 1
        read room( rx + ry * mx )
        select case room( rx + ry * mx )
        case WALL
            ? "|";
        case START
            ? "@";
            cx = rx
            cy = ry
            closedlist( 0 ).x = rx
            closedlist( 0 ).y = ry
        case FINISH
            ? "*";
            ex = rx
            ey = ry
        case else
            ? " ";
        end select
    next
    ?
next

sleep

dim as node ptr tmpnode
tmpnode = callocate( len( node ) )
tmpnode->x = cx
tmpnode->y = cy
allnodes( ubound( allnodes ) ) = tmpnode
redim preserve shared allnodes( ubound( allnodes ) + 1 )
while cx <> ex or cy <> ey
   
    dim as integer max = 100, aye, x, y
   
    aye = 0
   
    for x = -1 to 1
        for y = -1 to 1 step 1 - ( x = 0 )
           
            dim as coord working
            working.x = cx + x
            working.y = cy + y
           
            if onclosedlist( working ) = 0 and onopenlist( working ) = 0 and _
               room( cx + x + ( cy + y ) * mx ) <> WALL and _
               room( cx + ( cy + y ) * mx ) <> WALL and _
               room( cx + x + cy * mx ) <> WALL and _
               outofbounds( cx + x, cy + y ) = 0 then
               
                openlist( ubound( openlist ) ) = callocate( len( node ) )
                dim as node ptr temp
                temp = openlist( ubound( openlist ) )  '' use a temp var so we don't have to
                                                       '' keep using ubound()
                temp->x = working.x
                temp->y = working.y
               
                temp->f = 10 * sqr( abs( x ) + abs( y ) ) + _                   '' the g score
                          10 * sqr( ( cx + x - ex ) ^ 2 + ( cy + y - ey ) ^ 2 ) '' the h score
                if temp->f > max then max = temp->f
                temp->p = tmpnode
               
                allnodes( ubound( allnodes ) ) = temp
                redim preserve shared allnodes( ubound( allnodes ) + 1 )
               
                redim preserve shared openlist( ubound( openlist ) + 1 )
               
            end if
           
        next
    next
   
    dim as integer lowest, lowestidx = 0
    lowest = max + 1
    for i = 0 to ubound( openlist ) - 1
        if openlist( i )->f < lowest and openlist( i )->f <> -1 then
            lowest = openlist( i )->f
            lowestidx = i
        end if
    next
   
    locate cy + 1, cx + 1: ? " "
   
    if lowest <> max + 1 then
        cx = openlist( lowestidx )->x
        cy = openlist( lowestidx )->y
    end if
   
    locate cy + 1, cx + 1: ? "@"
   
    closedlist( ubound( closedlist ) ).x = cx
    closedlist( ubound( closedlist ) ).y = cy
    redim preserve shared closedlist( ubound( closedlist ) + 1 )
   
    tmpnode = openlist( lowestidx )
    removefromopenlist( lowestidx )
   
    sleep
   
wend

'' as a function this would return tmpnode

while tmpnode <> 0
    locate tmpnode->y + 1, tmpnode->x + 1
    ? "*"
    tmpnode = tmpnode->p
wend

'' it will be necessary to clean up memory afterward, otherwise we'll end up with
'' a leak the size of the pacific ocean ;P

for i = 0 to ubound( allnodes )
   
    deallocate allnodes( i )
   
next

sleep

end

data 12,10
data 4,4,4,4,4,4,4,4,4,4,4,4
data 4,0,0,0,0,0,0,0,0,0,0,4
data 4,0,0,0,0,0,0,0,0,0,0,4
data 4,0,0,0,4,4,4,0,0,0,0,4
data 4,0,0,0,0,0,0,4,0,0,0,4
data 4,0,0,0,0,6,0,4,0,5,0,4
data 4,0,0,0,0,0,0,4,0,0,0,4
data 4,0,0,0,4,4,4,0,0,0,0,4
data 4,0,0,0,0,0,0,0,0,0,0,4
data 4,4,4,4,4,4,4,4,4,4,4,4

function outofbounds( byval x as integer, byval y as integer ) as byte
   
    return x < 0 or x > mx - 1 or y < 0 or y > my - 1
   
end function

function onclosedlist( byref what as coord ) as byte
   
    dim as integer i
    for i = 0 to ubound( closedlist ) - 1
        if memcmp( @closedlist( i ), @what, len( coord ) ) = 0 then return -1
    next
    return 0
   
end function

function removefromopenlist( byval idx as integer ) as byte
   
    if idx > ubound( openlist ) then return 0
    dim as integer i
    for i = idx to ubound( openlist ) - 1
        openlist( i ) = openlist( i + 1 )
    next
    redim preserve openlist( ubound( openlist ) - 1 )
   
    return -1
   
end function

function onopenlist( byref what as coord ) as byte
   
    dim as integer i
    for i = 0 to ubound( openlist ) - 1
        if memcmp( openlist( i ), @what, len( coord ) ) = 0 then return -1
    next
    return 0
   
end function


[edit] changed to use open / closed lists
Last edited by dumbledore on Jul 02, 2005 2:37, edited 1 time in total.
Ryan
Posts: 693
Joined: Jun 10, 2005 2:13
Location: Louisville, KY
Contact:

Postby Ryan » Jun 30, 2005 13:52

Thanks! I'm lost when it comes to pathfinding and need to figure it out for the Rogue competition. No one else seemed quite sure of their code, though. = P
dumbledore
Posts: 680
Joined: May 28, 2005 1:11
Contact:

Postby dumbledore » Jul 02, 2005 2:37

i added opened / closed lists to it, should work a bit faster now.
Frobozz
Posts: 33
Joined: Jun 12, 2005 20:32

Postby Frobozz » Jul 02, 2005 3:26

Personally I don't see the point of strong pathfinding in a roguelike - unless you like the idea of mobs being able to find you even with a solid wall blocking their view. ^_^
dumbledore
Posts: 680
Joined: May 28, 2005 1:11
Contact:

Postby dumbledore » Jul 02, 2005 7:06

no, it'll have to be modified a bit to allow for line of sight type of things, what'll end up happening is if a monster can see you it'll use the pathfinding algo to figure out where to go, but it will only pass the stuff it can see to the algo. this way it will only be as smart as it should be.
rdc
Posts: 1713
Joined: May 27, 2005 17:22
Location: Texas, USA
Contact:

Postby rdc » Jul 02, 2005 12:46

Nice code.

If the monster can hear you, it doesn't need to see you. Sound could travel for quite a distance in a dank, dark dungeon. :)
Ryan
Posts: 693
Joined: Jun 10, 2005 2:13
Location: Louisville, KY
Contact:

Postby Ryan » Jul 02, 2005 14:21

And if all the monster has is one big nose, it can hunt you down. ^_^ I like the idea of having monsters use all three methods of finding the player. It's nice to use pathfinding if there are other things in the room besides the player, too. (Other monsters..) Though I guess full fledged pathfinding might not be needed for that.
inded005
Posts: 126
Joined: Jan 04, 2006 5:43
Location: Kingaroy Australia
Contact:

Postby inded005 » Feb 13, 2007 11:24

that code is very hard to understand...
i wrote an a* with opens/closed lists, and a bit of terrain analysis, trouble implementing it though. will anyone be interested in seeing it?
Dr_D
Posts: 2345
Joined: May 27, 2005 4:59
Contact:

Postby Dr_D » Feb 13, 2007 12:42

Sure. Here's something I made also. It isn't 3D, but it shows that FB is more than fast enough. ;)
http://www.freebasic.net/forum/viewtopi ... 0234#40234
Ryan
Posts: 693
Joined: Jun 10, 2005 2:13
Location: Louisville, KY
Contact:

Postby Ryan » Feb 14, 2007 3:13

That is awesome. I can't believe I never saw that back in the day. : P
inded005
Posts: 126
Joined: Jan 04, 2006 5:43
Location: Kingaroy Australia
Contact:

Postby inded005 » Feb 14, 2007 11:34

here's my attempt at implementing A*.

Code: Select all


function GameUnitType.WayPathGen(Xt As integer,Yt As integer) As integer
 ' =========================================================
 ' Function: Uses A* pathfinding algorithm to generate
 '            a path from this(x,y) to Xt,Yt
 ' Params: target/destination coords (as 32x32 tile coords)
 ' Returns: fills an array(the unit's WayPath()) and returns length(int) of the path found
 ' Notes: Uses simple distance-based heuristic.(beeline dist to tgt x 10)
 '        this causes it to use diagonals alot
 '==========================================================
 
  Debug "Starting Gen............................"
 ' 1. Add the starting node
 
 Dim As integer Xs,Ys,nextOpen,nextClosed, IsTgt
 Dim As integer iX,iY,i,lowF,f,lowFref, foundPath, tempF
 
 Debug "resetting arrays..."
 Dim wpt(MAP_XS,MAP_YS) As WptSqrType
 Dim opens(MAX_ASTARWPTS*2) As Coords
 ' ==============================================
 ' Notes about the arrays:
 '  wpt(x,y) type definition: (in separate header)
   '  Type WptSqrType
   '   State As byte ' 0 = none: 1 = open: 2=closed
   '   ParentX As integer 'was ushort
   '   ParentY As integer 'was ushort
   '   F As ubyte
   '   G As ubyte
   '   H As ubyte
   '   listRef As ushort
   ' End Type
 ' The State byte is essentially the closed list.
 ' If the State is open, it uses listRef to find the node in opens()
 '  this is to avoid doing looping array lookups.
 ' Same reason i used the 2d arrays: so i can just reference the coords
 ' instead of having to order them or look them up.
 ' Hopefully, it turns out faster. Seems to run pretty fast, and
 ' I really dont feel like doing a time-cost analysis to compare it
 ' with a version using list objects, ordering, and replacement.
 ' Plenty of memory available too, so why not?
 ' Anyway, as you can see, the F, G, and H costs for each square considered
 ' are recorded. The G cost is the movement cost up to this square.
 ' Diagonal moves cost more than orthogonal moves. (10 for ortho, 14
 ' for diag)
 ' These scores are calculated when the sqr is added to the
 ' open list. Squares are added to the opens() when they are candidates for
 ' movement; the only criteria being they must be within bounds, and must
 ' not be solid.     
 ' The ParentX/Y are really a 2D index reference to the square that precedes this
 ' node in the eventual "finished product" waypath.
 '
 ' The opens() array is just a simple integer coords type (x,y).
 ' These coordinate serve, again, as an index reference into the
 ' wpt() array. For a square/node to be "open" it must be on this
 ' list, else the algorithm will not consider/discover it as a better
 ' option... an integral part of shortest-path wayfinding!
 '
 ' There is another 2D array, MapSqr(x,y), that stores map tile
 ' info such as fog, solid state, and importantly to this alg, Cost.
 ' This cost is added to each square when it's F cost is being
 ' calculated.
 '
 ' Oh, and Debug is just a trace func that outputs to console.
   
 Debug " done local Dims"
    Xs = X
    Ys = Y
    ToSqrs(Xs,Ys) ' convert pixel coords to tile size coords (32x32) (bitshifts right 5)
 Debug " STARTSQR: try to add wpt at "+Str(Xs)+":"+Str(Ys)   
    wpt(Xs,Ys).State = 1 ' puts current unit sqr on opens   
 Debug " STARTSQR: try to add to opens at "+Str(Xs)+":"+Str(Ys)+" nO:"+Str(nextOpen)
    nextOpen = 1
    wpt(Xs,Ys).listRef = nextOpen   
    opens(nextOpen).X = Xs
    opens(nextOpen).Y = Ys
    nextOpen += 1
    lowF = 255
    IF DEBUGGING = TRUE then ScreenSet Primary,Primary
 Debug "-done add start node"
 
  ' 550 is a magic number, I know, but it's just
  ' how many nodes (map squares) the alg will try before
  ' giving up; therefore this governs the max length of
  ' the end result path.... 
  For i = 1 To 550
    ' get lowest F score sqr in the open list
    ' for i = 1 this will always be the unit's start pos
    ' or, (Xs, Ys)
    lowF = 255
    For f = 0 To MAX_ASTARWPTS
      If opens(f).X > 0 And opens(f).Y > 0 Then
         If wpt(opens(f).X,opens(f).Y).F < lowF and _
            wpt(opens(f).X,opens(f).Y).listRef > 0 and _
            wpt(opens(f).X,opens(f).Y).State = 1 Then
               lowF = wpt(opens(f).X,opens(f).Y).F
               lowFref = f           
         End If
      End if
    Next f
    Debug "-done find next low F"
   
    Xs = opens(lowFref).X
    Ys = opens(lowFref).Y
    Debug "curSqr:"+Str(Xs) +" "+ Str(Ys)+" openFRef:"+Str(lowFref)+" F:"+Str(lowF)
    'If Xs = 0 And Ys = 0 Then
    ' Debug "waypathGen died"
    ' Return 0
    'End if 
    If Xs = Xt And Ys = Yt Then
       ' target square found!
       Debug "hallelujah"
       foundPath = 1
       Exit for
    End If
   
    ' put it on closed 'list' (state) (and take it off opens list)
    ' the path will DEFINITELY use this node, since it has the
    ' lowest F cost.
    wpt(Xs,Ys).listRef = 0
    wpt(Xs,Ys).State = 2
    opens(lowFref).X = 0
    opens(lowFref).Y = 0
   
    For iX = -1 To 1
       For iY = -1 To 1
          isTgt = 0
          If iX <> 0 or iY <> 0 Then
            If Xs + iX > 0 Then           ' -\
            If Ys + iY > 0 Then           '   |__ bounds checking
            If Xs + iX <= MAP_XS Then     '   |
            If Ys + iY <= MAP_YS Then     ' -/
                'DBG:     debug "access:"+Str(Xs+iX)+" : "+Str(Ys+iY)
                'DBG:     If nextOpen = MAX_ASTARWPTS - 1 Then
                'DBG:        Debug "opens nearly full!"
                'DBG:     End if
                     If (Xs+iX=Xt and Ys+iY=Yt) Then isTgt = 1
                     If MapSqr(Xs+iX,Ys+iY).Cost < 255 or isTgt = 1 Then
                        ' either not solid, or this is the target
                        Debug "- not solid"
                       If wpt(Xs+iX,Ys+iY).State <> 2 or isTgt = 1 Then
                          ' not on closed list
                          Debug "- not closed"
                          If wpt(Xs+iX,Ys+iY).State = 1 Then
                            ' aready open
                            Debug "- already open"
                           ' check to see if this G score is better
                           Dim As integer tempG
                           If iX = 0 Or iY = 0 Then
                              tempG = wpt(Xs,Ys).G + 10   
                           Else
                              tempG = wpt(Xs,Ys).G + 14
                           End If
                           'tempG is the Gscore if using currentsqr: (Xs,Ys)
                           If tempG < wpt(Xs+iX,Ys+iY).G Then
                            ' recalc the scores, and change the parent
                            ' since this is a better path
                            wpt(Xs+iX,Ys+iY).ParentX = Xs
                            wpt(Xs+iX,Ys+iY).ParentY = Ys
                             ' get H
                            wpt(Xs+iX,Ys+iY).H = Int(DIST(Xt,Yt,Xs+iX,Ys+iY)) * 10
                            ' get F
                            tempF = wpt(Xs+iX,Ys+iY).G + wpt(Xs+iX,Ys+iY).H + MapSqr(Xs+iX,Ys+iY).Cost
                            If tempF > 255 Then tempF = 255
                            If isTgt = 1 Then tempF = 1 
                            wpt(Xs+iX,Ys+iY).F = tempF 
                           End If
                          Else   ' not already open
                           Debug "- new open" 
                           wpt(Xs+iX,Ys+iY).ParentX = Xs
                           wpt(Xs+iX,Ys+iY).ParentY = Ys
                           wpt(Xs+iX,Ys+iY).State = 1
                           wpt(Xs+iX,Ys+iY).listRef = nextOpen
                           opens(nextOpen).X = Xs+iX
                           opens(nextOpen).Y = Ys+iY
                           nextOpen += 1
                           Debug "created new open"
                           Line((Xs+iX) Shl 5,(Ys+iY) Shl 5)-Step(5,15),RGB(20,255,0),b
                           ' get G
                           Debug "X:"+Str(Xs+iX)+ " Y:"+Str(Ys+iY)                           
                           If iX = 0 Or iY = 0 Then
                              wpt(Xs+iX,Ys+iY).G = wpt(Xs,Ys).G + 10   
                           Else
                              wpt(Xs+iX,Ys+iY).G = wpt(Xs,Ys).G + 14
                           End If
                           Debug "calc'ed new G"
                           ' get H
                           wpt(Xs+iX,Ys+iY).H = int(DIST(Xt,Yt,Xs+iX,Ys+iY)) * 10
                           ' get F                           
                           ' use tempF to avoid overflows (is this necessary?)
                           tempF = wpt(Xs+iX,Ys+iY).G + wpt(Xs+iX,Ys+iY).H + MapSqr(Xs+iX,Ys+iY).Cost
                           If tempF > 255 Then tempF = 255
                           If isTgt = 1 Then tempF = 1 
                           wpt(Xs+iX,Ys+iY).F = tempF                                                     
                          End If
                          Debug "- done check opens"
                       End If   
                     End If
                   End If
                End If
             End If
            End If
          End if 
       Next iY
    Next iX
    If DEBUGGING = TRUE then Line(Xs Shl 5 , Ys Shl 5)-Step(5,5),RGB(255,255,0),b
 Next i
 Debug "sqrs used:"+Str(i)
 
 If foundPath = 1 Then
    ' work back from Xt,Yt
    Dim As integer newXs,newYs
    Xs = Xt
    Ys = Yt
    For i = 1 To 50
       With wpt(Xs,Ys)
        asWpt(i).X = Xs Shl 5
        asWpt(i).Y = Ys Shl 5
        asWpt(i).Parent = i - 1
        If DEBUGGING = TRUE Then
         Line(Xs Shl 5, Ys Shl 5)-Step(15,5),RGB(255,255,255),b
         If i > 1 Then
            Line (Xs Shl 5, Ys Shl 5)-(asWpt(i-1).X, asWpt(i-1).Y),RGB(255,0,255)
         End if   
        End if
        If Xs Shr 5 = (X Shr 5) And Ys Shr 5 = Y Shr 5 Then
           Debug "traced back to start"
           CASP = i
           Exit for
        End if
        If .ParentX = 0 And .ParentY = 0 Then
           Debug "traced back to parents (0,0)"
           CASP = i
           Exit for   
        Else
           newXs = .ParentX
           newYs = .ParentY
           Xs = newXs
           Ys = newYs
           Debug "new asWpt:"+Str(i)+ ": "+Str(Xs)+ "-"+Str(Ys)
        End if   
       End with
    Next i
 Else
  Debug "didnt find a path"   
 End If
 IF DEBUGGING = TRUE then
  Sleep
  ScreenSet Primary,Secondary
 End if   
 Return casp

End Function 





Sub GameUnitType.MoveToTarget   
 ' =========================================================
 ' Function: *WAS* a Pathfinding proc for unit. move 2ward X/Ytgt
 ' Params:
 ' Returns:
 ' Notes:  OLD NOTES The current avoidStep is the main thing.
 '         if it's 1: apply a wing-and-finger spreading
 '         pathfinder around the unit to find an opening
 '         in the obstacles.
 '         2: follow the waypath set out by avoidStep 1
 '         else: beeline towards X/Ytgt
 '==========================================================
 Dim As Integer xo, yo, wpg
 If CVAR_nomovelimit = True Then AvoidStep = 0
 If CASP = 0 Then
  'If DIST(X,Y,Xtgt,Ytgt) > 8 then 
  Clear asWpt(1), 0, Len(asWpt(1)) * UBound(asWpt)
   wpg = WayPathGen(Xtgt Shr 5,Ytgt Shr 5)
   Debug "wayPathGen:"+Str(wpg)
   IF wpg = 0 then CASP = -1
  'End if
 Else
   ' Debug " MoveToTgt: casp:"+Str(CASP)
 End if
 AvoidStep = 3 ' hack: this is to use WayPathGen waypoints instead.
  Select Case AvoidStep
   Case 1               
    ' old wingandfinger waypathing went here
   Case 3 ' FOLLOW A* WAYPOINTS
    If CASP > 0 Then
    If X Shr 5 = asWpt(CASP).X Shr 5 And Y shr 5  = asWpt(CASP).Y Shr 5 Then
      Debug "reached asWpt#"+Str(CASP)
      CASP -= 1     
      If CASP <= 0 Then
         CASP = -1
         Debug "reached casp=0"
         'reset unit's wpts to blank
         ResetWPTs
         Exit sub
      End if
    End If         
    With asWpt(CASP) 
     If DEBUGGING = True Then Line(.X,.Y)-Step(4,2),Rgb(90,255,0),bf
     If X Shr 5 < .X Shr 5 Then xo = 1           
     If X Shr 5 > .X Shr 5 Then xo = -1
     If Y Shr 5 < .Y Shr 5 Then yo = 1
     If Y Shr 5 > .Y Shr 5 Then yo = -1 
     'Debug " follow casp:"+Str(xo)+" :"+Str(yo) 
    End With
    Else
      ' Debug "CASP <= 0: "+Str(CASP)
    End if
   Case 2
    ' follow the wing waypaths
    If Int(X/4) = Int(WingWpt(CWWP).X/4) And Int(Y/4) = Int(WingWpt(CWWP).Y/4) Then
     CWWP = WingWpt(CWWP).Link(1)
     If DEBUGGING = True Then PlaySound 7
     If CWWP = 0 Then
      ' beeline baby       
      If DEBUGGING = True Then  PlaySound 6
      AvoidStep = 3
      Exit Sub
     End If
    End If
    With WingWpt(CWWP) 
     If DEBUGGING = True Then Line(.X,.Y)-Step(2,2),Rgb(90,255,0),bf
     If X Shr 2 < .X Shr 2 Then xo = 1           
     If X Shr 2 > .X Shr 2 Then xo = -1
     If Y Shr 2 < .Y Shr 2 Then yo = 1
     If Y Shr 2 > .Y Shr 2 Then yo = -1     
    End With               
    With WingWpt(WingWpt(CWWP).Link(1)) 
     If DEBUGGING = True Then Line(.X,.Y)-Step(2,2),Rgb(0,255,90),bf
    End With
   Case Is > 40
    AvoidStep = 1
   Case Else               
    ' these are only shr 2 to allow for more accurate targeting
    ' (i.e. so xo or yo can be 0, stops the unit from bouncing between 1 and -1)
    If Xtgt Shr 3 < X Shr 3 Then xo = -1
    If Xtgt Shr 3 > X Shr 3 Then xo = 1
    If Ytgt Shr 3 < Y Shr 3 Then yo = -1
    If Ytgt Shr 3 > Y Shr 3 Then yo = 1
   End Select
    If DIST(X,Y,Xtgt,Ytgt) > 16 Then
     If xo <> 0 And yo <> 0 Then
      If Int(Rnd*3) = 0 Then
       yo = 0 
      Else
       xo = 0
      End If
     End If
     Move xo,yo               
    Else
     AvoidStep = 0
    End If
    OldXO = xo
    OldYO = yo
End Sub



This is just a fragment(!!!), it won't compile/run.
If you don't know much about A*, i doubt you will be able to follow it.
(I will be surprised if you 'follow' it even if you know all about A*!!)
It works fine MOST times, but doesnt do very long paths for some reason.
(ie only about 15 squares long)
I might upload a stripped-down demonstration version of the game i'm using it in.
inded005
Posts: 126
Joined: Jan 04, 2006 5:43
Location: Kingaroy Australia
Contact:

Postby inded005 » Feb 15, 2007 7:47

ok... I fixed everything (including the small distances), and uploaded a demo of the waypathing in my game to <a href = http://members.dodo.com.au/pklanham/kngt_a04.zip > this location </a> . check it out, some feedback (esp. regarding the movement) would be cool
cheers
Dr_D
Posts: 2345
Joined: May 27, 2005 4:59
Contact:

Postby Dr_D » Feb 15, 2007 8:12

looks like that could end up being pretty damn fun dude... keep it up! :)
Torahteen
Posts: 91
Joined: Jul 15, 2005 15:58
Contact:

Postby Torahteen » Feb 22, 2007 21:21

Hehe, very cool guys. I remember writing my A* implementation. It's back on QBN. If anyone's interested, I can get the link. Also, someone mention LOS. I did make an LOS tutorial on Pete's QB Express :P.

Return to “Tips and Tricks”

Who is online

Users browsing this forum: No registered users and 2 guests