- Joined
- Apr 24, 2012
- Messages
- 5,113
I don't know if i have problems inside the script,because i coded it in Notepad++ and i don't have any WE or JNGP to check its syntax.
Demo:
Changelogs
1.0
- Release
1.1
- Fix code errors(thanks to Spinnaker
1.2
- Added wrappers
- Fix code.
1.3
- code now stable
- Added test map.
1.4
- Optimized code.
- Cleaned some leaks.
- Add Table as a required library for finding unit index.
1.5
-Updated version,still buggy.
(Test map code is outdated,due to update)
JASS:
library Knockback2D /* v 1.5
*************************************************************************************
*
*
* Knockback 2D
*
* by: Almia aka Radamantus
*
*
* --------------------------------------------------------------------------
*
* Description
*
* ------------------------------------------
*
* Knockback 2D is a system for creating and handling 2D knockbacks.
* The system features safe-pathing, bounded movement, optional tree
* destroying which also decelerates knockback speed,destroys knockback
* when path is blocked.
*
* The system safe-pathing recognizes units, destructables and terrain
* path by collision size. Bounded movement disables units for leaving
* map bounds.
*
* The system also features personal events(onLoop, onEnd),which makes
* this user-friendly system.
*
* The system creates knockback by means of speed and time,but not
* distance.
*
* --------------------------------------------------------------------------
*
* Notes
*
* - Not recommended for knockbacking crowded units
*
* --------------------------------------------------------------------------
*
* */ requires /*
*
* ------------------------------------------
*
* */ Event /* hiveworkshop.com/forums/jass-resources-412/snippet-event-186555/
* */ GetUnitCollision /* hiveworkshop.com/forums/jass-resources-412/snippet-getunitcollision-180495/
* */ IsDestTree /* hiveworkshop.com/forums/spells-569/isdestree-v1-2-a-224623/
* */ IsTerrainWalkable /* pastebin.com/0zjeaBc7
* */ MapBounds /* hiveworkshop.com/forums/jass-resources-412/snippet-mapbounds-222870/
*
* --------------------------------------------------------------------------
*
* Credits
*
* ------------------------------------------
*
* Nestharus for Event and Collision Libs
* Vexorian for IsTerrainWalkable Lib
* Adiktuz for MapBounds Lib
* Spinnaker for spotting errors
* Magtheridon96 for explaining public groups properly
* Bribe for Table
*
* --------------------------------------------------------------------------
*
* API
*
* ------------------------------------------
*
* private function PathUnitFilter takes unit u, unit up returns boolean
* - filter function for enumerating units for pathing
*
* private function PathDestFilter takes nothing returns boolean
* - filter function for enumerating destructables for pathing
*
* struct Knockback2D extends array
*
* static method find takes unit tu returns integer
* - checks if a unit is already been knockbacked by finding it inside the list
* - this is used for rewriting knockback data of the unit for safety
*
* static method destroy takes nothing returns nothing
* - destroys a knockback instance
*
* private static method periodic takes nothing returns nothing
* - periodic method of system
* - basically, the system core
*
* static method add takes unit tu, real tspeed, real tangle, real ttime returns nothing
* - creates a knockback instance
* - can also be used for updating knockback data
*
* static method registerEvent takes integer KBevent, code c returns nothing
* - registers a code to the knockback event.
* - the code will be fired once the event is fired.
*
* private static method init takes nothing returns nothing
* - system initializer
*
* function GetKnockbackOnLoopUnit takes nothing returns unit
* function GetKnockbackOnEndUnit takes nothing returns unit
* function AddKnockback takes unit u, real speed, real angle, real time returns nothing
* function DestroyKnockback takes unit u returns nothing
* function RegisterKnockbackEvent takes code c, integer KBEvent returns nothing
*
* --------------------------------------------------------------------------
*
* Settings
*
* ------------------------------------------
*/
globals
/*
* The bonus collision of pathing check
*/
private constant real COLLISION_BONUS = 50
/*
* Percentage of speed to be removed
* for deceleration
*/
private constant real DECEL_SPEED_SCALE = 0.4
/*
* System Timeout
*/
private constant real TIMEOUT = 0.031250000
/*
* System Events
*/
constant integer EVENT_KNOCKBACK_LOOP = 1
constant integer EVENT_KNOCKBACK_END = 2
endglobals
/*
* --------------------------------------------------------------------------
*
* Knockback Struct and Functions
*
* --------------------------------------------------------------------------
*/
/*
* Misc Globals
*/
globals
private boolean hit = false
private boolean hitTree = false
private timer tm = CreateTimer()
private unit KnockbackEventOnDestroyUnit
private unit KnockbackEventOnLoopUnit
private group g = CreateGroup()
private hashtable ht
endglobals
/*
* Pathing enum unit filter
*/
private function PathUnitFilter takes unit u, unit up returns boolean
return not IsUnitType(u, UNIT_TYPE_DEAD)/*
*/ and GetWidgetLife(u) > 0.405 /*
*/ and u != up and u != null /*
*/ and not IsUnitType(u, UNIT_TYPE_FLYING)
endfunction
/*
* Pathing enum doodad filter
*/
private function PathDestFilter takes nothing returns boolean
local destructable d = GetFilterDestructable()
if d != null then
if GetWidgetLife(d) > 0.405 then
if IsDestTree(d) then
set hitTree = true
call KillDestructable(d)
else
set hit = true
endif
endif
endif
set d = null
return false
endfunction
private module Init
static method onInit takes nothing returns nothing
call init()
endmethod
endmodule
struct Knockback2D extends array
/*
* Linked List
*/
private static thistype ic = 0
private static thistype array rc
private static thistype array n
private static thistype array p
private static integer c = 0
/*
* Events
*/
private static Event onLoop
private static Event onDestroy
/*
* Iteration and Instance Var
*/
private static unit array u
private static real array speed
private static real array angle
private static real array time
private static real array csize
method destroy takes nothing returns nothing
set KnockbackEventOnDestroyUnit = u[this]
call FireEvent(onDestroy)
set rc[this] = rc[0]
set rc[0] = this
set n[p[this]] = n[this]
set p[n[this]] = p[this]
call SaveInteger(ht, GetHandleId(u[this]), 0, 0)
set u[this] = null
set speed[this] = 0
set angle[this] = 0
set time[this] = 0
set csize[this] = 0
set c = c - 1
if 0 == c then
call PauseTimer(tm)
endif
endmethod
private static method periodic takes nothing returns nothing
local real x
local real y
local rect r
local unit tu
local thistype i = n[0]
loop
exitwhen 0 == i
if 0 < time[i] then
set time[i] = time[i] - TIMEOUT
set KnockbackEventOnLoopUnit = u[i]
call FireEvent(onLoop)
set x = GetUnitX(u[i]) + speed[i] * Cos(angle[i])
set y = GetUnitY(u[i]) + speed[i] * Sin(angle[i])
if MapContainsX(x) and MapContainsY(y) then
set r = Rect(x - csize[i], y - csize[i], x + csize[i], y + csize[i])
call EnumDestructablesInRect(r, Filter(function PathDestFilter), null)
call RemoveRect(r)
set r = null
call GroupEnumUnitsInRange(g, x, y, csize[i], null)
loop
set tu = FirstOfGroup(g)
exitwhen null == tu
if PathUnitFilter(tu, u[i]) then
set hit = true
endif
call GroupRemoveUnit(g, tu)
endloop
if hitTree then
set speed[i] = speed[i] - (speed[i] * DECEL_SPEED_SCALE)
endif
if hit or not IsTerrainWalkable(x, y) then
call i.destroy()
endif
call SetUnitX(u[i], x)
call SetUnitY(u[i], y)
else
call i.destroy()
endif
else
call i.destroy()
endif
set hit = false
set hitTree = false
set i = n[i]
endloop
endmethod
static method add takes unit tu, real tspeed, real tangle, real ttime returns nothing
local integer i = GetHandleId(tu)
local thistype this = thistype(LoadInteger(ht, i, 0))
if this == 0 then
set this = rc[0]
if 0 == this then
set this = ic + 1
set ic = this
else
set rc[0] = rc[this]
endif
set n[this] = 0
set p[this] = 0
set n[p[0]] = this
set p[0] = this
set c = c + 1
if 1 == c then
call TimerStart(tm, TIMEOUT, true, function thistype.periodic)
endif
set csize[this] = GetUnitCollision(tu) + COLLISION_BONUS
set u[this] = tu
call SaveInteger(ht, i, 0, integer(this))
endif
set speed[this] = tspeed * TIMEOUT
set angle[this] = tangle * bj_DEGTORAD
set time[this] = ttime
endmethod
static method registerEvent takes integer KBEvent, code c returns nothing
if KBEvent == EVENT_KNOCKBACK_LOOP then
call onLoop.register(Filter(c))
elseif KBEvent == EVENT_KNOCKBACK_END then
call onDestroy.register(Filter(c))
endif
endmethod
private static method init takes nothing returns nothing
set onLoop = CreateEvent()
set onDestroy = CreateEvent()
set ht = InitHashtable()
endmethod
implement Init
endstruct
/*
* Wrappers
*/
function GetKnockbackOnLoopUnit takes nothing returns unit
return KnockbackEventOnLoopUnit
endfunction
function GetKnockbackOnEndUnit takes nothing returns unit
return KnockbackEventOnDestroyUnit
endfunction
function AddKnockback takes unit u, real speed, real angle, real time returns nothing
call Knockback2D.add(u, speed, angle, time)
endfunction
function DestroyKnockback takes unit u returns nothing
local Knockback2D i = Knockback2D(LoadInteger(ht, GetHandleId(u), 0))
call i.destroy()
endfunction
function RegisterKnockbackEvent takes code c, integer KBEvent returns nothing
call Knockback2D.registerEvent(KBEvent, c)
endfunction
endlibrary
Demo:
JASS:
struct Test extends array
private static method periodic takes nothing returns boolean
call DestroyEffect(AddSpecialEffect("Objects\\Spawnmodels\\Undead\\ImpaleTargetDust\\ImpaleTargetDust.mdl", GetUnitX(GetKnockbackOnLoopUnit()), GetUnitY(GetKnockbackOnLoopUnit())))
return false
endmethod
private static method run takes nothing returns boolean
local unit target
local unit caster = GetTriggerUnit()
local real x = GetUnitX(caster)
local real y = GetUnitY(caster)
local group g = CreateGroup()
call GroupEnumUnitsInRange(g, x, y, 500, null)
loop
set target = FirstOfGroup(g)
exitwhen target == null
if target != caster then
call AddKnockback(target, 500, Atan2(GetUnitY(target) - y, GetUnitX(target) - x) * bj_RADTODEG, 1.25)
endif
call GroupRemoveUnit(g, target)
endloop
call DestroyGroup(g)
set g = null
set caster = null
return false
endmethod
private static method onInit takes nothing returns nothing
local trigger t = CreateTrigger()
call TriggerRegisterAnyUnitEventBJ(t, EVENT_PLAYER_UNIT_SPELL_EFFECT)
call TriggerAddCondition(t, Condition(function thistype.run))
call RegisterKnockbackEvent(function thistype.periodic, EVENT_KNOCKBACK_LOOP)
set t = null
endmethod
endstruct
Changelogs
1.0
- Release
1.1
- Fix code errors(thanks to Spinnaker
1.2
- Added wrappers
- Fix code.
1.3
- code now stable
- Added test map.
1.4
- Optimized code.
- Cleaned some leaks.
- Add Table as a required library for finding unit index.
1.5
-Updated version,still buggy.
(Test map code is outdated,due to update)
Attachments
Last edited: