• 🏆 Texturing Contest #33 is OPEN! Contestants must re-texture a SD unit model found in-game (Warcraft 3 Classic), recreating the unit into a peaceful NPC version. 🔗Click here to enter!
  • It's time for the first HD Modeling Contest of 2024. Join the theme discussion for Hive's HD Modeling Contest #6! Click here to post your idea!

Pathfinding System

Status
Not open for further replies.
Level 19
Joined
Feb 4, 2009
Messages
1,313
I tried to make a pathfinding system but I have a few issues with it:
1. it does not always find the shortest path
2. if I enable diagonal paths it will find weird paths
(probably could be fixed by checking up/down/left/right points but there might be a better solution)
3. sometimes it does not find a path at all
or if anyone got a better idea to find paths than this grid approach tell me and I'll try if it works

Alright, here's the code and the map
JASS:
//Might find very small paths (even smaller than collision size of unit)
function FindPath_IsPathable takes real x, real y returns boolean
    //Move items to point
    call SetItemPosition(udg_Path_Item, x, y)
    call SetItemPosition(udg_Path_Item2, x, y)
    //If item1 is at the desired point the point is free
    //If item2 is not at that point item1 didn't get stuck in cliffs or water
    return GetWidgetX(udg_Path_Item)==x and GetWidgetY(udg_Path_Item)==y and GetWidgetX(udg_Path_Item2)!=x and GetWidgetY(udg_Path_Item2)!=y
endfunction

//Check point
function FindPath_Check takes integer x, integer y, integer c, integer i returns integer
    //If point not checked yet
    if not HaveSavedInteger(udg_Path, x, y) then
        //Check pathing
        if FindPath_IsPathable(x, y) then
            //Save point
            call SaveInteger(udg_Path, x, y, i)
            call SaveInteger(udg_Path, c+1, 1, x)
            call SaveInteger(udg_Path, c+1, 2, y)
            return 1
        endif
    endif
    return 0
endfunction

function FindPath_Run takes integer i, integer n returns integer
    local integer x
    local integer y
    local integer xt = LoadInteger(udg_Path, StringHash("xt"), 0)
    local integer yt = LoadInteger(udg_Path, StringHash("yt"), 0)
    local integer r = LoadInteger(udg_Path, StringHash("r"), 0)
    local integer c = n    //Index for new points
    local integer r2 = r*r //Detection radius

    loop
        //While there are points left to check
        exitwhen i>n
        //Load current point
        set x = LoadInteger(udg_Path, i, 1)
        set y = LoadInteger(udg_Path, i, 2)
        //Check if target is close to current point
        if (xt-x)*(xt-x)+(yt-y)*(yt-y)<=r2 then
            return i
        else
            //Check left, right, up, down
            set c = c + FindPath_Check(x+r, y, c, i)
            set c = c + FindPath_Check(x-r, y, c, i)
            set c = c + FindPath_Check(x, y+r, c, i)
            set c = c + FindPath_Check(x, y-r, c, i)

            //If I delete these it won't find diagonal paths at all
            set c = c + FindPath_Check(x+r, y+r, c, i)
            set c = c + FindPath_Check(x+r, y-r, c, i)
            set c = c + FindPath_Check(x-r, y+r, c, i)
            set c = c + FindPath_Check(x-r, y-r, c, i)

            //Internal opperation limit
            //Higher number might be possible
            //But things might become unstable under certain conditions
            //Better don't increase it much more
            if c-n>100 then
                exitwhen true
            endif
        endif
        //Next point
        set i = i + 1
    endloop

    //Target not found yet, start next circle
    if c>n then
        if n<LoadInteger(udg_Path, StringHash("limit"), 0) then
            //Workaround to bypass operation limit
            call SaveInteger(udg_Path, StringHash("i"), 0, i)
            call SaveInteger(udg_Path, StringHash("c"), 0, c)
            call TriggerExecute(gg_trg_Path)            
            return LoadInteger(udg_Path, StringHash("result"), 0)
        endif
        return -2
    endif
    return -3
endfunction

function FindPath_ItemFilter takes nothing returns boolean
    //Hide item and add it to array to reveal it later
    if IsItemVisible(GetFilterItem()) then
        set udg_Path_ItemArray[udg_Path_Count] = GetFilterItem()
        call SetItemVisible(udg_Path_ItemArray[udg_Path_Count], false)
        set udg_Path_Count = udg_Path_Count + 1
    endif
    return false
endfunction

//Prepare pathfinding
function FindPath takes real x, real y, real x2, real y2 returns integer
    //Distance between points
    local integer r = 128
    local integer result = -1

    //Clear path
    call FlushParentHashtable(udg_Path)
    set udg_Path = InitHashtable()

    //Create items for pathchecking
    if udg_Path_Item==null then
        set udg_Path_Item  = CreateItem('ches', 0.00, 0.00)
        set udg_Path_Item2 = CreateItem('ches', 0.00, 0.00)
        call SetItemVisible(udg_Path_Item , false)
        call SetItemVisible(udg_Path_Item2, false)
    endif

    //Hide items so they won't fuck up our pathchecking
    set udg_Path_Count = 0
    call EnumItemsInRect(bj_mapInitialPlayableArea, Condition(function FindPath_ItemFilter ), null)

    //Set starting point for pathfinding
    call SaveInteger(udg_Path, 0, 1, R2I(x))
    call SaveInteger(udg_Path, 0, 2, R2I(y))
    call SaveInteger(udg_Path, StringHash("xt"), 0, R2I(x2))
    call SaveInteger(udg_Path, StringHash("yt"), 0, R2I(y2))
    call SaveInteger(udg_Path, StringHash("r"), 0, r)
    call SaveInteger(udg_Path, StringHash("limit"), 0, 12345)

    //Begin pathfinding
    //Parameters:
    //1. index of first uprocessed point
    //2. index of last point
    set result = FindPath_Run(0, 0)

    //Hide pathcheck items (moving unhides them)
    call SetItemVisible(udg_Path_Item, false)
    call SetItemVisible(udg_Path_Item2, false)

    //Show previously hidden items
    loop
        exitwhen udg_Path_Count<=0
        set udg_Path_Count = udg_Path_Count - 1
        call SetItemVisible(udg_Path_ItemArray[udg_Path_Count], true)
    endloop
    return result
endfunction
  • Path
    • Events
    • Conditions
    • Actions
      • Custom script: local integer i = LoadInteger(udg_Path, StringHash("i"), 0)
      • Custom script: local integer c = LoadInteger(udg_Path, StringHash("c"), 0)
      • Custom script: call SaveInteger(udg_Path, StringHash("result"), 0, FindPath_Run( i, c))
  • FindPath
    • Events
      • Unit - A unit Is issued an order targeting a point
    • Conditions
    • Actions
      • Custom script: local integer result = -1
      • Custom script: local integer x
      • Custom script: local integer y
      • Custom script: local integer x2
      • Custom script: local integer y2
      • Custom script: set result = FindPath(GetUnitX(GetTriggerUnit()), GetUnitY(GetTriggerUnit()), GetOrderPointX(), GetOrderPointY())
      • For each (Integer A) from 1 to Lightning_Count, do (Actions)
        • Loop - Actions
          • Lightning - Destroy Lightning[(Integer A)]
      • Set Lightning_Count = 0
      • Custom script: loop
      • Custom script: set x = LoadInteger(udg_Path, result, 1)
      • Custom script: set y = LoadInteger(udg_Path, result, 2)
      • Custom script: exitwhen result<=0
      • Custom script: set result = LoadInteger(udg_Path, x, y)
      • Custom script: set x2 = LoadInteger(udg_Path, result, 1)
      • Custom script: set y2 = LoadInteger(udg_Path, result, 2)
      • Set Lightning_Count = (Lightning_Count + 1)
      • Custom script: set udg_Lightning[udg_Lightning_Count] = AddLightning("DRAL", false, x, y, x2, y2)
      • Custom script: endloop
 

Attachments

  • second problem.jpg
    second problem.jpg
    95 KB · Views: 195
  • Pathfinding.w3x
    32.1 KB · Views: 63
Level 19
Joined
Feb 4, 2009
Messages
1,313
i have seen a map, rollercoaster or something, which has a pathfinding system.

try it out. its open source, and GUI.

http://www.hiveworkshop.com/forums/...v-07-a-128062/?prev=search=roller&d=list&r=20

wow
awesome map
but unfortunately the "Finish Track" function just finishes it and does not find the shortest path

Hmm, I were creating a system like this once~ Let me see if I could recreate it.

feel free to do so :D

I found a few other ways in the last weeks when I posted this but of course I am interested in others as well
 
Status
Not open for further replies.
Top