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

[Snippet] GetUnitCollision

Bribe

Code Moderator
Level 50
Joined
Sep 26, 2009
Messages
9,464
I think the whole thing should just hash all the collision sizes using a LUA generator, since those are static Object Editor things anyway. Requiring placing the location in a certain "perfect" spot is less appealing than just running a simple loop like Vexorian has, to be honest. It won't run more than 50% slower but it doesn't require a location, unit, external libraries... a lot easier to implement. As it stands, it would be fine as an alternative but probably not going to turn any heads.
 
Level 4
Joined
Jan 27, 2010
Messages
133
  • Triggers Enter/Leave region events
  • Returns the wrong sign (- instead of +)
  • Is less accurate than Vexorian's version
  • (Breaks channels...?)
 

Attachments

  • collisiontest.w3x
    17.1 KB · Views: 59
Level 4
Joined
Jan 27, 2010
Messages
133
Nah, that gave me collision size ~50... Using -128 gave (-13.5) which seem closer (if you do abs). GetUnitCollisionSize gives 15.9...

The desired output is 16, btw.

Oh, and I'm almost certain that moving a unit will make it stop channeling (besides from possibly triggering region events).
 
Level 10
Joined
Jul 12, 2009
Messages
318
Comments from a quick look:
1. It won't work for flying units, will it?
2. Moving the test unit is dangerous, because it might trip exit-region events or stop Drain Life, not to mention interrupting that unit with SetUnitPosition. Instead...
3. ...shouldn't it take unit-type and create a new test subject?
4. It'll consider pathing maps, and whether that's desired or not, they won't necessarily be a circle (no single collision value).

5. Or, all that could be avoided, including the need for a special tester unit-type at all, by using the method used in this script: iterating distances from the unit's position until IsUnitInRangeXY returns false, since that function considers a unit's collision size.
 

Bribe

Code Moderator
Level 50
Joined
Sep 26, 2009
Messages
9,464
This is about as light as it gets - a hybrid of Vexorian's GeUnitCollisionSize with some of Bribe's crazy ideas. It iterates 8 or 9 times at most. The only disadvantage is that it works entirely in integers, so decimals will be cropped off.

JASS:
library GetUnitCollision requires Table
//Created by Vexorian with some improvements by Bribe
    
    globals
        //-------------------------------------------------------------------
        // You can optimize this to be the max collision in your map
        // 172 is max natural collision - from tier 3 town halls.
        private constant integer MAX_COLLISION = 172
        
        // A Table for an optimization perk.
        private Table t = 0
    endglobals
    
    //=======================================================================
    private function Check takes integer id, unit u returns integer
        local integer z = MAX_COLLISION
        local integer a = 0
        local integer i = z
        local real x = GetUnitX(u)
        local real y = GetUnitY(u)
        loop
            if IsUnitInRangeXY(u, x + i, y, 0) then
                set a = i
            else
                set z = i
            endif
            exitwhen z - a <= 1
            set i = (z + a) / 2
        endloop
        set i = i - z + a
        set t[id] = i
        return i
    endfunction
    
    //=======================================================================
    // Golden function - optimized for fast repeat returns on type id's.
    //
    function GetUnitCollision takes unit u returns integer
        local integer id = GetUnitTypeId(u)
        if not t.has(id) then
            return Check(id, u)
        endif
        return t[id]
    endfunction
    
    //=======================================================================
    private module I
        private static method onInit takes nothing returns nothing
            set t = Table.create()
        endmethod
    endmodule
    private struct S extends array
        implement I
    endstruct
    
endlibrary
 
Level 6
Joined
Jun 20, 2011
Messages
249
Could you add a constant for the max unit collision so we can pick groups in range + max collision and then decide if the unit's collision matches the actual range?

edit
to be more specific
JASS:
function TestGroup takes real x, real y, real r returns nothing
	local unit u
	local real ux
	local real uy
	call GroupEnumUnitsInRange(bj_lastCreatedGroup,x,y,r+MAX_COLLISION_SIZE,null)
	loop
		set u = FirstOfGroup(bj_lastCreatedGroup)
		exitwhen u==null
		set ux = GetUnitX(u)-x
		set uy = GetUnitY(u)-y
		// check if the unit collides with the picking radius
		if SquareRoot(ux*ux+uy*uy)-GetUnitCollision(u) <= r then
			// Do Actions...
		endif
		call GroupRemoveUnit(bj_lastCreatedGroup,u)
	endloop
	set u = null
endfunction
 
Last edited:
Level 31
Joined
Jul 10, 2007
Messages
6,306
Eh, you are right ; P. I wasn't thinking while reading default object editor collision size for the castles. Just did the math really quick based on the stuff I did in IsPathBlocked and it indeed comes out to 512 ; ).

Castle collision size doesn't match its pathing map ; D. I should probably fix that in IsPathBlocked ^)^.


Figured Blizzard would at least do the collision sizes right relative to the pathing maps, but guess I was wrong >.>.


However, the collision size for the 512 would still be 256 (radius), so 300 is still ok.


Thought that 160 radius was pretty strange while writing IsPathBlocked ; P.
 
Top