- 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:
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
Go to the trigger editor and to the variables window and create the following variables:
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:
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:
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
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:
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.
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:
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 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
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
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:
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
-
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 --------
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)
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
-
Events
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.
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())
Attachments
Last edited: