• 🏆 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!

Checking a point in a triangle

Status
Not open for further replies.
Level 2
Joined
Aug 26, 2020
Messages
12
Hello, i am trying to create a spell which selects units who are in a triangle inside a 1200 unit radius.
So far i have read up about it and found this thread: [vJASS] - Is Point In Triangle and i've chosen this script
JASS:
function IsPointInTriangle takes real px, real py, real ax, real ay, real bx, real by, real cx, real cy returns boolean
local boolean b1 = (px - bx) * (ay - by) - (ax - bx) * (py - by) < 0.0
local boolean b2 = (px - cx) * (by - cy) - (bx - cx) * (py - cy) < 0.0
local boolean b3 = (px - ax) * (cy - ay) - (cx - ax) * (py - ay) < 0.0
return b1 == b2 and b2 == b3
endfunction
Thing is, i do not know how to use this custom script to check whether the point of the unit is within the triangle shape.
The trigger looks like this, the point of the spell is to push Hero units who are within the triangle away from the hero casting, the test map is attached below. The version of Warcraft 3 i am using is 1.26, if it matters.
image.png
 

Attachments

  • triangle.w3x
    17.7 KB · Views: 6
Level 39
Joined
Feb 27, 2007
Messages
5,010
You give that function 4 pairs of xy coordinates: the point to check and 3 vertices for a triangle. It says true if the point is in the triangle. There are an infinite number of triangles you could draw over the units within 1200, but I presume you want an equilateral one. Which way should the triangle 'point'? I presume in the facing direction of the unit that cast.

So put that function inside your map's Custom Script section (click on your map icon in the trigger editor and paste there), then you generate the 3 vertices by doing some polar offset stuff and feed those 3 plus the location of the picked unit into the function. In order to do this, you'll assign a global boolean variable to the output of the function call. If that variable is true, then you do whatever you wanted to do because the unit was inside the triangle. Note that this will not consider unit collision, so a unit very close to the edge of a triangle might not have its center inside the triangle even though it appears to overlap with it. Just consider that.

Also you're leaking a point of each unit every time they're moved (the new location made by offsetting), and you never actually filtered your unit group to

  • Set TCLocation = (Position of (Triggering Unit))
  • Set TCFace = (Facing angle of (Triggering Unit))
  • Set TCRadius = 1200.00
  • Set TCVertex[1] = TCLocation offset by TCRadius towards TCFace degrees
  • Set TCVertex[2] = TCLocation offset by TCRadius towards (TCFace + 120.00) degrees
  • Set TCVertex[3] = TCLocation offset by TCRadius towards (TCFace - 120.00) degrees
  • For each (Integer A) from 1 to 3 do (Actions)
    • Loop - Actions
      • Set TCVx[(Integer A)] = (X-coordinate of TCVertex[(Integer A)])
      • Set TCVy[(Integer A)] = (Y-coordinate of TCVertex[(Integer A)])
  • Custom script: set bj_wantDestroyGroup = true
  • Unit Group - Pick every unit in (Units within TCRadius of TCLocation) and do (Actions)
    • Loop - Actions
      • Set TCFilterUnit = (Picked Unit)
      • If (All conditions are true) then do (Then actions) else do (Else actions)
        • If - Conditions
          • (TCFIlterUnit is a Hero) equal to True
          • -------- put other conditions to filter your targets here --------
        • Then - Actions
          • Set TCVertex[0] = (Position of TCFilterUnit)
          • Set TCVx[0] = (X-coordinate of TCVertex[0]]
          • Set TCVy[0] = (Y-coordinate of TCVertex[0]]
          • Custom script: call RemoveLocation(udg_TCVertex[0])
          • -------- match the name of the variables below with the ones you actually use in your map; keep the udg_ prefix, it's added by the WE --------
          • Custom script: set udg_TCBool = IsPointInTriangle(udg_TCVx[0], udg_TCVy[0], udg_TCVx[1], udg_TCVy[1], udg_TCVx[2], udg_TCVy[2], udg_TCVx[3], udg_TCVy[3])
          • If (All conditions are true) then do (Then actions) else do (Else actions)
            • If - Conditions
              • TCBool equal to True
            • Then - Actions
              • -------- do whatever you need to the units inside the triangle here. knockback or whatever! --------
            • Else - Actions
        • Else - Actions
  • Custom script: call RemoveLocation(udg_TCVertex[1])
  • Custom script: call RemoveLocation(udg_TCVertex[2])
  • Custom script: call RemoveLocation(udg_TCVertex[3])
  • Custom script: call RemoveLocation(udg_TCLocation)
You could also generate the xy coordinates of the vertices with some simple math instead of doing the point bologna, but I'm guessing you're more familiar with points.
 
Level 2
Joined
Aug 26, 2020
Messages
12
You give that function 4 pairs of xy coordinates: the point to check and 3 vertices for a triangle. It says true if the point is in the triangle. There are an infinite number of triangles you could draw over the units within 1200, but I presume you want an equilateral one. Which way should the triangle 'point'? I presume in the facing direction of the unit that cast.

So put that function inside your map's Custom Script section (click on your map icon in the trigger editor and paste there), then you generate the 3 vertices by doing some polar offset stuff and feed those 3 plus the location of the picked unit into the function. In order to do this, you'll assign a global boolean variable to the output of the function call. If that variable is true, then you do whatever you wanted to do because the unit was inside the triangle. Note that this will not consider unit collision, so a unit very close to the edge of a triangle might not have its center inside the triangle even though it appears to overlap with it. Just consider that.

Also you're leaking a point of each unit every time they're moved (the new location made by offsetting), and you never actually filtered your unit group to

  • Set TCLocation = (Position of (Triggering Unit))
  • Set TCFace = (Facing angle of (Triggering Unit))
  • Set TCRadius = 1200.00
  • Set TCVertex[1] = TCLocation offset by TCRadius towards TCFace degrees
  • Set TCVertex[2] = TCLocation offset by TCRadius towards (TCFace + 120.00) degrees
  • Set TCVertex[3] = TCLocation offset by TCRadius towards (TCFace - 120.00) degrees
  • For each (Integer A) from 1 to 3 do (Actions)
    • Loop - Actions
      • Set TCVx[(Integer A)] = (X-coordinate of TCVertex[(Integer A)])
      • Set TCVy[(Integer A)] = (Y-coordinate of TCVertex[(Integer A)])
  • Custom script: set bj_wantDestroyGroup = true
  • Unit Group - Pick every unit in (Units within TCRadius of TCLocation) and do (Actions)
    • Loop - Actions
      • Set TCFilterUnit = (Picked Unit)
      • If (All conditions are true) then do (Then actions) else do (Else actions)
        • If - Conditions
          • (TCFIlterUnit is a Hero) equal to True
          • -------- put other conditions to filter your targets here --------
        • Then - Actions
          • Set TCVertex[0] = (Position of TCFilterUnit)
          • Set TCVx[0] = (X-coordinate of TCVertex[0]]
          • Set TCVy[0] = (Y-coordinate of TCVertex[0]]
          • Custom script: call RemoveLocation(udg_TCVertex[0])
          • -------- match the name of the variables below with the ones you actually use in your map; keep the udg_ prefix, it's added by the WE --------
          • Custom script: set udg_TCBool = IsPointInTriangle(udg_TCVx[0], udg_TCVy[0], udg_TCVx[1], udg_TCVy[1], udg_TCVx[2], udg_TCVy[2], udg_TCVx[3], udg_TCVy[3])
          • If (All conditions are true) then do (Then actions) else do (Else actions)
            • If - Conditions
              • TCBool equal to True
            • Then - Actions
              • -------- do whatever you need to the units inside the triangle here. knockback or whatever! --------
            • Else - Actions
        • Else - Actions
  • Custom script: call RemoveLocation(udg_TCVertex[1])
  • Custom script: call RemoveLocation(udg_TCVertex[2])
  • Custom script: call RemoveLocation(udg_TCVertex[3])
  • Custom script: call RemoveLocation(udg_TCLocation)
You could also generate the xy coordinates of the vertices with some simple math instead of doing the point bologna, but I'm guessing you're more familiar with points.
Outstanding, perfect, just what i needed, i'm nearly done replicating the trigger now.
Could you please tell me which variable type TCVx and TCVy and the array of them?
Also, how do i set Set TCVx[(Integer A)] = (X-coordinate of TCVertex[(Integer A)]) and Set TCVy[(Integer A)] = (Y-coordinate of TCVertex[(Integer A)])?
 
Level 2
Joined
Aug 26, 2020
Messages
12
…think about it. What is a coordinate? It’s a number. What are numbers?

Look for the one that literally says x/y coordinate of point. It’s a GUI function.
Right, my bad, thinking's not my strong suit. Also, is it specifically "x/y coordinate of point" or does X/Y of point suffice? I cannot find the coordinate option, could it have something to do with my game version being 1.26?
As in, would this work?

coordinatemaxxing.png
 

Attachments

  • coordinate.png
    coordinate.png
    14.4 KB · Views: 6

Uncle

Warcraft Moderator
Level 64
Joined
Aug 10, 2018
Messages
6,535
@Plebbetry
Yes, the X of Point function gets you the X coordinate of a Point. X, Y, and Z are almost always referring to coordinates in Warcraft 3.

Inside of the World Editor you can see in the bottom left corner there are three numbers next to the word "Point:". These are the X, Y, and Z coordinates of your current mouse position inside of the map. See the attached picture for an example. Anything you create in the map uses these coordinates to determine where it should be placed.

So that gives us a clue as to what a Point variable really is, a collection of X, Y, and Z coordinates. And what's a coordinate? It's a Real number, because we can clearly see it has a decimal place which Integers do not have. When working with numbers in Warcraft 3 they will either be Integers or Reals.

With this in mind, it's important to understand that whenever you're referencing some position in the game, whether that be the center of a region, at the position of a unit, or at a preset Point variable, in the end you're actually referencing the X/Y coordinates of that position.

The reason these concepts exist is because directly referencing the x/y coordinates of your map is less user-friendly. For example, would you rather Create a unit at the "Center of the playable map" or at X: 0, Y: 0. For the average user, the center of the map is much easier to understand.

If you ever get into coding your maps in Jass/Lua (technically you are coding when you use the Custom Script action), you'll find that there are functions that allow you to reference x/y coordinates directly. CreateUnit(), CreateItem(), SetUnitPosition(), etc... All of these functions reference x/y coordinates instead of Point variables. This is because outside of GUI it's usually unnecessary to use a Point since referencing the coordinates directly is almost always better as it's more efficient and clean.
 

Attachments

  • point exa.png
    point exa.png
    2.3 MB · Views: 7
Last edited:
Level 2
Joined
Aug 26, 2020
Messages
12
I expected as much, but thanks for putting it so clearly.
Now, i have replicated the trigger by Pyrogasm and i'm getting a compile error.
compile error.png
 
Level 39
Joined
Feb 27, 2007
Messages
5,010
Call should be lowercase call, but that’s not the only thing wrong.

It looks like you’re converting your triggers from GUI to JASS. You do not have to do that, just insert the custom script (JASS) line like I wrote above. You need to assign its output to a variable and give it all the appropriate arguments:

set udg_TCBool = IsPointInTriangle(udg_TCVx[0], udg_TCVy[0], udg_TCVx[1], udg_TCVy[1], udg_TCVx[2], udg_TCVy[2], udg_TCVx[3], udg_TCVy[3])
 
Level 2
Joined
Aug 26, 2020
Messages
12
Funny thing, i do not know how to convert a trigger from GUI to JASS and i couldn't find where the call started with an uppercase, turns out the first clumsy trigger i made was still on and was messing with the new trigger somehow, now i've turned it off and it works like a charm.
I cannot thank you and Uncle enough.
 

Uncle

Warcraft Moderator
Level 64
Joined
Aug 10, 2018
Messages
6,535
Funny thing, i do not know how to convert a trigger from GUI to JASS and i couldn't find where the call started with an uppercase, turns out the first clumsy trigger i made was still on and was messing with the new trigger somehow, now i've turned it off and it works like a charm.
I cannot thank you and Uncle enough.
Select the trigger you want to convert, click the Edit tab, and then click "Convert to Custom Text". That'll convert the trigger to Jass, although it'll be less optimized than if you were to write the Jass from scratch.

So whenever you get stuck while using Custom Script in GUI you can use this conversion method to see how things are done.

The rules are pretty simple though:
Setting a variable? You use the word "set".
  • Custom script: set udg_MyInteger = 1000
Calling/Running a function? You use the word "call".
  • Custom script: call KillUnit(udg_MyUnit)
I bet you can guess what the KillUnit() function does. It's the same exact thing as this:
  • Unit - Kill MyUnit
What you type inside the (parenthesis) of Jass code is no different from the fields that you click and choose from in your GUI Events/Conditions/Actions.
 
Last edited:
Status
Not open for further replies.
Top