Doomhammer
Bob Kotick - Gamers' corporate spoilsport No. 1
- Reaction score
- 67
The Mass Movement System is a system to facilitate and optimize the ordering of large amounts of units. It may come in handy to improve any type of footy map, TD maps or cinematics involving entire armies of moving units. As follows, a short description, two screenies and the test map
1) What can it do?
2) The concept: Why not grab all units and send them to x/y?
3) How does the mass-movement system order units?
4) Requirements
5) Code please!
1) What can it do?
It can order large amounts of units to move or attack-move to a certain position in a structured manner.
2) The concept: Why not grab all units and send them to x/y?
Especially with large amounts of units, this is very likely to create movement lags. Also experience has proven that it is more efficient to order large amounts of units in unit groups.
3) How does the mass-movement system order units?
It counts how many units there are to be ordered, then creates grouping clusters according to each units position and the unit density. Each new group has a group captain whose distance to the target decides about the timing of the call to march off. So the units march off in structured groups and with a moderate timing to avoid congestions.
4) Requirements
Actually none apart from WE (since the code is kept on an old-school level).
5) Code please!
JASS:
//%%%%%%%%%%%%%%%%%%%%% Custom Settings %%%%%%%%%%%%%%%%%%%%%%%%%%
function scatter_size takes integer n,real k returns real
return 64000.0 / ( n * Pow(bj_E , k) )
endfunction
// The scatter size describes the size of the area, i.e. half the size of the rect
// which is used to group clustered units into subgroups.
// It is set dependend on the unit amount n, and on an iteration factor k.
constant function scatter_size_min takes nothing returns real
return 80.0
endfunction
// The maximum amount of units in a cluster before iterating the grouping with a factor k larger by 1.
// Should be quite a bit larger than 12, but definitely smaller than 50: the higher,
// the more operations needed, the smaller, the less likely suitable groups will be formed
constant function max_cluster takes nothing returns integer
return 30
endfunction
//%%%%%%%%%%%%%%%%%%% Helper Functions %%%%%%%%%%%%%%%%%%%%%%
function All_filter takes nothing returns boolean
return IsUnitType(GetFilterUnit() , UNIT_TYPE_STRUCTURE) == false and IsUnitType(GetFilterUnit() , UNIT_TYPE_PEON) == false and GetWidgetLife(GetFilterUnit()) > 0.405
endfunction
function OneId_filter takes nothing returns boolean
return GetUnitTypeId(GetFilterUnit()) == bj_groupEnumTypeId and GetWidgetLife(GetFilterUnit()) > 0.405
endfunction
function TwoId_filter takes nothing returns boolean
return GetUnitTypeId(GetFilterUnit()) == bj_groupEnumTypeId or GetUnitTypeId(GetFilterUnit()) == bj_forceCountPlayers and GetWidgetLife(GetFilterUnit()) > 0.405
endfunction
function Group_filter takes nothing returns boolean
return IsUnitInGroup(GetFilterUnit() , bj_randomSubGroupGroup)
endfunction
//%%%%%%%%%%%%%%%%%%%%% Main Functions %%%%%%%%%%%%%%%%%%%%%%%%
function NearUnitArray takes nothing returns nothing
local unit e=GetEnumUnit()
local real dx= bj_meleeNearestMineDist - GetUnitX(e)
local real dy= bj_randomSubGroupChance - GetUnitY(e)
local real d= bj_enumDestructableRadius
if ( dx < d and dx > - d ) and ( dy < d and dy > - d ) then
set bj_ghoul[bj_destRandomConsidered]=e
set bj_randDistID[bj_destRandomConsidered]=R2I(dx * dx + dy * dy)
set bj_destRandomConsidered = bj_destRandomConsidered + 1
endif
set e = null
endfunction
function NearestSubGroup takes nothing returns group
local group g= CreateGroup() //the final subgroup to be returned
local integer n= bj_destRandomConsidered //the cluster size
local integer i= 0
local integer j= 0
local integer d
local unit u
// bj_ghoul[] : the unit currently looked at
//bj_randDistID : the unit's distance to the group 'captain'
if ( n <= 12 ) then
loop
exitwhen ( i > n )
call GroupAddUnit(g , bj_ghoul<i>)
call GroupRemoveUnit(bj_groupRemoveGroupDest , bj_ghoul<i>)
set bj_ghoul<i>=null
set i = i + 1
endloop
else
loop
exitwhen ( i == n )
set j = i + 1
loop
exitwhen ( j == n )
if bj_randDistID<i> < bj_randDistID[j] then
set u = bj_ghoul<i>
set d = bj_randDistID<i>
set bj_ghoul<i>=bj_ghoul[j]
set bj_randDistID<i>=bj_randDistID[j]
set bj_ghoul[j]=u
set bj_randDistID[j]=d
endif
set j = j + 1
endloop
set i = i + 1
endloop
loop
exitwhen i < 0
if i > j - 12 then
call GroupAddUnit(g , bj_ghoul<i>)
call GroupRemoveUnit(bj_groupRemoveGroupDest , bj_ghoul<i>)
endif
set bj_ghoul<i>=null
set i = i - 1
endloop
endif
set u = null
return g
endfunction
function ImmediateOrder takes nothing returns nothing
call IssueImmediateOrder(GetEnumUnit() , bj_cineFadeContinueTex)
endfunction
function MassMoveType takes integer Id1, integer Id2, string order, real x, real y, player p, real t returns nothing
local group g=CreateGroup()
local group array subgroup
local real array dist
local boolexpr b
local unit v
local real dy
local real dx
local integer i= 0
local integer j= 0
local integer n
if Id1 == 0 and Id2 == 0 then
set b = Filter(function All_filter)
elseif Id1 != 0 and Id2 == 0 then
set bj_groupEnumTypeId = Id1
set b = Filter(function OneId_filter)
elseif Id1 != 0 and Id2 != 0 then
set bj_groupEnumTypeId = Id1
set bj_forceCountPlayers = Id2
set b = Filter(function TwoId_filter)
endif
if GetLocalPlayer() == p then
call SetCameraQuickPosition(x , y)
endif
call GroupEnumUnitsOfPlayer(g , p , b)
if order == "stop" then
set bj_cineFadeContinueTex = order
call ForGroup(g , function ImmediateOrder)
elseif order=="move" or order=="attack" then
set bj_groupCountUnits = 0
call ForGroup(g , function CountUnitsInGroupEnum)
set n = bj_groupCountUnits
//call BJDebugMsg("ordering " + I2S(n) + " units")
if n > 0 and n <= 12 then
call GroupPointOrder(g , order , x , y)
elseif n > 12 then
loop
set v = FirstOfGroup(g)
exitwhen v == null
set bj_meleeNearestMineDist = GetUnitX(v)
set bj_randomSubGroupChance = GetUnitY(v)
loop
if scatter_size(n , j) >= scatter_size_min() then
set bj_enumDestructableRadius = scatter_size(n , j)
else
set bj_enumDestructableRadius = scatter_size_min()
endif
set bj_destRandomConsidered = 0
call ForGroup(g , function NearUnitArray)
if bj_destRandomConsidered > max_cluster() then
set j = j + 1
endif
exitwhen bj_destRandomConsidered <= max_cluster()
endloop
set j = 0
set bj_groupRemoveGroupDest = g
set subgroup<i>=NearestSubGroup()
set g = bj_groupRemoveGroupDest
set dx = x - bj_meleeNearestMineDist
set dy = y - bj_randomSubGroupChance
set dist<i>=SquareRoot(dx * dx + dy * dy)
set i = i + 1
endloop
loop
exitwhen ( j == i )
set n = j + 1
loop
exitwhen ( n == i )
if dist[j] < dist[n] then
set g = subgroup[j]
set dx = dist[j]
set subgroup[j]=subgroup[n]
set dist[j]=dist[n]
set subgroup[n]=g
set dist[n]=dx
endif
set n = n + 1
endloop
set j = j + 1
endloop
loop
exitwhen i < 0
set v = FirstOfGroup(subgroup<i>)
set dist<i>=0.28 * dist<i>
set dx = bj_RADTODEG * Atan2(GetUnitY(v) - y , GetUnitX(v) - x)
call GroupPointOrder(subgroup<i> , order , x + dist<i> * Cos(dx * bj_DEGTORAD) , y + dist<i> * Sin(dx * bj_DEGTORAD))
call TriggerSleepAction(t)
call DestroyGroup(subgroup<i>)
set subgroup<i>=null
set i = i - 1
endloop
endif
endif
call DestroyBoolExpr(b)
call DestroyGroup(g)
set g = null
set v = null
set p = null
endfunction</i></i></i></i></i></i></i></i></i></i></i></i></i></i></i></i></i></i></i></i></i>