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

How many calculations is too many?

Status
Not open for further replies.
Level 14
Joined
Aug 30, 2004
Messages
909
I am working on a Star Wars game that uses dummy units for lasers and missiles. I keep coming up with more and more interesting ideas for it, which is unlike my previous maps I must say, but I'm concerned that I'm going to try to put too much in and cause the game to "lag" when too many people are playing. Here's a breakdown of the rapidly firing triggers:

The whole movement engine is based on a "for each integer 1-100, loop" that fires every .02 seconds and picks every one of the possible 100 units and moves them in the unit's facing direction. It checks the terrain to see if it's possible. Then it checks a point array (1-100 again) that stores where the ship is going and checks for whether it needs to turn. If so, it adjusts the facing angle of the unit. If the unit is a laser it also adjusts altitude as necessary.

All that happens every .02 seconds.

Every .07 seconds a trigger picks every laser and missile and sets up unit groups around them to see if any enemies are there. If so, they explode doing damage.

There are other repeat triggers, but they are much slower so I doubt they contribute much to the lag.

It lagged horribly before I learned how to remove leaks. Since then it doesn't appear to leak at all (I ran it on autopilot and went shopping, came back an hour later and it was still running fine). But I'm worried about how much I can cram into those repeat triggers without busting something.

Is there any way to test that? It needs to be playable on Battlenet as well. Is Battlenet slower than when I just playtest it myself?

Thank you,

Darwin
 
Level 11
Joined
Aug 6, 2009
Messages
697
I am working on a Star Wars game that uses dummy units for lasers and missiles. I keep coming up with more and more interesting ideas for it, which is unlike my previous maps I must say, but I'm concerned that I'm going to try to put too much in and cause the game to "lag" when too many people are playing. Here's a breakdown of the rapidly firing triggers:

The whole movement engine is based on a "for each integer 1-100, loop" that fires every .02 seconds and picks every one of the possible 100 units and moves them in the unit's facing direction. It checks the terrain to see if it's possible. Then it checks a point array (1-100 again) that stores where the ship is going and checks for whether it needs to turn. If so, it adjusts the facing angle of the unit. If the unit is a laser it also adjusts altitude as necessary.

All that happens every .02 seconds.

Every .07 seconds a trigger picks every laser and missile and sets up unit groups around them to see if any enemies are there. If so, they explode doing damage.

There are other repeat triggers, but they are much slower so I doubt they contribute much to the lag.

It lagged horribly before I learned how to remove leaks. Since then it doesn't appear to leak at all (I ran it on autopilot and went shopping, came back an hour later and it was still running fine). But I'm worried about how much I can cram into those repeat triggers without busting something.

Is there any way to test that? It needs to be playable on Battlenet as well. Is Battlenet slower than when I just playtest it myself?

Thank you,

Darwin
I believe to the point it starts lagging is 1300-1500.
 
Level 19
Joined
Feb 4, 2009
Messages
1,313
with SetUnitX/Y you should not go above 100 (if you got a rather good pc)
20 for SetUnitPosition or the GUI equivalent
a badass pc might be able to handle 1000 at once with a good code but most likely less

picking units within range will reduce this number further
you must use GroupEnumUnitsInRange and a global unitgroup for this in order to archive at least a decent speed (instead of the GUI thing which creates a new group every time)

these values are rather low but there are people out there with pcs which won't even run that

however you should not run the trigger every 0.02 sec (rather every 0.03) and not from 1 to 100 but from 1 to n where n is the real number of units to be moved

and of course there is a way to test that
add a new unit to be moved every time you press a key or every second or something and write "/fps" to see the frames per second (below the clock)

of course there is no real border like xxx units since pcs have different processing power from being unable to even render a single unit to up to a screen full of them so you will have to see what's the average
 
Level 14
Joined
Aug 30, 2004
Messages
909
with SetUnitX/Y you should not go above 100 (if you got a rather good pc)
20 for SetUnitPosition or the GUI equivalent
a badass pc might be able to handle 1000 at once with a good code but most likely less

picking units within range will reduce this number further
you must use GroupEnumUnitsInRange and a global unitgroup for this in order to archive at least a decent speed (instead of the GUI thing which creates a new group every time)

these values are rather low but there are people out there with pcs which won't even run that

however you should not run the trigger every 0.02 sec (rather every 0.03) and not from 1 to 100 but from 1 to n where n is the real number of units to be moved

Thank you, this is all very useful. I've been using the "SetUnitX/Y" custom script action; I believe I read one of your tutorials actually.

I'm confused about the GroupEnumUnitsInRange. Keep in mind I don't know JASS at all, so I just read tutorials and use custom script actions to clean up leaks or get LocationZ and such. I googled "GroupEnumUnitsInRange". I use a unit group which I destroy afterward to prevent leaking. Would it still be more efficient to use the JASS code?

Perhaps when I'm completely done I could post some of the code here and people could tell me the most efficient way to do it.
 
Thank you, this is all very useful. I've been using the "SetUnitX/Y" custom script action; I believe I read one of your tutorials actually.

I'm confused about the GroupEnumUnitsInRange. Keep in mind I don't know JASS at all, so I just read tutorials and use custom script actions to clean up leaks or get LocationZ and such. I googled "GroupEnumUnitsInRange". I use a unit group which I destroy afterward to prevent leaking. Would it still be more efficient to use the JASS code?

Perhaps when I'm completely done I could post some of the code here and people could tell me the most efficient way to do it.

well, using GroupEnumUnitsInRange + a single global group will be better, and you wont even need to destroy the group after you use it.
 
Level 19
Joined
Feb 4, 2009
Messages
1,313
Thank you, this is all very useful. I've been using the "SetUnitX/Y" custom script action; I believe I read one of your tutorials actually.

only wrote one which is not even approved yet :S

I'm confused about the GroupEnumUnitsInRange. Keep in mind I don't know JASS at all, so I just read tutorials and use custom script actions to clean up leaks or get LocationZ and such. I googled "GroupEnumUnitsInRange". I use a unit group which I destroy afterward to prevent leaking. Would it still be more efficient to use the JASS code?

ok I'll show you an example
if you intend to use GUI only you can do it like this:
JASS:
call GroupEnumUnitsInRange(udg_Unitgroup, udg_x, udg_y, udg_aoe, null
this will FILL a unitgroup with the units in range
it won't SET the unitgroup so there is no need to destroy it as Adiktuz said
(actually unitgroups leak a little little bit if you destroy them because blizzards people didn't make their job properly)
it is like "all all units in range to unitgroup" which does not leak either except it clears the group itself
you have to filter the units in the group yourself by picking them and then checking if they are valid

if you want to use JASS you can do things easier
you can replace "null" with "function Condition( FilterFunctionName )"
a filterfunction returns a boolean value if the filtered unit is valid:
JASS:
function FilterFunction takes nothing returns boolean
    return GetWidgetLife(GetFilterUnit()) > 0.405
endfunction
if you need the group only once you can do this:
JASS:
function FilterFunction takes nothing returns boolean
    if GetWidgetLife(GetFilterUnit()) > 0.405 then
        call SetUnitX(GetFilterUnit(), udg_x)
        call SetUnitY(GetFilterUnit(), udg_y)//with many actions it might be faster to safe GetFilterUnit() first
    endif
    return false
endfunction
this way you can do all actions in the filter function already and don't have to run a loop

if you have a small aoe which will mostlikely not contain any units it can be faster to use no filter function because no units have to be checked

for big aoes a filterfunction (prefareably with actions in them already) is the best choice

Perhaps when I'm completely done I could post some of the code here and people could tell me the most efficient way to do it.

great idea! do it! :D
 
Level 14
Joined
Aug 30, 2004
Messages
909
only wrote one which is not even approved yet :S

It was the one in your signature. Very informative, I hope it gets approved!

ok I'll show you an example
if you intend to use GUI only you can do it like this:
JASS:
call GroupEnumUnitsInRange(udg_Unitgroup, udg_x, udg_y, udg_aoe, null
this will FILL a unitgroup with the units in range
it won't SET the unitgroup so there is no need to destroy it as Adiktuz said
(actually unitgroups leak a little little bit if you destroy them because blizzards people didn't make their job properly)
it is like "all all units in range to unitgroup" which does not leak either except it clears the group itself
you have to filter the units in the group yourself by picking them and then checking if they are valid

I'm a bit confused about the GroupEnumUnitsInRange still. You say it fills a unitgroup. From the line you wrote, I imagine it would fill a variable called "Unitgroup" with units in range (real) of variable "aoe" of point "x,y". The "null" I'm unclear on. So imagine I fill the unit group with those units, then do a "pick every unit in "unitgroup" and clear out the dead units and friendly units. When I'm done with all that I don't need to destroy the unit group?

Here's the actual trigger. Before it, there is a giant unit group of all the lasers, missiles and other units I need to check for impact. I grab one at random, set it equal to a unit variable called "tempLaser" and then run this trigger. "tempGunnerSkill" is the skill of the shooter which is used to set the range, i.e. "aoe"

  • subDT Laser Ion
    • Events
    • Conditions
    • Actions
      • Set tempPointBlaster = (Position of tempLaser)
      • Set tempDamageUnits = (Units within (50.00 + ((Real(tempGunnerSkill)) x 25.00)) of tempPointBlaster matching (((Owner of (Matching unit)) is an enemy of (Owner of tempLaser)) Equal to True))
      • -------- BELOW: removes lasers (sapper) and dead units --------
      • Unit Group - Pick every unit in tempDamageUnits and do (Actions)
        • Loop - Actions
          • If (All Conditions are True) then do (Then Actions) else do (Else Actions)
            • If - Conditions
              • Or - Any (Conditions) are true
                • Conditions
                  • ((Picked unit) is A sapper) Equal to True
                  • ((Picked unit) is dead) Equal to True
            • Then - Actions
              • Unit Group - Remove (Picked unit) from tempDamageUnits
            • Else - Actions
      • -------- -------- --------
      • -------- REMOVES DODGING UNITS who have "Barrel Roll" buff-------
      • -------- -------- --------
      • Unit Group - Pick every unit in tempDamageUnits and do (Actions)
        • Loop - Actions
          • If (All Conditions are True) then do (Then Actions) else do (Else Actions)
            • If - Conditions
              • ((Picked unit) has buff Barrel Roll) Equal to True
            • Then - Actions
              • Unit Group - Remove (Picked unit) from tempDamageUnits
            • Else - Actions
      • -------- -------- --------
  • //[[It goes on like that, picks all units and damages them based on their shields and the strength of the laser, etc.]]
    • -------- -------- --------
      • Unit - Remove tempLaser from the game
      • Unit - Kill tempLaser
      • Custom script: call RemoveLocation (udg_tempPointBlaster)
      • Custom script: call DestroyGroup(udg_tempDamageUnits)
I changed the beginning to read like this:

  • subDT Laser Ion
    • Events
    • Conditions
    • Actions
      • Set tempPointBlaster = (Position of tempLaser)
      • Set x = (X of tempPointBlaster)
      • Set y = (Y of tempPointBlaster)
      • Set aoe = ((Real(tempGunnerSkill)) x 25.00)
      • Custom script: call GroupEnumUnitsInRange(udg_tempDamageUnits, udg_x, udg_y, udg_aoe, null)
      • -------- No Detonating on Lasers --------
      • Unit Group - Pick every unit in tempDamageUnits and do (Actions)
        • Loop - Actions
          • If (All Conditions are True) then do (Then Actions) else do (Else Actions)
            • If - Conditions
              • Or - Any (Conditions) are true
                • Conditions
                  • ((Picked unit) is A sapper) Equal to True
                  • ((Picked unit) is dead) Equal to True
                  • ((Picked unit) belongs to an ally of (Owner of tempLaser)) Equal to True
            • Then - Actions
              • Unit Group - Remove (Picked unit) from tempDamageUnits
            • Else - Actions
      • -------- -------- --------
      • -------- And so on... --------
That was the only thing that I changed but now the lasers just fly through their enemies. I assume I'm doing something wrong, but I'm afraid I don't know what it is.


EDIT:

Oh, I think I might have misunderstood earlier. Does this custom script get all the units within range of all the units in the unitgroup? If so, I'm not sure I can use it. I need to know which laser has hit which enemy, and just having all the targets together wouldn't tell me that I don't think...
 
Last edited:

Dr Super Good

Spell Reviewer
Level 64
Joined
Jan 18, 2005
Messages
27,202
The number of calculations a computer can perform per second depends on its hardware.
It is perfectly possible to play a game like SC2 on my computer with lots of excess processing power for example, but I can not run a simulation of reality at any recordable speed as another example.
 
Level 19
Joined
Feb 4, 2009
Messages
1,313
The "null" I'm unclear on

the filter function (mentioned above)

When I'm done with all that I don't need to destroy the unit group?

correct
but you still need to clear the location leak
or you could do this:
Custom Script: set udg_x = GetUnitX(udg_tmpLaser)
Custom Script: set udg_y = GetUnity(udg_tmpLaser)
will be faster because you don't have to create and remove a location

EDIT:

Oh, I think I might have misunderstood earlier. Does this custom script get all the units within range of all the units in the unitgroup? If so, I'm not sure I can use it. I need to know which laser has hit which enemy, and just having all the targets together wouldn't tell me that I don't think...

the units around the x/y position will be added to the group
locusted units will not be picked (unless you use GroupEnumUnitsOfType or GroupEnumUnitsOfPlayer)
but an aoe of 25 might be a little small (probably typo because the other trigger has +50)

instead of using 2 unitgroup picks you should use only 1 and do this:
pick units in group
if picked unit is valid
kill/remove it
 
Level 14
Joined
Aug 30, 2004
Messages
909
Great advice as always.

I found the problem; I had left in the: Custom script: call DestroyGroup(udg_tempDamageUnits) line and that messed it all up. It seems to work great now, thanks.

I combined the "pick all units" statements like you suggested into 1 giant one.

I also used those "set udg_X" statements to get the location. I think I'm going to start using those elsewhere to save space as well. That leads me to one question though:

QUESTION: If I use X,Y coordinates to define a point do I have to set it to a variable and remove it? For example: Unit - Create 1 Footman at Point (x,y) facing 0 angles. Would that point leak?
 
Level 19
Joined
Feb 4, 2009
Messages
1,313
QUESTION: If I use X,Y coordinates to define a point do I have to set it to a variable and remove it? For example: Unit - Create 1 Footman at Point (x,y) facing 0 angles. Would that point leak?

yes it would
but you can use this instead
JASS:
call CreateUnit(udg_player, udg_unitType, udg_x, udg_y, udg_facing)
or
JASS:
set udg_unit = CreateUnit(udg_player, udg_unitType, udg_x, udg_y, udg_facing)
or
JASS:
set bj_lastCreatedUnit = CreateUnit(udg_player, udg_unitType, udg_x, udg_y, udg_facing)
for probably all functions in GUI there is a JASS function which takes x and y instead of a location
lost of many functions: http://wiki.thehelper.net/wc3/jass/Blizzard.j
 
Status
Not open for further replies.
Top