HomeUser Control Panel (unavailable in archive)ForumsTutorialsArt GalleryResourcesMaps

Handle Variables. WHAT?!

01-27-2006, 04:31 AM#1
Beeva186
Rightio, now I'm feeling pretty damn stupid. I know this must get asked a lot, but I have yet to find an answer I can comprehend.
1. Are handle variables needed if you want to, say, make a timer that smoothly makes a unit transparent?
2. If they are , can someone please tell me what the hell they are, and how to implement them?
Argh!
01-27-2006, 07:35 AM#2
Moss
I just learned about these myself not so long ago. They are variables wich are are attached and local to a handle (unit, effect, trigger, timer etc.). They can definitely be very usefull. I found a good explanation how to use them here: http://www.wc3jass.com/viewtopic.php?t=2006 and to "install" the system in your map you just copy and paste the script from http://wc3sear.ch/index.php?p=JASS&ID=39 into the custom script section of your map. But I heard Vexorian say that that system isn't as efficient as his CSCache module in his Caster System, but maybe you don't want to install that whole beast in your map.

It probably would help for smoothly making a unit go transparent. I read a tut showing how to make a unit slide smoothly using Handle Vars, but the code didn't make much sense to me, I wouldn't mind a breakdown of something like that myself. All I know is that the Wait function (aka TriggerSleep function) has a minimum of 0.2 seconds whereas a timer can be really short. So if you want your unit to go transparent of 10 seconds it would probably look smooth enough...
01-27-2006, 08:25 AM#3
Anitarf
To make units smoothly transparent, you can use the particle sub-system from my cinematic system.

Otherwise, the use of a timer for this purpose is explained here (link can also be found in the thread Moss linked to). The idea is that since waits are inaccurate at short intervals, we must either use a periodic event, or a timer. Either way, the whole slide won't be done by a single function, but by many function calls, so we can't use local variables to store data, because locals are function-specific. That's why we use handle variables. A timer is a handle, so we can attach data to it with handle vars; This way, we can pass this data between the function that creates the timer and the function that runs when the timer expires.
01-27-2006, 08:53 AM#4
Beeva186
Argh.. thanks guys... I think my not understanding of handles is due to my own incapacity to get my head around it rather than the incompetency of the people trying to explain it... I guess I'll just work through it some more.
01-27-2006, 09:43 AM#5
qwertyui
Ohhh...

Will split explanation in 3 parts for easier comprehension.

---------------------
What are handle variables?

The full handle variable system is not absolutely necessary for what you are trying to do. But it still makes things easier.

A definition of handle in WC3 is basically everything which is not an integer, real, boolean, string or "code" type variable.

Units are handles, timers are handles, doodads are handles. Everything which is not a basic variable type is a handle.

What the handle variables system does is it allows to attach other variables to handles. If you already have some experience with Unit Custom Values, which attach an integer to a unit, that gives you a pretty good idea on how handle variables work.
The difference is, handle variables allow you to attach not only integers, but also reals, booleans and other handles.

So you can make systems of interrelated handles, each with their own specific additional data stored into them.

---------
Timers and vanishing

Creating a unit that smoothly vanishes is a somewhat separate issue.

Vanishing gradually means moving your unit through a set number of states, where each new state has higher and higher transparency levels.

In order for fading out to be smooth, these states have to change rapidly. Think about camera film for a second. It gives you a smooth moving picture, by showing you 60 static pictures a second. You need to do the same here - rapidly move your unit through large number of incrementing transparency levels. You don't need 60, but at least 20 is more or less required.

Now, there is a problem of course. There always is one.
In this case, the problem is that normal wait trigger action will not allow you to wait less than 0.23 seconds. That means that you cannot realistically make more than 4 "frames per second" if you use Wait-based trigger. So something different has to be invented.

That something different is the use of Timers.
Timers help out in this respect a lot, because they are not limited to .23 seconds wait and can measure much smaller time values.

The idea is to create a repeating .05 seconds timer and fade a unit a bit more every time it expires, for making a nice, smooth, 20fps fade.

-------------------------
Handle variables and timers.

Basically timer is a handle. Using Handle variables system, you can attach it to other handles.
That means you can assign every unit to a specific timer. Which helps out when you suddenly need to have multiple independent timered events going on your map at the same time.

EDIT: typo, there always is one :/
01-27-2006, 03:08 PM#6
Vexorian
CSCache without caster system : http://www.wc3jass.com/viewtopic.php?t=2336

If you are going to use Handle variables use this official link instead http://www.wc3jass.com/viewtopic.php?t=224 it will at least load faster.

CSCache 's reason to be faster is that you can use tables, without over calling H2I it can seriously improve the efficiency
01-27-2006, 07:57 PM#7
Moss
Actually qwertyui, its 24fps for cinema film and 30fps for NTSC television. Nice explanation though. So let me see if I get how this works.

Trigger 1:
Events:
-Unit casts an ability
Conditions:
-Ability == GoTransparent
Actions:
-Create a timer which expires in 0.05
-call SetHandleHandle([whatever the jass is for last created timer],"transTimer", GetTriggerUnit())
-call SetHandleReal([last created timer],"transReal", 0.00)

Trigger 2:
Events:
-Timer Expires
Conditions:
Actions:
-set udg_temp_unit = GetHandleUnit(GetExpiredTimer(), "transTimer")
-if (GetHandleReal(GetExpiredTimer() < 100.00) then
-set udg_temp_real = GetHandleReal(GetExpiredTimer(), "transReal") + 5.00
-change vertex coloring of temp_unit to .... temp_real transparency
-revive the expired timer or whatever
-else
-FlushHandleLocals(GetExpiredTimer())
-destroy the timer
-endif

That isn't the proper wording for those functions by any means, I don't have access to the World Editor from here, but at least I think I did the get and set handle functions right. So in the first trigger we start the ball rolling by making a trigger and attaching the triggering unit and a real to it. In the second trigger which fire every time the timer expires we check if the real is 100 yet and if not bump it up 5 and set the unit to whatever it is. Otherwise clean all the variables off the timer and then destroy it so there is no memory leaking.
01-27-2006, 08:56 PM#8
Beeva186
Ah, that explanation was much clearer qwertyui, thanks heaps. Relating it to custom values of units makes it a lot easier to understand. Oh, and I'll look at that CSCache thing as well Vexorian. Thanks, guys.
One more thing, I was looking at KaTTana's timer tutorial:

Code:
function UPDATE_FUNC takes nothing returns nothing
    local timer t = GetExpiredTimer()
    local integer steps = GetHandleInt(t, "steps")

    // Get parameters again using GetHandleHandle(t, "...")

    // Do loop actions....

    if ( steps <= 1 ) then // Check if loop is over
        call FlushHandleLocals(t)
        call DestroyTimer(t)
        return
    endif
    call SetHandleInt(t, "steps", steps-1)
endfunction

function START_FUNC takes ...variables..., real duration returns nothing
    local timer t = CreateTimer()
    local real update = 0.10 // Update interval

    // Store parameters using SetHandleHandle(t, "...", ...)

    call SetHandleInt(t, "steps", R2I([b]duration[/b]/update))
    call TimerStart(t, update, true, function UPDATE_FUNC)
endfunction
Where does that duration part near the bottom come from? it's not a local variable or a global so what in the hell is it?
01-27-2006, 10:05 PM#9
Anitarf
It's a parameter of the function.

"function START_FUNC takes ...variables..., real duration returns nothing"
01-28-2006, 03:06 AM#10
Beeva186
Do I actually need to "install" that local handle variables thing into my map? Man, I'm finding this so god damn hard.. I've been trying for a long while and I can't even do a simple little timer because it crashes my map when it runs...
01-28-2006, 05:23 AM#11
Guest
Wouldn't using handle vars be 4 times slower than using an array, since it uses gamecache, and Vexorian says gamecache is 4 times slower than arrays?
01-28-2006, 10:59 AM#12
Anitarf
Not four, it would be ten times slower, because of the H2I. However, when having to store handle-specific data, it's the only way; it's seldom used in massive ammounts (for example in individual spells), and when it is (for example in general map systems), you can always optimize it by not using the handle vars functions, but gamecache natives instead.
01-28-2006, 04:37 PM#13
agamemnus
Well.. what I've done recently is to try to use "un-needed" data in my objects to stash their index. That way you don't need handle variables but only arrays.. For example I stored the index of all my trees in the map in the maximum life of the tree variable. I've had to add 100 to that though because max life dynamically updates if it is less than actual life.
01-28-2006, 04:41 PM#14
Vexorian
yeah well any alternative to using gamecache H2I has been proven to be extremely unpractical and slower in practice
01-28-2006, 04:54 PM#15
agamemnus
Tis practical and fast for what I'm doing, though..