• 🏆 Texturing Contest #33 is OPEN! Contestants must re-texture a SD unit model found in-game (Warcraft 3 Classic), recreating the unit into a peaceful NPC version. 🔗Click here to enter!
  • It's time for the first HD Modeling Contest of 2024. Join the theme discussion for Hive's HD Modeling Contest #6! Click here to post your idea!

Exact Cinematic Timing (Trigger Queue and Timers)

Level 10
Joined
Jul 14, 2004
Messages
463
The Problem
Wait actions never work exactly and this is annoying especially when you create cinematics. If you don't know this problem, read the rest of this paragraph, otherways continue.
Maybe you noticed this when you built camerasways in the past: You said "Apply CameraX over 3 seconds", added a "Wait 3 seconds" behind it and then a final "Apply CameraY over 2 seconds". Then the sway will look very ugly because the sway stops for about 0.2 seconds when it reaches CameraX. The reason is that the "Wait" waits always longer than requested, no matter if it is a normal or a gametime "Wait". And the worst: the amount of delay always varies, so you often can't just make the waits shorter and everything is fine. This is annoying especially if you want to time animations and effects in action scenes.

Standard Solutions
Use a periodic event like used in Infrane's and Anitarf's JASS Cinematic System. If you don't want to do nearly everything in JASS, there is another alternative to these damn "Wait" actions: Use "Elapsed gametime equal to x seconds" events. They are exact. But they have obviuosly huge disadvantages:
  • You cannot use them in playable maps (because you don't know how long the player will need until he is ready for your cinematic) and
  • if you change any timing value at the beginning of the cinematic, you often have to adjust every following trigger which can be very much work
This Tutorial's Solution
This tutorial will teach you how to use a timer and the trigger queue to get your cinematic actions perfectly timed.

The Trigger Queue
The trigger queue is an old feature available since Reign Of Chaos but I never saw anybody using it; so there will probably be many people who don't know what it is and how it works. If you know the trigger queue and how to use it, skip to the next point.
The trigger queue is, just as the name says a queue of triggers. The triggers will be executed in the order you added them, so if you add Trigger1, then Trigger2 and then Trigger3, Trigger1 is the first that will be executed. The actions of the first trigger in the queue will be executed instantly. The second trigger waits until the first is removed from the trigger queue and as soon as the first is removed, it will instantly start. This is what we are going to base our cinematic's timing on.

What you need
  • a Reign of Chaos or Frozen Throne World Editor
  • basic knowledge of the trigger editor and variables
1. Setting up the variables
Go to the trigger editor and to the variables window and create the following variables:
  • "NextTrigger", type Timer, starting value "New Timer"
  • RunningTrigger, type Trigger, starting value nothing
Close the variables window

2. Creating the trigger structure
Well, of course it is not necessary that you use this structure for your map, but I recommend it when you use this method the first time, because I had good experiences with it. Later you may use your own variation if you like it more.
You should have a folder for initialization and general triggers. In this folder, I devide the simple initialization triggers and the general triggers by comments. You can do this as you like, but you should know what is where and be able to find it easily. I have two initialization triggers: One to fire at "Map Initialization" and one to fire at "Elapsed game-time is 0.00 seconds". We need the difference because the first is still in loading screen and the second is actually about 0.2 seconds after the loading screen, so you see the difference this trigger causes, if there is any (e.g. I often see cinematics that turn cinematic mode on at 0.00 seconds - this should save loading time, I heard. This may be, but it looks so ugly that you really should do this at map init).
Create also a new folder called "Queued Cinematic Triggers". Your structure in the trigger editor should now look like this:
attachment.php


3. Create your first cinematic trigger
All queued cinematic triggers do not need any event or condition.
The first cinematic trigger has three parts, which you should show by comments:
  • Setup for next trigger in queue
  • Add scene triggers to the queue
  • This cinematic trigger's actions
Add trigger actions as shown:
  • Cinetrigger 01
    • Events
    • Conditions
    • Actions
      • -------- Setup for next trigger in queue --------
      • Set RunningTrigger = (This trigger)
      • Countdown Timer - Start NextTrigger as a One-shot timer that will expire in 2.00 seconds
      • -------- Add this scene's triggers --------
      • -------- This cinematic trigger's actions --------
Instead of 2.00 seconds, you should insert the time you want to wait until the next cinematic trigger should start.
We don't have any additional triggers for this scene yet so we can't add any.
The first trigger will fire instantly when the cinematic should start, so add things like applying the first camera and fading in the third part. You should always add only actions that you want to execute actually at the moment the trigger fires, because we want to get rid of waits, so it's best not to begin using them at all.

At last, add a trigger action
  • Trigger - Add Cinetrigger 01 <gen> to the trigger queue (Ignoring conditions)
where you want to start the cinematic, in my example I add it to the "Gametime 0 init" trigger.

4. Create following cinematic triggers
The normal cinematic triggers structure is nearly the same as with the first one, but the "Add this scene's triggers" part is missing. So I just copy&paste the first trigger, rename it and replace each "start NextTrigger" time with the time I need (this may also be very few, e.g. 0.1 seconds - it will work well and exactly!) as well as of course setting "This cinematic trigger's actions" to the ones I need. You may do it the same way or copy the things manually if you prefer this for any reason.

5. Adding the following cinematic triggers to the queue
Well, now that we have some more triggers for the queue, we should also add them. You should do this in the first trigger in the "Add this scene's triggers" using actions of the type "Trigger - Add trigger to the trigger queue" for every following trigger in the scene.

Now we have all triggers in the queue, but if you remember the principe the trigger queue works, you should know that only the first one will fire, because it keeps the others from starting until it is removed.

6. Create the "Start Next Trigger" Trigger
Just add the following trigger to the General Triggers:
  • Start Next Trigger
    • Events
      • Time - NextTrigger expires
    • Conditions
    • Actions
      • Trigger - Remove RunningTrigger from the trigger queue

Final Notes
Well, I could say, that's all. So how does this work? At the start of every queued trigger, the variable "RunningTrigger" is set to this trigger, so always the running trigger will be removed from the queue. But it will wait with removing and therefore with firing the next trigger until the timer expires. As soon as the timer expires, the current trigger is removed and the next trigger starts, so the effect is just as if you would have copied each following trigger's actions to the first with a wait between the "actions-packs". But since timers are very accurate, you now have perfect timing that always behaves the same way.

Scenes
Theoretically, you can add all triggers to the trigger queue at the beginning of the cinematic. I did not test it, but I think it's better for performance to keep the trigger queue not too long. You also can add always only the following trigger when starting each of the triggers, but that's probably quite difficult to overview. I personally prefer a structure of scenes: I give all triggers of each scene the same name and a number. In the first trigger of each scene, I add all remaining triggers of the scene and the first of the next scene to the queue.

Escape function in playable maps
Canceling a cinematic in playable maps also gets much easier. You don't need any boolean "cinematic skipped" variable or all these if/then/else actions with "skip remaining actions" any longer. Just pause the NextTrigger timer and clear the trigger queue. Now nothing of the cinematic triggers should follow anymore but everything is ready for the next cinematic. Of course you should fade out and setup the things for continuing gameplay, too. :wink:

Optimizing performance
Well, probably you already realized that this method will cause you to build very many small triggers instead of the few big ones you had using waits. Every trigger takes memory, so you should try to reduce their count ingame. The best way to do this is just to add this action to every trigger that, once it's executed, is no longer needed:
  • Custom Script: call DestroyTrigger(GetTriggeringTrigger())
This will free the memory the trigger took before, but the trigger is not useable in any way afterwards. Anyways, I recommend that, because probably you are not able to build a map that does not at all use more and more memory with increasing game time (leak), and the more memory a map uses, the slower it will run, especially on computers with not that much RAM.
 

Attachments

  • TimerTutE.jpg
    TimerTutE.jpg
    15.8 KB · Views: 5,497
Last edited:
Level 40
Joined
Dec 14, 2005
Messages
10,532
The big problem with this is that it promotes excessive trigger spamming, but meh, what can'ya do.

I'll leave this open for comment for a bit, but nothing stands out really (to make it not get approved), other than the fact that I want other peoples' opinions, and that you forgot to remove your signature ;)
 
Level 10
Joined
Jul 14, 2004
Messages
463
Well, "trigger spamming" sounds worse than it is, I think. To free some memory, you can of course add a DestroyTrigger(GetTriggeringTrigger()) to every cinematic action. The problem with that is of course that you can't use the trigger any longer then, and maybe there are some less experienced people who wonder what's happening if a trigger is no longer available because it's destroyed. Shall I add a little paragraph in the end about this?
And the possibility of reliable timing is worth the little plus in effort and trigger count, I think.

Oh and I removed my signature... was that written in the rules? Ah, now I saw it, no problem (what is this rule for, by the way?).
 
Level 40
Joined
Dec 14, 2005
Messages
10,532
[quoted from the announcement thread]

No signature files may be attached to tutorials. (...)

And the possibility of reliable timing is worth the little plus in effort and trigger count, I think.
Yeah, sadly GUI can't just do fnctions. But meh, jass ftw!

And go ahead and add such a paragraph if you want.

Oh, also, indenting? Just a suggestion.
 
Level 40
Joined
Dec 14, 2005
Messages
10,532
use
tags.

It indents the entire thing, so I'd suggest opening and closing or so over the first word, and seeing if that works.

Test;

TEST​
adfasf safasdf saf saf asf sf saf saf sf asf saf saf saf asf asf asf sf asf saf asf saf asf sf saf s fsaf asf sadf saf asf asf sadf asf asf saf asf sf

EDIT: I guess it adds a linebreak after you close the indent tags, hmm, that complicates it...​
 
Top