HomeUser Control Panel (unavailable in archive)ForumsTutorialsArt GalleryResourcesMaps

Complex problem involving points and pathing

03-13-2007, 02:00 PM#1
Earth-Fury
Lets say i have 2 copys of the exact same map next to eachother, and want an ability to switch you between them. Rather easy to do. untill you realize that there are buildings and variable pathing on the other side. I have NO idea where to start in coding a function to detect if a unit can fit in the area around a location. This has to account for things like building, and preferably units too. A fully coded function would be nice but just giving me an idea where to start would be great too
03-13-2007, 06:39 PM#2
grim001
If you just do SetUnitLocation(GetUnitX(u), GetUnitY(u)) then it will force the unit into a pathable area
03-13-2007, 06:57 PM#3
Earth-Fury
Thats a rather... messy way to do it tho =/ as you may think you're gonna end up somewhere... and be verry displeased to be pushed rather far away. whereas if i can simply find out if an area is pathable and can fit the unit, i can display an error message instead.
03-13-2007, 07:08 PM#4
grim001
Well then, use the same concept.

Create a dummy unit at the position that the person would teleport to, and use SetUnitLocation on it.

After that, check if the dummy unit moved more than about 10 distance (don't check if it moved more than 0 distance because that will usually true because of the inexactness of reals in WC3).

If it did, that means that the spot is not pathable and you can give an error message. If not, it means the spot is clear and you can move the player unit there.
03-13-2007, 07:27 PM#5
Pyrogasm
Hows about using your CheckPathability() function, grim001?
03-13-2007, 08:21 PM#6
grim001
Yeah, that does the same thing, it's just a little more complicated to set up.

Collapse JASS:
function CheckPathability takes unit u, real x, real y returns boolean
    local real ox = GetUnitX(u)
    local real oy = GetUnitY(u)
    if x > 9376. or x < -9632. or y > 9376. or y < -9632. then    //map bounds
        return false
    endif
    call SetUnitX(u, -9472.) //move unit to safespot
    call SetUnitY(u, 9216.)
    call SetUnitPosition(checkpathabilityunit, x, y) //requires global unit here
    set x = GetUnitX(checkpathabilityunit)-x
    set y = GetUnitY(checkpathabilityunit)-y
    call SetUnitX(checkpathabilityunit, -9472.) //moves global unit back to safespot
    call SetUnitY(checkpathabilityunit, 9216.)
    call SetUnitX(u, ox)
    call SetUnitY(u, oy)
    return x*x+y*y <= 100.
endfunction

This function moves the original unit to a safespot while it's doing the check so that it doesn't screw up a pathability check in a spot that is very close to the unit's own location. This is very useful when you're making units slide but you want to make sure they don't slide inside of buildings or off cliffs or inside other units.

Collapse JASS:
function CheckPathability_IgnoreUnits takes real x, real y returns boolean
    if x > 9376. or x < -9632. or y > 9376. or y < -9632. then    //map bounds
        return false
    endif
    call SetItemPosition(checkpathabilityitem,x,y) //requires global item
    call SetItemVisible(checkpathabilityitem, false)
    set x = GetItemX(checkpathabilityitem)-x
    set y = GetItemY(checkpathabilityitem)-y
    return x*x+y*y <=100
endfunction
This function will ignore units in the pathability check and doesn't require any kind of safespot. This is probably the one you want to use for your application.
03-14-2007, 02:18 AM#7
Earth-Fury
Quote:
Originally Posted by grim001
Yeah, that does the same thing, it's just a little more complicated to set up.

Collapse JASS:
function CheckPathability takes unit u, real x, real y returns boolean
    local real ox = GetUnitX(u)
    local real oy = GetUnitY(u)
    if x > 9376. or x < -9632. or y > 9376. or y < -9632. then    //map bounds
        return false
    endif
    call SetUnitX(u, -9472.) //move unit to safespot
    call SetUnitY(u, 9216.)
    call SetUnitPosition(checkpathabilityunit, x, y) //requires global unit here
    set x = GetUnitX(checkpathabilityunit)-x
    set y = GetUnitY(checkpathabilityunit)-y
    call SetUnitX(checkpathabilityunit, -9472.) //moves global unit back to safespot
    call SetUnitY(checkpathabilityunit, 9216.)
    call SetUnitX(u, ox)
    call SetUnitY(u, oy)
    return x*x+y*y <= 100.
endfunction

This function moves the original unit to a safespot while it's doing the check so that it doesn't screw up a pathability check in a spot that is very close to the unit's own location. This is very useful when you're making units slide but you want to make sure they don't slide inside of buildings or off cliffs or inside other units.

Collapse JASS:
function CheckPathability_IgnoreUnits takes real x, real y returns boolean
    if x > 9376. or x < -9632. or y > 9376. or y < -9632. then    //map bounds
        return false
    endif
    call SetItemPosition(checkpathabilityitem,x,y) //requires global item
    call SetItemVisible(checkpathabilityitem, false)
    set x = GetItemX(checkpathabilityitem)-x
    set y = GetItemY(checkpathabilityitem)-y
    return x*x+y*y <=100
endfunction
This function will ignore units in the pathability check and doesn't require any kind of safespot. This is probably the one you want to use for your application.

But wouldnt it be more effective to use multiple unit types for comparing units of diffrent sizes, instead of having to check multiple spots with items? and isnt there even a function to change a units colission size? whereas items are only 1 size ;) But, thanks! I have a good start point now! +rep
03-14-2007, 02:47 AM#8
grim001
Quote:
Originally Posted by Earth-Fury
But wouldnt it be more effective to use multiple unit types for comparing units of diffrent sizes
If you really wanted that level of precision you could, but I have not found it to have any practical effect on anything.

Quote:
Originally Posted by Earth-Fury
instead of having to check multiple spots with items?
You don't need to check multiple spots, you just check the exact spot you want to move the unit to.
03-14-2007, 03:27 AM#9
Earth-Fury
Quote:
Originally Posted by grim001
You don't need to check multiple spots, you just check the exact spot you want to move the unit to.

Except for the fact that items can fit in some spaces some units cannot.

Example:
X = No ground pathing
O = Ground pathable
S = Spot the unit 'wants' to go to, is ground pathable

XXOXXOXX
XXOXXOXX
OOOSOOOO
XXOXXOXX
XXOXXOXX


Lets say each X or O is 1/4 the size of a farm. If the unit is a pesant, he should be able to go there. If the unit is a paladin / other hero, they should NOT, because they cant actually FIT there. But if you just check with an item which can fit there, then the largest part of checking if the ground is pathable is lost, because units of larger-then-items collision size will invalidate the system in such an instance. Unless im missing something. (With me, thats always a possability )

What i was saying with that is that it would still be possable to check with an item, but for each point you check, you would have to check more and more point around the requested movement location inorder to find a pathable area.

XXX
XSO
XOO


you would have to find a space big enogh for a large unit around point S by individually checking each section. which is rather ineficient, even at such a small resolution.


Edit:

Heres what i've come up with:
Collapse JASS:
globals
    integer array udg_PathingUnits
endglobals

function CheckPathability takes real x, real y, integer pathing_type returns boolean
    local location l = Location( x, y )
    local unit u = CreateUnitAtLoc( Player(15), udg_PathingUnits[pathing_type], l, 0.0 )
    
    set x = GetUnitX(u) + x
    set y = GetUnitY(u) + y
    
    call RemoveUnit( u )
    set u = null
    
    return x*x+y*y <= 100
endfunction

function MoveUnitPathingSafe takes unit u, real x, real y, integer pathing_type returns boolean
    local location l
    
    if ( CheckPathability( x, y, pathing_type ) ) then
        set l = Location( x, y )
        call SetUnitPositionLoc( u, l )
        
        call RemoveLocation( l )
        set l = null
        
        return TRUE
    endif
    
    return FALSE
endfunction

where udg_PathingUnits is an array of unit types set at map initialization.
I haven't tested this yet, but from the testing i have done, this should work just fine. (but i may have made a mistake ^^')
03-14-2007, 01:37 PM#10
grim001
sure, you could even make an array of units 1-48 with different collision sizes...

it depends on how much accuracy you want