| 04-16-2009, 01:39 PM | #1 |
All right, after the PeriodicLoopModule failure, this is a simpler version that is less flexible but should work, it is for structs that are exclusive for looping and will conflict with stuff that require you not to call .destroy but another method. It is a module you implement in a struct to do the whole array+loop thing that we always do in spells. Only that this time you won't have to code it all the time... an example: Only disadvantage against doing the loop manually is that it will do a function call (not TriggerEvaluate) for each instance in the loop. Differences with things like TT is the OOPness and the lack of TriggerEvaluate, though it uses a timer per struct type, wonder if that's important. Usage Sample:struct moveUnit unit u //===================================================== // You need to code an onTimedLoop method before // implementing the module. // private method onTimedLoop takes nothing returns boolean //instance's timer expired: // This will just move a unit's x coordinate with // a speed of 100 until it reaches 5000.0 call SetUnitX(u, GetUnitX(u) + 100.0* TimedLoop_PERIOD ) // notice the use of the TimedLoop_PERIOD constant // since it may be tweaked by the user... if ( GetUnitX(u) >= 5000) then return TimedLoop_STOP endif return TimedLoop_CONTINUE //You are free to/should use false and true instead of the //constants. endmethod implement TimedLoop //This does the module magic static method create takes unit u returns moveUnit local moveUnit m= moveUnit.allocate() set m.u = u call m.startTimedLoop() //The module works by // creating a startTimedLoop method that will // do all the dirty work and end up calling // .onTimedLoop... // return m endmethod endstruct //call moveUnit.create(GetTriggerUnit()) and see... Names are now finished.. thecode:library TimedLoop //******************************************************** //* TimedLoop //* --------- //* //* Requires jasshelper 0.9.G.1 or greater. //* //* A library + module that are meant to make those //* array + timer loops easy, yet still faster than //* other alternatives meant to be easy (In other words //* no TriggerEvaluate is involved). //* //* The OOPness is interesting. //* //* Before implementing TimedLoop //* your struct needs an onTimedLoop method that takes //* nothing and returns boolean, if the method //* returns false, the instance will get removed //* from the loop and destroyed, else it will continue, //* think of it as if the call asks the method a //* question: "Should I continue the loop afterwards?" //* //* Alternatively, if you are not convinced, you may //* use the TimedLoop_CONTINUE and TimedLoop_STOP //* constants in the method's returns. //* //* After implementing TimedLoop, you can call //* the startTimedLoop method to add the periodic event //* to that instance, only call it once per instance. //* //* I recommend to call implement just bellow the //* declaration of the onLoop method, else it will //* actually use TriggerEvaluate, which is lame. Remind //* me to implement a topsort in jasshelper. //* //* If you feel the need to destroy the struct outside //* the loop, well, you'll have to add a flag to it so //* you send a message to onLoop to make it return false. //* A more complicated module to allow that easily would //* come later. //* //******************************************************** //======================================================== // config: globals public constant real PERIOD = 0.025 // A lower value and everything using the module will // look better, yet performance will drop. endglobals //======================================================== // implementation: // globals public constant boolean STOP = false public constant boolean CONTINUE = true endglobals //=========================== module TimedLoop // god bless private module members. // private static thistype array V // The array private static integer N = 0 // The count private static timer T = null // the timer, one per // struct that implements this private static method onExpire takes nothing returns nothing local integer n = 0 local thistype this // yay for odd-sounding syntax constructs local integer i = 0 loop exitwhen (i== thistype.N) set this = .V[i] if ( this.onTimedLoop() == CONTINUE ) then set .V[n] = this set n=n+1 else call this.destroy() endif set i=i+1 endloop set thistype.N = n if (n== 0) then call PauseTimer(.T) endif endmethod public method startTimedLoop takes nothing returns nothing set .V[.N] = this set .N=.N + 1 if (.N == 1) then if (.T == null) then set .T = CreateTimer() endif call TimerStart(.T, PERIOD, true, function thistype.onExpire) endif endmethod endmodule endlibrary |
| 04-16-2009, 03:06 PM | #2 |
Function calls with no parameters are pretty fast, I have heard around as fast as using trig functions, and my physics engine has managed to use hundreds of them per second without lagging. People should get over the fear of using something like this for spell development. You could get around the one timer per struct-type problem by using a single public timer in the library. You would also need a new integer in the library that keeps track of the total instances using the timer so you know when to start/stop it. I did something like that in UnitList with a public trigger that each struct-type just adds an action to. I vote "LoopModule" for the name; everyone is naming their module libraries SomethingModule, just like when every new game for the Nintendo 64 ended with "64". |
| 04-16-2009, 03:12 PM | #3 |
The function call actually has a single "this" argument. PeriodicModule ? LoopModule sounds like a way to make it easy to loop through the instances of a struct anywhere. This is focused on timers. |
| 04-16-2009, 03:18 PM | #4 |
OK, it compiles to have one argument (I am sleepy), it's still very fast. Since your main function name is "startLoop," LoopModule kind of fits, but it would make more sense to call it PeriodicModule and rename the method to startPeriodic. |
| 04-16-2009, 06:09 PM | #5 |
I don't like having a fixed period. In my opinion it would be the better choice, to force the user to define a static constant real in ever struct using this. In movement stuff your constant may be the right choice, but for example in my buff system 0.25 is enough or sometimes it want to move something not i a smooth way. A feature for optimal overwriting of something from modules would be nice :) |
| 04-16-2009, 06:17 PM | #6 |
What's NOT_IN_LOOP for? It would help understanding if the post better conveyed which part is the module and which part is the example. Perhaps add some @@ highlights to the example? The module is very specific. I could see other uses for a list of all structs besides looping through them periodically (although that is the most common use and doing that alone is certainly justification enough for a module), could perhaps the list be one module and the timerloop another module that uses the list? |
| 04-16-2009, 08:32 PM | #7 | |
Quote:
I like this module because of being so specific, most of my spells really only need a single loop. |
| 04-16-2009, 09:47 PM | #8 |
JASS://* nothing and returns boolean, if the method //* returns false, the instance will get removed //* from the loop and destroyed. |
| 04-20-2009, 02:10 PM | #9 | |
Quote:
Ok, grim onLoop is a bad name for that method anyway. will have to think of a new name for the method and module. |
| 04-21-2009, 10:37 AM | #10 |
I remember cohadar saying something about how a true return signaling that an instance should be removed from a loop has become a standard. Also, a true return is what you use in TT. Personally I've always used false returns, in my own systems. Somehow it seems more intuitive. But yeah, it's a minor thing... |
| 04-21-2009, 11:21 AM | #11 |
I say that the boolean is for whether the loop should keep running. False = remove it from the loop. |
| 04-21-2009, 11:39 AM | #12 |
Periodic - True Not - False Standard established by Blizzard has been there far longer and used by everyone who uses timers directly. |
| 04-21-2009, 11:51 AM | #13 |
The boolean that's returned isn't an argument for starting a timer, it's an argument for whether it should continue or not. |
| 04-21-2009, 05:10 PM | #14 | |
Quote:
It's the same principle, so it makes no sense to flip it, as you could have it as a return as to whether to stop it or not, but stopping it is more negative than positive. |
| 04-22-2009, 10:42 PM | #15 |
You should return an enum (an integer, with some public constants). Nobody disagrees about what RET_REMOVE and RET_KEEP mean. |
