| 07-22-2011, 03:01 AM | #1 |
Here's a simple respawning trigger: JASS:library RefreshEnemies initializer init requires TimerUtils private struct Respawn unit c timer t real x real y endstruct globals Respawn array RespawnEnemyGroup integer EnemyRefreshCount = 0 endglobals private function Conditions takes nothing returns boolean return GetOwningPlayer(GetDyingUnit()) == Player(11) and RectContainsUnit(gg_rct_W_Battlefields, GetDyingUnit()) == false endfunction private function TimerCallback takes nothing returns nothing local Respawn data = RespawnEnemyGroup[EnemyRefreshCount] local timer t = GetExpiredTimer() call PauseTimer(t) call SetUnitPosition(data.c, data.x, data.y) set RespawnEnemyGroup[EnemyRefreshCount] = RespawnEnemyGroup[EnemyRefreshCount] - 1 set EnemyRefreshCount = EnemyRefreshCount - 1 call ReleaseTimer(t) call RespawnEnemyGroup[EnemyRefreshCount].destroy() endfunction function RemoveEnemyGroup takes unit u returns nothing local Respawn data = Respawn.create() set EnemyRefreshCount = EnemyRefreshCount + 1 set RespawnEnemyGroup[EnemyRefreshCount] = data set data.c = u set data.x = GetUnitX(data.c) set data.y = GetUnitY(data.c) set data.t = NewTimer() call SetUnitPosition(data.c, GetRectCenterX(GetWorldBounds()), GetRectCenterY(GetWorldBounds())) call TimerStart(data.t, 60., false, function TimerCallback) endfunction //=========================================================================== private function init takes nothing returns nothing endfunction endlibrary What this trigger does is that whenever an enemy unit of a certain type dies, it gets moved to the center of the map (I will change this later), makes a timer that counts down for a minute, then puts the unit back where it disappeared. I probably didn't need a struct to do this, but I really need to practice simple struct usage. This works great and all, but there's one issue and I knew that this trigger was going to do this when I was making the trigger: the unit that dies is assigned an index in the struct to keep track of it and put it back after a minute. However, I don't know how to identify which index that a particular unit has in the struct array. This causes problems, like so: Unit A dies and becomes struct index [0]. Timer starts for [0]. Unit B dies and becomes index [1] ten seconds later. But because the index does not change what it is assigned to until timer[0] finishes, when timer[0] does finish we're still at the struct array at [1], causing Unit B to be moved back. Even though Unit A moved first. How do I go about this the right way? My alternative route is to make this trigger for every unit type, but seriously... that's tedious and I imagine 99% unnecessary. Please tell me that this as easy as it sounds. |
| 07-22-2011, 04:24 AM | #2 |
Why do you need to store it in an array? Since you're already using TimerUtils you can just store the struct index in the timer and then get it in the callback: JASS:library RefreshEnemies initializer init requires TimerUtils private struct Respawn unit c timer t real x real y endstruct private function Conditions takes nothing returns boolean return GetOwningPlayer(GetDyingUnit()) == Player(11) and RectContainsUnit(gg_rct_W_Battlefields, GetDyingUnit()) == false endfunction private function TimerCallback takes nothing returns nothing local timer t = GetExpiredTimer() local Respawn data = Respawn(GetTimerData(t)) call PauseTimer(t) call SetUnitPosition(data.c, data.x, data.y) call ReleaseTimer(t) call data.destroy() set t = null //Remember to null the timer :o endfunction function RemoveEnemyGroup takes unit u returns nothing local Respawn data = Respawn.create() set data.c = u set data.x = GetUnitX(data.c) set data.y = GetUnitY(data.c) set data.t = NewTimer() call SetTimerData(data.t, integer(data)) call SetUnitPosition(data.c, GetRectCenterX(GetWorldBounds()), GetRectCenterY(GetWorldBounds())) call TimerStart(data.t, 60., false, function TimerCallback) endfunction //=========================================================================== private function init takes nothing returns nothing endfunction endlibrary |
| 07-22-2011, 06:07 AM | #3 |
... Really? Ah, I didn't know I could do that with TimerUtils... Hmm... Gives me ideas. Thank you for showing me this. |
| 07-22-2011, 09:44 AM | #4 |
Yeah, TimerUtils rocks. |
| 07-22-2011, 11:12 AM | #5 |
You don't need "call PauseTimer(t)" because TimerUtils pauses the timer automatically when you do ReleaseTimer. |
| 07-22-2011, 01:34 PM | #6 |
There's nothing wrong with attaching instances to timers using TimerUtils, however due to the constant timer timeout this is one of those rare cases that can be solved with just a FIFO data structure like a queue. The speed advantage that gives you is utterly insignificant, but it can be an interesting exercise that provides an answer to your original problem rather than bypassing it. JASS:private struct Respawn unit c real x real y static thistype first=0 static thistype last=0 thistype next static method callback takes nothing returns nothing // Get the instance at the start of the queue and remove it. local thistype this=.first set .first=.next // Move the unit back to the original coordinates. call SetUnitPosition(.c, .x, .y) // Destroy the instance. call .destroy() // Recycle the timer. call ReleaseTimer(GetExpiredTimer()) endmethod static method create takes unit u returns thistype local thistype this=thistype.allocate() set .c=u set .x=GetUnitX(u) set .y=GetUnitY(u) // Move the unit to the center of the map. call SetUnitPosition(.c, GetRectCenterX(GetWorldBounds()), GetRectCenterY(GetWorldBounds())) // Add the new instance to the end of the queue. if .first==0 then // List doesn't contain instances. set .first=this else // List contains instances. set .last.next=this endif set .last=this set .next=0 // Start the timer. call TimerStart(NewTimer(), 60.0, false, function thistype.callback) return this endmethod method onDestroy takes nothing returns nothing set c=null // Not really needed. endmethod endstruct /* Note: this simple example code does not support the destruction of an instance while its timer is still running, but I think it is sufficient for your purposes. |
| 07-23-2011, 06:48 AM | #7 | |||
Quote:
Quote:
Oh, how interesting. It kind of confuses me, but I will learn it... albeit slowly. I hadn't realized it before, but Vex putting structs into Jass was essentially creating object oriented programming for Warcraft III. Never once have I really been formally taught any kind of programming, so yeah it is... difficult thinking in this kind of way. But I've been getting better! Although the material is getting more complicated. I am going to keep both versions in my map. The former I can use as a TimerUtils usage reference. The latter solves my problem directly. Thanks, you guys. |
