• 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.

Making a complex unit collision system

Status
Not open for further replies.
Level 10
Joined
May 24, 2016
Messages
339
So the things is, my map is often filled with much team 1 ai units running around, so the team 1 heroes are constantly getting stopped by them. I do NOT want to use windwalk, since it cant be casted if you hide it's buttong icon, moreover I still want to save hero's collision with units from other teams.

So the things is, I thought like, why not recycle all team 1 heroes in a group, and then check for team 1 ai units around? If they are around, than you are able to walk through them.. But only if are in a really close range, sine turning off collision might let you to just walk through obstacles too

JASS:
loop
set f = FirstOfGroup(Team1Paladins)
exitwhen f==null
set g=CreateGroup()
set bol = false //local boolean bol
call GroupEnumUnitsInRange(g,GetUnitX(f),GetUnitY(f),60,null) //60 might be enough... right?
loop
set f2=FirstOfGroup(g)
exitwhen f2 == null or bol == true
if IsUnitInGroup(f2,Team1AIUnits) and not IsUnitDead(f2) then
set bol == true
endif
call GroupRemoveUnit(g,f2)
endloop

if LoadBoolean(Hash,GetHandleId(f),StringHash("CollisionBoolean")) == false then
if bol == true then
call SaveBoolean(Hash,GetHandleId(f),StringHash("CollisionBoolean"),true)
call SetUnitCollision(f,false) // im sorry I cant recall right now what is that function name, but it's close to real one
 endif
endif



call GroupRemoveUnit(Team1Paladins,f)
endloop


If you do remember a nice unit collision system on the web, please share with me, Ill be grateful!
 

Uncle

Warcraft Moderator
Level 73
Joined
Aug 10, 2018
Messages
7,866
Here's an example map done in GUI. I use Unit Groups to contain everything so you can avoid the overhead of generating a new Unit Group every single loop. Also, a distance of 128 worked well, I tried lower values like 110 and it failed to detect the Paladin next to the Footman.

Another potential idea would be to rely on a Knockback system to push allies away from your Heroes. This way you never toggle Collision off/on which helps avoid exploits/issues. Although, at the same time, it may create even more exploits/issues where you push allies into weird positions.
 

Attachments

  • Advanced Collision 1.w3m
    21.1 KB · Views: 5
Level 10
Joined
May 24, 2016
Messages
339
Here's an example map done in GUI. I use Unit Groups to contain everything so you can avoid the overhead of generating a new Unit Group every single loop. Also, a distance of 128 worked well, I tried lower values like 110 and it failed to detect the Paladin next to the Footman.

Another potential idea would be to rely on a Knockback system to push allies away from your Heroes. This way you never toggle Collision off/on which helps avoid exploits/issues. Although, at the same time, it may create even more exploits/issues where you push allies into weird positions.
Thx you Uncle, once I finish my today shift, Ill test it out and write my opinion on it.Have you set all units collision in object editor as 31, or it's standart blizzard values? Because using in trigger 128 range detection seems seems pretty huge, I believe unit can occasionally pass throught some cliffs and obstacles and get stuck in some zones.
 
Last edited:

Uncle

Warcraft Moderator
Level 73
Joined
Aug 10, 2018
Messages
7,866
Thx you Uncle, once I finish my today shift, Ill test it out and write my opinion on it.Have you set all units collision in object editor as 31, or it's standart blizzard values? Because using in trigger 128 range detection seems seems pretty huge, I believe unit can occasionally pass throught some cliffs and obstacles and get stuck in some zones.
It's all default settings. Footman collision size is 31 I think (which is the same as 24 if I recall correctly?), Paladin is 32. You could adjust the Distance value based on the Hero and Unit being compared. A Unit Indexer or Hashtables that stores this value for fast lookup would work nicely:
  • Set Variable DistanceThreshold = (CollisionSize[Custom value of hero] + CollisionSize[Custom value of allied unit])
  • If (Distance between points) Less than or equal to DistanceThreshold then...
 
Level 10
Joined
May 24, 2016
Messages
339
It's all default settings. Footman collision size is 31 I think (which is the same as 24 if I recall correctly?), Paladin is 32. You could adjust the Distance value based on the Hero and Unit being compared. A Unit Indexer or Hashtables that stores this value for fast lookup would work nicely:
  • Set Variable DistanceThreshold = (CollisionSize[Custom value of hero] + CollisionSize[Custom value of allied unit])
  • If (Distance between points) Less than or equal to DistanceThreshold then...
You made it great but I can't believe you did not make it safe to use.

I set paladin collision size to 31, and then changed distance dimension check from 128 to 70. That's enough to let you still pas through units (even though it may work a little bit clumsier, it still works nice) AND you cant pass through cliffs. You cant get stuck under water, you cant climb off and up through the cliffs. Check this yourself, I tried like 50 attempts and could not do that anymore. The only thing you can pass through is props like fences and walls.

The only thing that now bothers me is movement speed relation. I mean, if you set movement more than Paladin's default movement speed, you may still be able to abuse mechanic. I forgot to test it out.
 

Attachments

  • Advanced Collision 1 by Uncle modified.w3m
    22.9 KB · Views: 4
Last edited:

Uncle

Warcraft Moderator
Level 73
Joined
Aug 10, 2018
Messages
7,866
You made it great but I can't believe you did not make it safe to use.

I set paladin collision size to 31, and then changed distance dimension check from 128 to 70. That's enough to let you still pas through units (even though it may work a little bit clumsier, it still works nice) AND you cant pass through cliffs. You cant get stuck under water, you cant climb off and up through the cliffs. Check this yourself, I tried like 50 attempts and could not do that anymore. The only thing you can pass through is props like fences and walls.

The only thing that now bothers me is movement speed relation. I mean, if you set movement more than Paladin's default movement speed, you may still be able to abuse mechanic. I forgot to test it out.
Lowering the periodic interval to 0.01 seconds would help at the cost of game performance, 50 checks per second -> 100 checks per second. This also scales with the number of heroes registered to the system which could get out of hand.

Anyway, you could also test the pathability in front of the Hero to see if there's an obstacle you shouldn't be able to move through. This could be done using the "Item displacement" method. Place an item in front of the hero -> Check if it moved from it's given position using a distance check -> If it moved then there was something in the way -> Turn collision back on.

Edit:
Added the item pathability stuff. It seems to help.
Also fixed a mistake in the AC Register Ally trigger. It now has new instructions on how to use it.
 

Attachments

  • Advanced Collision 2.w3m
    24.9 KB · Views: 2
Last edited:

Uncle

Warcraft Moderator
Level 73
Joined
Aug 10, 2018
Messages
7,866
Alright, I got it working nicely by adding some more Item pathing checks. This is more expensive on performance but it seems to be fine, at least with 2 heroes. It also runs on a longer interval of every 0.03 seconds which means it's enumerating over nearby units less often, so that's nice. I also made it so the system runs a less expensive check for slower moving heroes and a more expensive check for faster moving heroes. There's definitely room for more optimizations but I didn't want to go too crazy with it.

I attached two maps, one of them has Debug messages and Special Effects to help show what's happening.
 

Attachments

  • Advanced Collision 3 No Debug.w3m
    26.9 KB · Views: 5
  • Advanced Collision 3.w3m
    27.7 KB · Views: 6
Last edited:
Level 10
Joined
May 24, 2016
Messages
339
Alright, I got it working nicely by adding some more Item pathing checks. This is more expensive on performance but it seems to be fine, at least with 2 heroes. It also runs on a longer interval of every 0.03 seconds which means it's enumerating over nearby units less often, so that's nice. I also made it so the system runs a less expensive check for slower moving heroes and a more expensive check for faster moving heroes.

I attached two maps, one of them has Debug messages and Special Effects to help show what's happening.
Item placeability works exactly like famous place walkability system on hive, right? You just recreated it on your system.

You are telling that perfomance issues are important here. I believe that means it doesntot matter is it 1 or 10 timers are running, more important is what functions that timers are doing, right? In this case item displacement check cause expensive perfomance weight on the game engine.

So why even using item displacement at the first place? You can just set your own interval on each individual hero, depending on what hero type ids and abils are


JASS:
//timer 0.01 sequence. One for all of the team 1

loop
set f = FirstOfGroup(Team1Paladins) // Team1Paladin would actually be consistent group that wont be in a loop, I just dont show how local group would copy Team1Paladin's units to recycle them
//'which means it's enumerating over nearby units less often, so that's nice' so if I got you right, I decided not not to actually enumerate units nearby paladin, but just recycling his group of heroes every 0.01 sec
exitwhen f==null
set r = LoadReal(Hash,GetHandleId(f),StringHash("Displace_r")) - 0.01
if r <= 0. then
if GetUnitTypeId(f) == PaladinType
if GetUnitAbilityLevel(f,'bootsofspeedid') < 1 then
call SaveReal(Hash,GetHandleId(f),StringHash("Displace_r"),0.03)
set r2= 128 //depens on unit collision size. For paladin I use 128 check range
else
call SaveReal(Hash,GetHandleId(f),StringHash("Displace_r"),0.01) // if he has boots of speed we d better have more often check condition timer
set r2= 128 //depens on unit collision size. For paladin I use 128 check range
endif

endif
set bol = false //local boolean bol
set g=CreateGroup()
call GroupEnumUnitsInRange(g,GetUnitX(f),GetUnitY(f),r,null) //range has been set before
loop
set f2=FirstOfGroup(g)
exitwhen f2 == null or bol == true
if IsUnitInGroup(f2,Team1AIUnits) and not IsUnitDead(f2) then
set bol == true
endif
call GroupRemoveUnit(g,f2)
endloop

if bol == true then
if LoadBoolean(Hash,GetHandleId(f),StringHash("CollisionBoolean")) == false then
call SaveBoolean(Hash,GetHandleId(f),StringHash("CollisionBoolean"),true)
call SetUnitCollision(f,true) // im sorry I cant recall right now what is that function name, but it's close to real one
elseif bol == false and LoadBoolean(Hash,GetHandleId(f),StringHash("CollisionBoolean")) == true
call SetUnitCollision(f,false) // im sorry I cant recall right now what is that function name, but it's close to real one
endif

elseif GetUnitTypeId(f) == PaladinType
call SaveReal(Hash,GetHandleId(f),StringHash("Displace_r"),r)
endif




call GroupRemoveUnit(Team1Paladins,f)
endloop

In this case you only check for nearby ally units only with 0.03 interval. If PaladinType has no any haste buff, and has slower than medium movement speed, that work nice.
 
Last edited:

Uncle

Warcraft Moderator
Level 73
Joined
Aug 10, 2018
Messages
7,866
Item placeability works exactly like famous place walkability system on hive, right? You just recreated it on your system.
Yes, it's more efficient to do it myself, but you can use a system instead if you'd like.

u are telling that perfomance issues are important here. I believe that means it doesntot matter is it 1 or 10 timers are running, more important is what functions that timers are doing, right? In this case item displacement check cause expensive perfomance weight on the game engine.
Yes, we're doing Distance checks every interval which is an expensive math operation that can be tough for your processor to handle. Especially when you do it ~1000 times per second. Let's say you have 10 heroes, each with 100 unit armies, and an interval of 0.02 seconds. That's 10 * 100 * 50 = 50,000 Distance checks per second.


Anyway, when I tested the Paladin with max movement speed it was clipping through the fence and wall even with a 0.01 second Periodic interval. So I added the Item pathing checker stuff as extra protection, and it works great. You can no longer clip through the fence/walls even at a slower 0.03s Periodic interval. Although, I'm sure there's a very rare case that it fails but that's probably acceptable.

Also, you can easily perform varied checks based on your Hero's current movement speed. Something like this could be good for you:

If movement speed is >= 460:
Do a large range "item check", then a short range "item check", and if both don't find any obstacles then do a "nearby unit" check.

Else if movement speed is >= 360:
Do a short range "item check" and if that doesn't find any obstacles then do a "nearby unit" check.

Else if movement speed is < 360:
Do a basic "nearby unit" check, no items involved.

Play around with the numbers to get things feeling right. And of course you should do whatever is best for your map. A timer per hero is a good idea, Timers are very performant and Hero counts will never be too high that it'd matter.
 
Last edited:
Level 10
Joined
May 24, 2016
Messages
339
Yes, it's more efficient to do it myself, but you can use a system instead if you'd like.


Yes, we're doing Distance checks every interval which is an expensive math operation that can be tough for your processor to handle. Especially when you do it ~1000 times per second.


Anyway, when I tested the Paladin with max movement speed it was clipping through the fence and wall even with a 0.01 second Periodic interval. So I added the Item pathing checker stuff as extra protection, and it works great. You can no longer clip through the fence/walls even at a slower 0.03s Periodic interval. Although, I'm sure there's a very rare case that it fails but that's probably acceptable.

The way I have it setup now, you can easily perform varied checks based on your Hero's current movement speed. Something like this could be good for you:

If movement speed is >= 460:
Do a large range "item check", then a short range "item check", and if both don't find any obstacles then do a "nearby unit" check.

Else if movement speed is >= 360:
Do a short range "item check" and if that doesn't find any obstacles then do a "nearby unit" check.

Else if movement speed is < 360:
Do a basic "nearby unit" check, no items involved.

Play around with the numbers to get things feeling right. And of course you should do whatever is best for your map. A timer per hero is a good idea, Timers are very performant and Hero counts will never be too high that it'd matter.
I'd actually thinking about recycling them in one timer. But I guess it still doesnot matter whether it's individual timer or a single one for a whole team, consisting of only 4 heroes, If I get it right.
Moreover, if you do not set long enough distance range, but long enought for it to work, it would result into hero wont be completely "phase" through all units, but instead making some stops and moving forward afterthat. It also means you can't consciously phase through a single unt (It's possible, but it takes a time to click point many times), but moving through a crowd still works on its own. It might look for some players as "more pleasurable gameplay" I believe
 
Status
Not open for further replies.
Top