| 03-24-2007, 05:00 AM | #1 |
JASS:library EventTimer initializer init interface TimerEventListener boolean stop=false //If set to true it prevents the interface from running it, instead it cancels the event //It is never a good idea to just destroy the listener while it is active // If this method returns true, the system will destroy this object after executing it. method onExpire takes nothing returns boolean endinterface globals private timer T=null private timer gametime=null private TimerEventListener array events private real array expires private integer N=0 endglobals private function init takes nothing returns nothing set T=CreateTimer() set gametime=CreateTimer() call TimerStart(gametime,1000000.0,false,null) endfunction private function expire takes nothing returns nothing local integer i local integer cleft local integer cright if (N==0) then debug call BJDebugMsg("Warning: Event Lib expires with no event") return endif // [0] has expired... if ((events[0].stop) or (events[0].onExpire()) ) then call events[0].destroy() endif // Reheap the stuff... set N=N-1 set i=0 if (N==0) then //nothing to do here. return endif loop set cright=(i+1)*2 set cleft=cright-1 exitwhen (cleft>=N) if (cright<N) then if ( expires[cleft] <= expires[cright]) then if (expires[cleft] <=expires[N] ) then set expires[i]=expires[cleft] set events[i]=events[cleft] set i=cleft else exitwhen true endif else if (expires[cright] <=expires[N] ) then set expires[i]=expires[cright] set events[i]=events[cright] set i=cright else exitwhen true endif endif elseif ( expires[cleft] <= expires[N] ) then set expires[i]=expires[cleft] set events[i]=events[cleft] set i=cleft else exitwhen true endif endloop set events[i]=events[N] set expires[i]=expires[N] call TimerStart(T, expires[0]-TimerGetElapsed(gametime),false, function expire) endfunction function AddTimeEvent takes TimerEventListener lt, real delay returns nothing local real t=delay+TimerGetElapsed(gametime) local integer i=N local integer p set N=N+1 loop exitwhen i==0 set p= (i-1)/2 exitwhen (t >= expires[p]) set expires[i]=expires[p] set events[i]=events[p] set i=p endloop set events[i]=lt set expires[i]=t call TimerStart(T, expires[0]-TimerGetElapsed(gametime),false, function expire) endfunction endlibrary Names are temporary If you can come up with better names I might change them. I may have made a post about this system before. This is a new way to have timed events based in the pseudo OOP and has a couple of advantages over the old (CreateTimer + attach) usual one:
This new edition now also uses a heap as a priority queue so it is much faster than the old linear one. Logarithmic complexity to add events and when events expire. It is fast enough. The disadvantage is that interfaces require an extra funciton call + TriggerEvaluate when an event expires, so it is in theory slower than alternatives. Besides of the process of preparing the next event in the queue. But notice that dealing with DestroyTimer() / ReleaseTimer() , using H2I() and extra function calls to assist in that process (even TimerGetRemaining) could arguably be slower than that. So it is probably slower than native timers, but the advantages are worth it and it is very good for those processes that are not too frequent. Declaring an struct might also be over-verbose sometimes... Usage example: JASS:library TimedSpecialEffects requires EventTimer private struct expire extends TimerEventListener effect fx method onExpire takes nothing returns boolean call DestroyEffect( .fx) return true endmethod endstruct function AddSpecialEffectTimed takes string modelName, real x, real y, real duration returns nothing local expire e=expire.create() set e.fx=AddSpecialEffect(modelName,x,y) call AddTimeEvent(e, duration) endfunction function AddSpecialEffectTargetTimed takes string modelName, widget targetWidget, string attachPointName, real duration returns nothing local expire e=expire.create() set e.fx=AddSpecialEffectTarget(modelName,targetWidget,attachPointName) call AddTimeEvent(e, duration) endfunction endlibrary This is the alternative for random duration timers, for periodic timers (the animation ones typically 0.04 seconds) it is much better to keep an array of the objects to process and do so periodically, like what I did in this tutorial |
