Terrain Check

Azylaminaz

Vox Populi
Reaction score
91
I think I've put too much brainpower into this already... I'm clearly missing something. :X

OK, so, basically I want to create a "smarter" terrain check. The classic means (simply detecting the terrain with GetTerrainType) gives funny results because "terrain" is seen as simple squares, ignoring how the art actually looks. What I want is a system that accurately reflects the art....

Terrain actually works in triangles (eight per a traditional square).

GWogS.jpg

Blue & light blue: correctly valid
Purple: incorrectly valid
Red: correctly invalid
Green: incorrectly invalid
*valid means marble, invalid means square tiles.

This is also just one of two ways terrain can act. A tile can "bridge" over another type or "break" at it (in terms of going diagonally). Mrable is an example of bridging. Further more, a tile that bridges can over-extend past itself. Marble is an example of one that doesn't; brick, round/square tiles do over-extend.

Preloading the validity of each triangle would be near impossible as even a tiny map (52x52 playable) has 173,056 triangles. The other way would be simply detect on command. IE, pass over a point to check if it is valid or not - this is the approach I've been trying and failing on for days.

I've attacked this problem from a number of sides. -.- The following is my latest attempt at doing this.
Pre-note: View the terrain as a diamond-checkerboard. The deep-blue diamonds are an example of these (as well as the diamonds diagonally between them).

Rules for simple tiles such as marble:
1) Any diamond that contains three or more valid classically checked triangles is 100% valid (contains obvious blue diamonds as well as "3 light blue 1 green" diamonds)
2) Any diamond that contains two opposite triangles that share obtuse sides with blue triangles is 100% valid (contains diamonds that are bridges, "2 light blue 2 green")
3) Any diamond that contains two adjacent triangles that share obtuse sides with blue triangles is 50% valid, those sharing triangles being the valid ones (contains "2 light blue 2 red")
4) Every other triangle is invalid.

Step 1: For any given point, get a rigid point at the center of the corresponding diamond. IE, a point in any triangle will fall to exactly where the 90 degree angle is. Get angles radiating from the center of the diamond to the midpoints of the obtuse feeding triangles (45/135/225/315).

Step 2: Use above rules to see if a the triangle is valid or not.
I can probably pretty easily do step 2, the problem is step 1 (finding the center of diamonds/triangles). I want to tell myself the solution is obvious and I'm just running into a mental block, but eh. :/

Edit: OH. And my attempts at trying to find the center of dimaonds were:
First: To find if the x or y of the diamonds were closest. The x of the diamond would be Int(x / 64 + .5) * 64, the y similar. Whichever was closer would get it. The other would be +32 or -32. This simply wasn't working and was getting ugly with so many if's.

Second: To work in a rotated Cartesian system. I tried this by converting x/y to polar coordinates, rotating it by 45 degrees, converting back into Cartesian coordinates (on a rotated Cartesian plane, now). Then I'd simply do "Int(x / 64 + .5) * 64" and "Int(y / 64 + .5) * 64". I'd then turn these points back to polar, rotate by -45, and convert back to traditional Cartesian.

I was failing at converting back and fourth (was testing with a simple x = 1, y = 2; x' and y' being the values on the rotated field):
x' = (x^2 + y^2)^.5 * Cos(Atan2(y/x) + Pi/4)
y' = (x^2 + y^2)^.5 * Sin(Atan2(y/x) + Pi/4)

x = (x'^2 + y'^2)^.5 * Cos(Atan2(y'/x') - Pi/4)
y = (x'^2 + y'^2)^.5 * Sin(Atan2(y'/x') - Pi/4)

I failed.

Somebody help before I have an accident resulting in my unfortunate death. :X
 

Sgqvur

FullOfUltimateTruthsAndEt ernalPrinciples, i.e shi
Reaction score
62
Azylaminaz
1. Preloading the validity of each triangle would be near impossible as even a tiny map (52x52 playable) has 173,056 triangles.

1. Hm... shouldn't a hashtable do the job? Or maybe 10 hashtables, a 100? Your map can make use of the 256 limit for hashtables, and
256 limit for gamecaches, if you don't want to overload 1 single hashtable. I am not sure but maybe you can generate the need data
for the triangles with an external program and just copy it in to functions, and of course coupled with a dozen of ExecuteFunc calls, to
prevent hitting the oplimit. So I guess this could be a brute force solution.
 

inevit4ble

Well-Known Member
Reaction score
38
As I understand it, Position of Unit (GetUnitX/Y) gives the center point of the unit. As with regions, an event like UnitEntersRegion it will only trigger if the unit's center point enters the region.

Don't know if the will help but if the used the Position of Unit, you would have the center point of where the unit is standing and check terrain at Point?
 

Switch33

New Member
Reaction score
12
inevit4ble might have something there. You could place a unit per square then check a distance with the facing angles to get at least 4 of the triangles for the terrain.

Another maybe more realisitc approach for this might be to just export the terrain models from the mpq and re-create them as triangles somewhat?
 

Azylaminaz

Vox Populi
Reaction score
91
Have made some progress! Finally have hammered out my biggest problem: finding the reference point for any given point.

From here it should be free sailing, but considering this function may be called thousands of times a second, I'd love feedback on making it more efficient (ignoring the BJs, I mean another METHOD).

JASS:
function grabCenter takes real x, real y returns nothing
    local real x2
    local real y2
    if x < 0 then
        set x2 = R2I((x - 32)/64) * 64
    else
        set x2 = R2I((x + 32)/64) * 64
    endif
    if y < 0 then
        set y2 = R2I((y - 32)/64) * 64
    else
        set y2 = R2I((y + 32)/64) * 64
    endif
    if x2 + y2 != 0 and ModuloReal(x2 + y2, 128) != 0 then
        if ModuloReal(x, 32) < ModuloReal(y, 32) then
            call BJDebugMsg("a")
            if RAbsBJ(y2 + 64 - y) > RAbsBJ(y2 - 64 - y) then
                set y2 = y2 - 64
            else
                set y2 = y2 + 64
            endif
        else
            if RAbsBJ(x2 + 64 - x) > RAbsBJ(x2 - 64 - x) then
                set x2 = x2 - 64
            else
                set x2 = x2 + 64
            endif
        endif
    endif
    call BJDebugMsg("in: (" + R2S(x) + ", " + R2S(y) + "), out: (" + R2S(x2) + ", " + R2S(y2) + ")")
endfunction




Edit:
You guys aren't understanding the problem. The GetTerrainType() native returns false positives and false negatives, as depicted by the picture.
 

Azylaminaz

Vox Populi
Reaction score
91
Yee. :D I did it (well, sort of, it works for marble over... anything). :D

JASS:
globals
    integer array ttID  //NEEDS TO BE WRITTEN IN ORDER
    boolean array ttBridge
    string array ttName
endglobals

function getTerrainType takes real x, real y returns integer
    //variables for grabbing center of x/y (into x2/y2)
    local real x2
    local real y2
    local real modPrime
    local real modX
    local real modY
    local real upDif
    local real downDif
    //variables for finding terrain type
    local integer i
    local integer typeA = 0
    local integer typeB = 0
    if x < 0 then
        set x2 = R2I((x - 32)/64) * 64
    else
        set x2 = R2I((x + 32)/64) * 64
    endif
    if y < 0 then
        set y2 = R2I((y - 32)/64) * 64
    else
        set y2 = R2I((y + 32)/64) * 64
    endif
    if x2 + y2 != 0 then
        set modPrime = x2 + y2 - I2R(R2I((x2 + y2) / 128)) * 128
        if modPrime < 0 then
            set modPrime = modPrime + 128
        endif
        if modPrime != 0 then
            set modX = x - I2R(R2I(x / 32)) * 32
            if modX < 0 then
                set modX = modX + 32
            endif
            set modY = y - I2R(R2I(x / 32)) * 32
            if modY < 0 then
                set modY = modY + 32
            endif
            if modX < modY then
                set upDif = y2 + 64 - y
                if upDif < 0 then
                    set upDif = -upDif
                endif
                set downDif = y2 - 64 - y
                if downDif < 0 then
                    set downDif = -downDif
                endif
                if upDif > downDif then
                    set y2 = y2 - 64
                else
                    set y2 = y2 + 64
                endif
            else
                set upDif = x2 + 64 - x
                if upDif < 0 then
                    set upDif = -upDif
                endif
                set downDif = x2 - 64 - x
                if downDif < 0 then
                    set downDif = -downDif
                endif
                if upDif > downDif then
                    set x2 = x2 - 64
                else
                    set x2 = x2 + 64
                endif
            endif
        endif
    endif
    
    //simple diamond
    if GetTerrainType(x2 + 16, y2 + 16) == GetTerrainType(x2 - 16, y2 + 16) and GetTerrainType(x2 + 16, y2 + 16) == GetTerrainType(x2 - 16, y2 - 16) then
        return GetTerrainType(x2 + 16, y2 + 16)
    elseif GetTerrainType(x2 + 16, y2 + 16) == GetTerrainType(x2 - 16, y2 + 16) and GetTerrainType(x2 + 16, y2 + 16) == GetTerrainType(x2 + 16, y2 - 16) then
        return GetTerrainType(x2 + 16, y2 + 16)
    elseif GetTerrainType(x2 + 16, y2 + 16) == GetTerrainType(x2 - 16, y2 - 16) and GetTerrainType(x2 + 16, y2 + 16) == GetTerrainType(x2 + 16, y2 - 16) then
        return GetTerrainType(x2 + 16, y2 + 16)
    elseif GetTerrainType(x2 - 16, y2 - 16) == GetTerrainType(x2 + 16, y2 - 16) and GetTerrainType(x2 - 16, y2 - 16) == GetTerrainType(x2 - 16, y2 + 16) then
        return GetTerrainType(x2 - 16, y2 - 16)
    endif
    
    //adjacent
    if x >= x2 and GetTerrainType(x2 + 48, y2 + 48) == GetTerrainType(x2 + 48, y2 - 48) then
        return GetTerrainType(x2 + 48, y2 + 48)
    elseif y >= y2 and GetTerrainType(x2 + 48, y2 + 48) == GetTerrainType(x2 - 48, y2 + 48) then
        return GetTerrainType(x2 + 48, y2 + 48)
    elseif x <= x2 and GetTerrainType(x2 - 48, y2 - 48) == GetTerrainType(x2 - 48, y2 + 48) then
        return GetTerrainType(x2 - 48, y2 + 48)
    elseif y <= y2 and GetTerrainType(x2 - 48, y2 - 48) == GetTerrainType(x2 + 48, y2 - 48) then
        return GetTerrainType(x2 - 48, y2 - 48)
    endif
    
    //diangol IN REALITY I NEED TO CHECK IF IT BRIDGES
    if GetTerrainType(x2 + 48, y2 + 48) == GetTerrainType(x2 - 48, y2 - 48) then
        set typeA = GetTerrainType(x2 + 48, y2 + 48)
    endif
    if GetTerrainType(x2 + 48, y2 - 48) == GetTerrainType(x2 - 48, y2 + 48) then
        set typeB = GetTerrainType(x2 + 48, y2 - 48)
    endif
    
    if typeA != 0 and typeB != 0 then
        set i = 0
        loop
            if ttID<i> == typeA then
                return typeA
            elseif ttID<i> == typeB then
                return typeB
            endif
            if ttID<i> == null then
                exitwhen true
            endif
            set i = i + 1
        endloop
    else
        if typeA != 0 then
            return typeA
        elseif typeB != 0 then
            return typeB
        endif
    endif
    
    return 0
endfunction

function Trig_Center_Actions takes nothing returns nothing
    local integer terrain
    call Split(GetEventPlayerChatString(), &quot; &quot;, false)
    set terrain = getTerrainType(S2I(myArg[0]), S2I(myArg[1]))
    if terrain == &#039;Xwmb&#039; then
        call BJDebugMsg(&quot;marble&quot;)
    elseif terrain == &#039;Xsqd&#039; then
        call BJDebugMsg(&quot;square tile&quot;)
    else
        call BJDebugMsg(&quot;IDK&quot;)
    endif
endfunction

//===========================================================================
function InitTrig_Center takes nothing returns nothing
    set gg_trg_Center = CreateTrigger(  )
    call TriggerAddAction( gg_trg_Center, function Trig_Center_Actions )
    call TriggerRegisterPlayerChatEvent(gg_trg_Center, Player(0), &quot;&quot;, false)
    
    set ttID[0] = &#039;Xwmb&#039;
    set ttBridge[0] = true
    set ttName[0] = &quot;marble&quot;
    
    set ttID[1] = &#039;Xsqd&#039;
    set ttBridge[1] = false
endfunction</i></i></i>
 
General chit-chat
Help Users
  • No one is chatting at the moment.
  • Varine Varine:
    How can you tell the difference between real traffic and indexing or AI generation bots?
  • The Helper The Helper:
    The bots will show up as users online in the forum software but they do not show up in my stats tracking. I am sure there are bots in the stats but the way alot of the bots treat the site do not show up on the stats
  • Varine Varine:
    I want to build a filtration system for my 3d printer, and that shit is so much more complicated than I thought it would be
  • Varine Varine:
    Apparently ABS emits styrene particulates which can be like .2 micrometers, which idk if the VOC detectors I have can even catch that
  • Varine Varine:
    Anyway I need to get some of those sensors and two air pressure sensors installed before an after the filters, which I need to figure out how to calculate the necessary pressure for and I have yet to find anything that tells me how to actually do that, just the cfm ratings
  • Varine Varine:
    And then I have to set up an arduino board to read those sensors, which I also don't know very much about but I have a whole bunch of crash course things for that
  • Varine Varine:
    These sensors are also a lot more than I thought they would be. Like 5 to 10 each, idk why but I assumed they would be like 2 dollars
  • Varine Varine:
    Another issue I'm learning is that a lot of the air quality sensors don't work at very high ambient temperatures. I'm planning on heating this enclosure to like 60C or so, and that's the upper limit of their functionality
  • Varine Varine:
    Although I don't know if I need to actually actively heat it or just let the plate and hotend bring the ambient temp to whatever it will, but even then I need to figure out an exfiltration for hot air. I think I kind of know what to do but it's still fucking confusing
  • The Helper The Helper:
    Maybe you could find some of that information from AC tech - like how they detect freon and such
  • Varine Varine:
    That's mostly what I've been looking at
  • Varine Varine:
    I don't think I'm dealing with quite the same pressures though, at the very least its a significantly smaller system. For the time being I'm just going to put together a quick scrubby box though and hope it works good enough to not make my house toxic
  • Varine Varine:
    I mean I don't use this enough to pose any significant danger I don't think, but I would still rather not be throwing styrene all over the air
  • The Helper The Helper:
    New dessert added to recipes Southern Pecan Praline Cake https://www.thehelper.net/threads/recipe-southern-pecan-praline-cake.193555/
  • The Helper The Helper:
    Another bot invasion 493 members online most of them bots that do not show up on stats
  • Varine Varine:
    I'm looking at a solid 378 guests, but 3 members. Of which two are me and VSNES. The third is unlisted, which makes me think its a ghost.
    +1
  • The Helper The Helper:
    Some members choose invisibility mode
    +1
  • The Helper The Helper:
    I bitch about Xenforo sometimes but it really is full featured you just have to really know what you are doing to get the most out of it.
  • The Helper The Helper:
    It is just not easy to fix styles and customize but it definitely can be done
  • The Helper The Helper:
    I do know this - xenforo dropped the ball by not keeping the vbulletin reputation comments as a feature. The loss of the Reputation comments data when we switched to Xenforo really was the death knell for the site when it came to all the users that left. I know I missed it so much and I got way less interested in the site when that feature was gone and I run the site.
  • Blackveiled Blackveiled:
    People love rep, lol
    +1
  • The Helper The Helper:
    The recipe today is Sloppy Joe Casserole - one of my faves LOL https://www.thehelper.net/threads/sloppy-joe-casserole-with-manwich.193585/
  • The Helper The Helper:
    Decided to put up a healthier type recipe to mix it up - Honey Garlic Shrimp Stir-Fry https://www.thehelper.net/threads/recipe-honey-garlic-shrimp-stir-fry.193595/

      The Helper Discord

      Members online

      No members online now.

      Affiliates

      Hive Workshop NUON Dome World Editor Tutorials

      Network Sponsors

      Apex Steel Pipe - Buys and sells Steel Pipe.
      Top