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

Check if player's camera is viewing a point?

Status
Not open for further replies.
Level 14
Joined
Aug 8, 2010
Messages
1,022
Hello, i wanna ask if i can check whether or not a player's camera is on a point. I have created a spell and i want the screen to flash with the "Cinematic" action but only for the players who have their camera near the point of ability cast. How should i do this? I don't think this can be accomplished trough GUI, so perhaps Jass is the solution.

Thanks in advance, mates!
 
Level 33
Joined
Mar 27, 2008
Messages
8,035
Try this.

The function for it to detect which point does the camera stays is GetCameraTargetPositionLoc()
Although, I don't know how to filter which Player does the function belongs to.
I guess it only works for Player 1.
 

Attachments

  • test14.w3x
    12.5 KB · Views: 36
Level 14
Joined
Aug 8, 2010
Messages
1,022
Here :
  • Melee Initialization
    • Events
      • Time - Every 0.15 seconds of game time
    • Conditions
    • Actions
      • Set TempLoc = (Position of Blood Mage 0000 <gen>)
      • For each (Integer A) from 1 to 12, do (Actions)
        • Loop - Actions
          • Set TempLoopNumber = (Integer A)
          • Custom script: set udg_TempLoc2[udg_TempLoopNumber] = GetCameraTargetPositionLoc()
          • Set TempReal[TempLoopNumber] = (Distance between TempLoc and TempLoc2[TempLoopNumber])
          • If (All Conditions are True) then do (Then Actions) else do (Else Actions)
            • If - Conditions
              • TempReal[TempLoopNumber] Less than 600.00
            • Then - Actions
              • Player Group - Add (Player((Integer A))) to TempPlayerGroup
            • Else - Actions
          • Custom script: if IsPlayerInForce(GetLocalPlayer(),udg_TempPlayerGroup) then
          • Cinematic - Fade in over 0.10 seconds using texture White Mask and color (100.00%, 100.00%, 100.00%) with 0.00% transparency
          • Custom script: endif
          • Custom script: call RemoveLocation(udg_TempLoc2[udg_TempLoopNumber])
      • Player Group - Remove all players from TempPlayerGroup
      • Custom script: call RemoveLocation(udg_TempLoc)
it works but i don't know if it's MPI... :/ However, it does what i want. I use this TempLoopNumber variable because i don't know how to make the array in Jass to be Integer A...

EDIT : I have tested it with my friend, it works. Thanks a lot!
 
Last edited:
Level 33
Joined
Mar 27, 2008
Messages
8,035
Well if it returns local value for each player, how does the trigger will look like ?
We have to loop it 12 times like what cold bone did ?

I mean the trigger don't know which player is currently triggering the trigger, therefore we need loop to determine GetCameraTargetPositionLoc() for each player ?
Like in loop 1, for Player 1, loop 2 for Player 2, and so on ?
 
Level 14
Joined
Aug 8, 2010
Messages
1,022
I think we are kinda talking about Jass here, so i might be wrong but i think that we should loop because the variable in which the GetCameraTargetPositionUnit() is set can not determine what player to pick with no array. So if the variable that stores the value does not have array, then the system will not know which player to pick - it can't pick a random player, so it should pick player 1. However, if it does have an array, things should be the same because i don't think that the system can set the array to be equal to the player number by its self...
 
Level 20
Joined
Jul 6, 2009
Messages
1,885
The way CoLd Bon3 did it, every player gets a different array with same values per player. I'm not sure how safe that is since it can locally add a player to a force (player group).

I would probably do something like this
  • Melee Initialization
    • Events
      • Time - Every 0.15 seconds of game time
    • Conditions
    • Actions
      • Set TempLoc = (Position of Blood Mage 0000 <gen>)
      • Custom script: set udg_TempLoc2 = GetCameraTargetPositionLoc()
      • If (All Conditions are True) then do (Then Actions) else do (Else Actions)
        • If - Conditions
          • Distance between TempLoc and TempLoc2 Less than 600.00
        • Then - Actions
          • Cinematic - Fade in over 0.10 seconds using texture White Mask and color (100.00%, 100.00%, 100.00%) with 0.00% transparency
        • Else - Actions
      • Custom script: call RemoveLocation(udg_TempLoc)
      • Custom script: call RemoveLocation(udg_TempLoc2)
Since the values are local, this should work.

One thing that bothers me is that GetCameraTargetPositionLoc() probably creates asynchronous location so it might be be better to use coordinates instead.

I'm not sure if what I posted is correct, but I'll test it tomorrow.
 
Level 33
Joined
Mar 27, 2008
Messages
8,035
Oh so you're saying that GetCameraTargetPositionLoc() already return values per player ?
Meaning that we don't have to further modify it to get each values per player ?

If you want to use reals, then here is the answer;
GetCameraTargetPositionX/Y/Z()
Although I'm not sure does Z plays important role in this particular case or not.
 
Level 14
Joined
Aug 8, 2010
Messages
1,022
Oh so you're saying that GetCameraTargetPositionLoc() already return values per player ?
Meaning that we don't have to further modify it to get each values per player ?
I think... yes? I think it does this, automatically :
  • Player Group - Pick every player in (All players) and do (Actions)
    • Loop - Actions
      • Custom script: set udg_FilterCameraLoc[udg_FilterLoopNumber] = GetCameraTargetPositionLoc()
I have actually changed the trigger a little bit :
  • Filters
    • Events
      • Unit - Blood Mage 0000 <gen> Takes damage
    • Conditions
    • Actions
      • Set FilterPoint = (Position of Blood Mage 0000 <gen>)
      • For each (Integer A) from 1 to 12, do (Actions)
        • Loop - Actions
          • Set FilterLoopNumber = (Integer A)
          • Custom script: set udg_FilterCameraLoc[udg_FilterLoopNumber] = GetCameraTargetPositionLoc()
          • Set FilterDistance[FilterLoopNumber] = (Distance between FilterPoint and FilterCameraLoc[FilterLoopNumber])
          • If (All Conditions are True) then do (Then Actions) else do (Else Actions)
            • If - Conditions
              • FilterDistance[FilterLoopNumber] Less than 600.00
            • Then - Actions
              • Player Group - Add (Player((Integer A))) to FilterPlayerGroup
            • Else - Actions
          • Player Group - Pick every player in (All players) and do (Actions)
            • Loop - Actions
              • Custom script: if IsPlayerInForce(GetLocalPlayer(),udg_FilterPlayerGroup) then
              • Cinematic - Fade in over 0.30 seconds using texture White Mask and color (100.00%, 0.00%, 0.00%) with (Percentage life of (Triggering unit))% transparency
              • Custom script: endif
          • Custom script: call RemoveLocation(udg_FilterCameraLoc[udg_FilterLoopNumber])
      • Player Group - Remove all players from FilterPlayerGroup
      • Custom script: call RemoveLocation(udg_FilterPoint)
It still works, i tested. However, i don't know if it's practical. Can someone tell me?

P.S. : I changed the variables' names because i used the trigger in my map.
 
Level 33
Joined
Mar 27, 2008
Messages
8,035
I don't know, if Garfield said is true, you are actually setting values 12 times per player, making it you're setting values for 144 times for all 12 players.

Because each that function returns 12 values for each player, if you repeat it 12 times, won't that be 144 ?

At the trigger itself, change GetCameraTargetPositionLoc() -> GetCameraTargetPositionX/Y()

But I guess that without arrays and looping, how would the trigger acknowledge which value belongs to which player ?

Perhaps using looping is needed here.
 
Level 14
Joined
Aug 8, 2010
Messages
1,022
At the trigger itself, change GetCameraTargetPositionLoc() -> GetCameraTargetPositionX/Y()

But I guess that without arrays and looping, how would the trigger acknowledge which value belongs to which player ?

Perhaps using looping is needed here.
Wouldn't it be the same? The first time you store locations, the second time you store reals. The locations are different, the reals are too. It should also be the same if you store units, destructibles, integers, everything. At least that's what i think.

About the 144 values... ill test this right away.

EDIT : It loops only 12 times. I created an action that creates a unit on the camera location. I made it loop only 3 times. The result was 3 units, instead of 36. I also made sure that there are actually players. Also, when i removed the Integer A loop, the trigger made the game crash...
 
Level 33
Joined
Mar 27, 2008
Messages
8,035
Wouldn't it be the same? The first time you store locations, the second time you store reals. The locations are different, the reals are too. It should also be the same if you store units, destructibles, integers, everything. At least that's what i think.
I mean, using Reals instead of Locations.
Locations create handles, while reals don't.
It improves your trigger's performance.
 
Level 20
Joined
Jul 6, 2009
Messages
1,885
I ran a test with a friend and the method I posted worked as expected, asynchronous locations didn't seem to cause a desync unless interacted with synced actions.
Your trigger doesn't loop 144 times, but using arrays isn't necessary as every player will have an array of same values and those values will be different for each player.
 
Level 22
Joined
Dec 31, 2006
Messages
2,216
Pffft, real men aim for accuracy.

This function will properly detect if a point is visible on your screen (sorry, it will not detect if it's occluded by units or hills). It basically just checks if it's within your view frustum in a herpy derpy way. There may or may not be a better way to get the same result this function provides. I just combined trig and basic algebra.

Enjoy:
JASS:
function IsPointVisible takes real px, real py, real pz returns boolean
    local real Cpx = GetCameraEyePositionX()
    local real Cpy = GetCameraEyePositionY()
    local real Cpz = GetCameraEyePositionZ()

    local real Crot = GetCameraField(CAMERA_FIELD_ROTATION)
    local real Caoa = GetCameraField(CAMERA_FIELD_ANGLE_OF_ATTACK)
    local real Cfov = GetCameraField(CAMERA_FIELD_FIELD_OF_VIEW)/2.
    
    local real Dx = Cos(Crot)*Cos(Caoa)
    local real Dy = Sin(Crot)*Cos(Caoa)
    local real Dz = Sin(Caoa)
    
    local real Crx = Sin(Crot)
    local real Cry = -Cos(Crot)
    
    local real Cux = Cry * Dz
    local real Cuy = -Dz * Crx
    local real Cuz = Crx * Dy - Dx * Cry
    
    local real d = -(-Dx*px - Dy*py - Dz*pz)
    local real u = (-d - (-Dx*Cpx - Dy*Cpy - Dz*Cpz))/(-Dx*Dx - Dy*Dy - Dz*Dz)
    
    local real Pw = u*Tan(Cfov)
    local real Ph = u*Tan(Cfov/1.4)
    
    local real Qx = Cpx + Dx*u
    local real Qy = Cpy + Dy*u
    local real Qz = Cpz + Dz*u
    
    local real QPx = px - Qx
    local real QPy = py - Qy
    local real QPz = pz - Qz
    
    local real dot = QPx*Crx + QPy*Cry
    
    local real Projx = Crx*dot
    local real Projy = Cry*dot
    local real Projz = 0
    
    if (Projx*Projx + Projy*Projy < Pw*Pw) then
        set dot = QPx*Cux + QPy*Cuy + QPz*Cuz
        set Projx = Cux*dot
        set Projy = Cuy*dot
        set Projz = Cuz*dot
        
        if (Projx*Projx + Projy*Projy + Projz*Projz < Ph*Ph) then
            return true
        endif
    endif
    
    return false
endfunction

It's relatively simple to use as well. Just use it like so:
JASS:
if IsPointVisible(durr) then
    //Do your cinematic shit in here. Do not touch units or other shit (basically any handles) inside here as that will cause a desync
endif

Or in GUI:
  • Custom script: if IsPointVisible(durr) then
  • <do shit>
  • Custom script: endif
Edit: Btw, it doesn't work with roll.
 
Last edited:
Level 17
Joined
Apr 27, 2008
Messages
2,455
So how these functions work ?

constant native IsVisibleToPlayer takes real x, real y, player whichPlayer returns boolean
constant native IsLocationVisibleToPlayer takes location whichLocation, player whichPlayer returns boolean

I mean maybe it does exactly what you want (i have not tested them).

Also i'm not sure about the GUI cinematic fade stuff, because a time is involved, no timer, TriggerSleepAction or PolledWait in the background ?
If there is one of them, then -> desync.
 
Level 22
Joined
Dec 31, 2006
Messages
2,216
So how these functions work ?

constant native IsVisibleToPlayer takes real x, real y, player whichPlayer returns boolean
constant native IsLocationVisibleToPlayer takes location whichLocation, player whichPlayer returns boolean

I mean maybe it does exactly what you want (i have not tested them).

That ignores screen position. It simply checks if the point is in fog of war. Same with IsUnitVisible.

Anti-maphack code uses those functions.
 
Level 14
Joined
Aug 8, 2010
Messages
1,022
That ignores screen position. It simply checks if the point is in fog of war. Same with IsUnitVisible.

Anti-maphack code uses those functions.
So i simply need to get the 12 points for the 12 players and check whether or not the point is visible trough "constant native IsLocationVisibleToPlayer takes location whichLocation, player whichPlayer returns boolean". It looks a lot more easy than your hardcore Jass :eekani:. I mean, i simply have to add this function to my code.
 
Level 22
Joined
Dec 31, 2006
Messages
2,216
So i simply need to get the 12 points for the 12 players and check whether or not the point is visible trough "constant native IsLocationVisibleToPlayer takes location whichLocation, player whichPlayer returns boolean". It looks a lot more easy than your hardcore Jass :eekani:. I mean, i simply have to add this function to my code.

No, as I said: That checks if the location/point is hidden in fog of war or not. It does not tell you if it's currently visible on your screen. If you try the functions IsLocationVisibleToPlayer or IsVisibleToPlayer on a map that is entirely visible, it will always return true regardless of which point you're testing, and regardless of your camera position and orientation.

My code checks if the point is within the borders of your window, and it takes into account position and orientation as well as field of view. It does not account for roll however, but roll is pretty much never used (you can only roll a camera through triggers). It will also return true even if the point is hidden behind UI, but there's nothing I can do about that.
 
Status
Not open for further replies.
Top