• Listen to a special audio message from Bill Roper to the Hive Workshop community (Bill is a former Vice President of Blizzard Entertainment, Producer, Designer, Musician, Voice Actor) 🔗Click here to hear his message!
  • Read Evilhog's interview with Gregory Alper, the original composer of the music for WarCraft: Orcs & Humans 🔗Click here to read the full interview.
  • The Hive's 22nd Icon Contest: Creep Abilities is now concluded, time to vote for your favourite set of icons! Click here to vote!
  • ✅ The POLL for Hive's Texturing Contest #34 is OPEN! Vote for the TOP 3 SKINS! 🔗Click here to cast your vote!
  • ✅ The POLL for Hive's Techtree Contest #20 is OPEN! Vote for the TOP 3 FACTIONS! 🔗Click here to cast your vote!

How to deal AoE damage with minimal CPU impact?

Level 8
Joined
Apr 16, 2025
Messages
160
I am creating a custom universal cleave, suitable even for ranged units. The point is that the damage is done in a 300 area. What's the problem, you might ask? The problem is that my unit makes 30 attacks per second. The FPS drops a lot. How can I create area-of-effect (AoE) damage with minimal performance impact?

I'll say right away that I've done a lot of testing (I use the damage engine). I'll share them now, and if you know a better way, please tell me about it, it's interesting to listen to.

1) The worst option: use the area damage trigger. For some reason, it's wildly unoptimized. The FPS drops from 60 to 20. In addition, you can't attach the blood effect to a combat unit that has received damage.

2) create your own temporary group, add creatures to it within a 300 radius of the combat unit that received damage. Then select each combat unit in the group and deal damage to it. If she is dead or outside the 300 area, then remove her from the group. Result = so-so. FPS drops from 60 to 30.

3) create a regular group with the "set bj_wantDestroyGroup = true" trigger before creating the group. Result = so-so. FPS drops from 60 to 30.

4) create a temporary group and reset it with the "call DestroyGroup(udg_TempGroup)" and "set udg_TempGroup = null" triggers. The result is 1 FPS more than in the third case. Still nonsense.

5) Then I tried many spells, converting their damage to physical. Frostnova turned out to be the best, but it has an internal limit of 30-50 targets. FPS 30.

6) All aura spells, like Demonhunter's Immolation, work with a delay, alas. And in general, the result is the same as with Frostnova.

7) Created a dummy unit that deals damage like a catapult. This is a nightmare, how bad. It seems to even try to damage the dead. FPS 15. Besides, no matter how hard I try, the attacking dummy unit still attacks with a 0.1 sec delay.

8) Do you have your own version, the most effective one?
 
Last edited:
Here's an attempt at optimizing the cleave effect. How it works:

1) I don't use Damage Engine but my own triggered damage Event (less system overhead).

2) I store damaged units in a Unit Group that is linked to the (Damage Source). So the Source keeps track of each unit it's currently damaging.

3) I use a Cooldown system which delays the recreation of the linked Unit Group. This way 30 attacks per second doesn't recreate the Unit Group 30 times per second. Instead, the Unit Group will only be recreated at most ~2.5 times per second (which can be modified to happen less or more often). This should be the major performance improvement.

4) While the Cooldown is active, you'll simply Loop over your existing Unit Group and damage all of them. This is a very quick process.
  • Unit Group - Pick every unit in AOE_Damage_Target_Group[AOE_Damage_ID] and do (Actions)
    • Loop - Actions
      • Set VariableSet AOE_Damage_Target_Other = (Picked unit)
      • If (All Conditions are True) then do (Then Actions) else do (Else Actions)
        • If - Conditions
          • AOE_Damage_Target_Other Not equal to AOE_Damage_Target
        • Then - Actions
          • Unit - Cause AOE_Damage_Source to damage AOE_Damage_Target_Other, dealing AOE_Damage_Amount damage of attack type Hero and damage type Normal
          • If (All Conditions are True) then do (Then Actions) else do (Else Actions)
            • If - Conditions
              • (AOE_Damage_Target_Other is alive) Equal to False
            • Then - Actions
              • Unit Group - Remove AOE_Damage_Target_Other from AOE_Damage_Target_Group[AOE_Damage_ID].
            • Else - Actions
        • Else - Actions
The major downside here, although I think a worthy compromise:

1) New units that come within range of your primary (Damage Target) will be ignored until the group is recreated.
2) Units already in the group that move too far away will continue to be damaged until the group is recreated.

HOWEVER, note that the group is recreated often (2.5 times per second by default), so it should quickly fix itself.
 

Attachments

Last edited:
1000 AoE, 60 targets, 0.10 bat, 400 attack speed, Damage Engine even with shity StringHash for check damage type.
Am I doing something wrong?

In any case, 30 attacks per second and a large number of targets is cancer, this is only done in Korean pseudo ORPGs.
Even "Holo Cure" style grinders start to lag when there are too many units/attacks per second, and you're trying to do that in a game from 2003.
With good game design decisions, most of the problems can be avoided.
 
1000 AoE, 60 targets, 0.10 bat, 400 attack speed, Damage Engine even with shity StringHash for check damage type.
Am I doing something wrong?

In any case, 30 attacks per second and a large number of targets is cancer, this is only done in Korean pseudo ORPGs.
Even "Holo Cure" style grinders start to lag when there are too many units/attacks per second, and you're trying to do that in a game from 2003.
With good game design decisions, most of the problems can be avoided.
How exactly does this splash work? I need a code or a test card right away, otherwise I don't understand.
In general, everyone has different computers. The point is to find the most efficient way, not to determine who lags where.
 
Last edited:
Here's an attempt at optimizing the cleave effect. How it works:

1) I don't use Damage Engine but my own triggered damage Event (less system overhead).

2) I store damaged units in a Unit Group that is linked to the (Damage Source). So the Source keeps track of each unit it's currently damaging.

3) I use a Cooldown system which delays the recreation of the linked Unit Group. This way 30 attacks per second doesn't recreate the Unit Group 30 times per second. Instead, the Unit Group will only be recreated at most ~2.5 times per second (which can be modified to be less or more). This should be the major performance improvement.

4) While the Cooldown is active, you'll simply Loop over your existing Unit Group and damage all of them. This is a very quick process.
  • Unit Group - Pick every unit in AOE_Damage_Target_Group[AOE_Damage_ID] and do (Actions)
    • Loop - Actions
      • Set VariableSet AOE_Damage_Target_Other = (Picked unit)
      • If (All Conditions are True) then do (Then Actions) else do (Else Actions)
        • If - Conditions
          • AOE_Damage_Target_Other Not equal to AOE_Damage_Target
        • Then - Actions
          • Unit - Cause AOE_Damage_Source to damage AOE_Damage_Target_Other, dealing AOE_Damage_Amount damage of attack type Hero and damage type Normal
          • If (All Conditions are True) then do (Then Actions) else do (Else Actions)
            • If - Conditions
              • (AOE_Damage_Target_Other is alive) Equal to False
            • Then - Actions
              • Unit Group - Remove AOE_Damage_Target_Other from AOE_Damage_Target_Group[AOE_Damage_ID].
            • Else - Actions
        • Else - Actions
The major downside here, although I think a worthy compromise:

1) New units that come within range of your primary (Damage Target) will be ignored until the group is recreated.
2) Units already in the group that move too far away will continue to be damaged until the group is recreated.

HOWEVER, note that the group is recreated often (2.5 times per second is still fast), so it should quickly fix itself.
I'll check it later and reply, looks promising
 
Here's an attempt at optimizing the cleave effect. How it works:

1) I don't use Damage Engine but my own triggered damage Event (less system overhead).

2) I store damaged units in a Unit Group that is linked to the (Damage Source). So the Source keeps track of each unit it's currently damaging.

3) I use a Cooldown system which delays the recreation of the linked Unit Group. This way 30 attacks per second doesn't recreate the Unit Group 30 times per second. Instead, the Unit Group will only be recreated at most ~2.5 times per second (which can be modified to happen less or more often). This should be the major performance improvement.

4) While the Cooldown is active, you'll simply Loop over your existing Unit Group and damage all of them. This is a very quick process.
  • Unit Group - Pick every unit in AOE_Damage_Target_Group[AOE_Damage_ID] and do (Actions)
    • Loop - Actions
      • Set VariableSet AOE_Damage_Target_Other = (Picked unit)
      • If (All Conditions are True) then do (Then Actions) else do (Else Actions)
        • If - Conditions
          • AOE_Damage_Target_Other Not equal to AOE_Damage_Target
        • Then - Actions
          • Unit - Cause AOE_Damage_Source to damage AOE_Damage_Target_Other, dealing AOE_Damage_Amount damage of attack type Hero and damage type Normal
          • If (All Conditions are True) then do (Then Actions) else do (Else Actions)
            • If - Conditions
              • (AOE_Damage_Target_Other is alive) Equal to False
            • Then - Actions
              • Unit Group - Remove AOE_Damage_Target_Other from AOE_Damage_Target_Group[AOE_Damage_ID].
            • Else - Actions
        • Else - Actions
The major downside here, although I think a worthy compromise:

1) New units that come within range of your primary (Damage Target) will be ignored until the group is recreated.
2) Units already in the group that move too far away will continue to be damaged until the group is recreated.

HOWEVER, note that the group is recreated often (2.5 times per second is still fast), so it should quickly fix itself.
Impressive! Your method is 4 FPS faster than the fastest option of all of mine. That's worthy.
 
How exactly does this splash work? I need a code or a test card right away, otherwise I don't understand.
In general, everyone has different computers. The point is to find the most efficient way, not to determine who lags where.
Here Damage Engine is built into YDWE PK, it will be difficult to compare with your code, I just lazily did a small test in a couple of clicks.
sc1.png

If you want to see the final code, you can take it from this map, or just test it in a solo game, for this you will not need YDWE PK editor.
 

Attachments

Here Damage Engine is built into YDWE PK, it will be difficult to compare with your code, I just lazily did a small test in a couple of clicks.
View attachment 546922
If you want to see the final code, you can take it from this map, or just test it in a solo game, for this you will not need YDWE PK editor.
This is one of my options. It moderately loads the processor. Of course, there will be no fps drop if you have a powerful computer.
 
How exactly are you testing this? Because map size and unit count is going to affect how costly it is to do things like "Pick every unit in 300.00 range". I imagine you have a bunch of triggers that run in response to "A unit is Attacked" and "Damage Event X". All of these things will add up and make an impact on these tests.
 
How exactly are you testing this? Because map size and unit count is going to affect how costly it is to do things like "Pick every unit in 300.00 range". I imagine you have a bunch of triggers that run in response to "A unit is Attacked" and "Damage Event X". All of these things will add up and make an impact on these tests.
I simply have all the triggers that shouldn't be active inactive. For example, I pick a hero and they turn on, so the damage engine load is minimal. In addition, I use deeper filters, which are implemented in Bridge, which consume less resources. For example, if the pre-event is less than 1, it means it's an attack, not a spell. Etc. In general, I optimized everything.
 
Back
Top