• Listen to a special audio message from Bill Roper to the Hive Workshop community (Bill is a former Vice President of Blizzard Entertainment, Producer, Designer, Musician, Voice Actor) 🔗Click here to hear his message!
  • Read Evilhog's interview with Gregory Alper, the original composer of the music for WarCraft: Orcs & Humans 🔗Click here to read the full interview.

Accurate timing for cinematics

Status
Not open for further replies.
Level 15
Joined
Jul 15, 2005
Messages
356
Before I spend a massive amount of time on a fix that might or might not work, I'd like to see what other people suggest...

I've got a cinematic-only map, with music in the background.

From my observations, the music always takes the same amount of time to play from start to finish, irrespective of the speed of a user's computer. However, the actions occurring in the cinematic can be slightly faster or slightly slower depending on the user's computer speed. This is a problem, because computers faster/slower than my test PC may cause the music to go out of sync with the events on-screen.

At the moment, the cinematic's events are a bunch of triggers separated by "Wait (game time)" commands, and I think that might be the problem.

My question is: to make sure the events on-screen always take the same amount of time (regardless of the speed of the user's computer), which of the following options will work?:

1) Using "Wait" (instead of "Wait (game time)")?
2) Using a separate trigger for everything that happens in the cinematic, with each trigger triggered by an individual countdown timer?
3) Using a separate trigger for everything that happens in the cinematic, with each trigger triggered by an "elapsed game time" event?
 
Level 15
Joined
Jul 15, 2005
Messages
356
did you try playing the music at Elapsed Game Time 1.00 instead of playing it at map initialization?

because at map initialization the music will be played when the player finishes loading but at elapsed game time 1.00 the music will start playing when all players finish loading the map and the game starts (i think)

Yeah, the music doesn't start on map initialization, so loading times for the map aren't a problem.

Only the 'wait time' between the in-game trigger actions are an issue. That wait time needs to stay the same in terms of real-world seconds irrespective of the user's PC speed.
 
Level 15
Joined
Jul 15, 2005
Messages
356
wait is really not a problem when using cinematic, I always use them...
countdown timer is an option but NOT elapsed game time coz it will bug...

I just tested two versions of the cinematic, one using "Wait (Game Time)" and one just using "Wait", both the same (slowish) machine.

Unfortunately the test was somewhat... inconclusive. The "Wait (Game Time)" test seemed to end a little later (ie, music stopped a bit earlier) than the "Wait" one, but not by a very appreciable amount.

I'll also be testing it on my home machine (which normally finishes MUCH earlier than my other machine here) later, but I'm afraid this might not have solved my problem...

To your knowledge, are countdown timers always accurate regardless of processor speed (within reason)? Implementing them as a fix will be nightmarish, so I don't really want to go down that road unless it really works.
 

Dr Super Good

Spell Reviewer
Level 64
Joined
Jan 18, 2005
Messages
27,258
no idea what on earth a "count down" timer is.

timer objects are virtually 100% accurate. I believe they generate some interupt using your system time so are slightly later (microseconds late) however for all purpose they keep time accuratly all the time.

I think I might finally have figured out how TriggerSleepAction works. It probably estimates time based upon the number of cycles the main WC3 thread is run divided by the clock rate of the processor. This will explain how results vary so much between systems. In Multiplayer it probably even generates a server icommand (for sync) so latency gets added to it.
 
Level 15
Joined
Jul 15, 2005
Messages
356
no idea what on earth a "count down" timer is.

timer objects are virtually 100% accurate. I believe they generate some interupt using your system time so are slightly later (microseconds late) however for all purpose they keep time accuratly all the time.

I think I might finally have figured out how TriggerSleepAction works. It probably estimates time based upon the number of cycles the main WC3 thread is run divided by the clock rate of the processor. This will explain how results vary so much between systems. In Multiplayer it probably even generates a server icommand (for sync) so latency gets added to it.

'Countdown timer' is in reference to the GUI interface for the Trigger editor - timers are referred to as 'countdown timers' there (eg, action: "Countdown Timer - Start timer").

Maybe the best solution is to break the entire cinematic up into a heap of different triggers, each triggered by a countdown timer.

Uh... this is going to be horrid, but it sounds like the most feasible solution.
 
Level 15
Joined
Jul 15, 2005
Messages
356
although timers is more accurate than waits, you will create another trigger(s), timer and a lot of actions involved, so it's a lot slower than waits...

means...
trigger 1:
create cinematic dialog
create sound
create timer

trigger 2:
timer expires
destroy timer
continue cinematic
and so on...


Yeah, I know. It's a pain. Every instance of 'wait' in my cinematic will instead have "start timer, enable next trigger (which triggers when the timer expires), destroy current trigger" at the end. Still, if that's what it takes for accuracy, that's what I'll do.
 
Level 37
Joined
Mar 6, 2006
Messages
9,243
I was thinking something like this:


  • Untitled Trigger 130
    • Events
      • Unit - A unit enters Region 001 <gen>
    • Conditions
    • Actions
      • Game - Display to Player Group - Player 1 (Red) the text: enter
      • If (All Conditions are True) then do (Then Actions) else do (Else Actions)
        • If - Conditions
          • i1 Equal to 0
        • Then - Actions
          • Trigger - Turn off (This trigger)
          • Cinematic - Turn cinematic mode On for (All players) over 2.00 seconds
          • Set trig = Untitled Trigger 130 <gen>
          • Countdown Timer - Start timer as a One-shot timer that will expire in 2.00 seconds
          • Skip remaining actions
        • Else - Actions
      • If (All Conditions are True) then do (Then Actions) else do (Else Actions)
        • If - Conditions
          • i1 Equal to 1
        • Then - Actions
          • Cinematic - Send transmission to (All players) from Hero named Arthas: Play No sound and display Suck my salty chock.... Modify duration: Add 0.00 seconds and Don't wait
          • Countdown Timer - Start timer as a One-shot timer that will expire in 2.00 seconds
          • Skip remaining actions
        • Else - Actions
      • If (All Conditions are True) then do (Then Actions) else do (Else Actions)
        • If - Conditions
          • i1 Equal to 2
        • Then - Actions
          • Cinematic - Send transmission to (All players) from Hero named Arthas: Play No sound and display They are deliciuos.. Modify duration: Add 0.00 seconds and Don't wait
          • Countdown Timer - Start timer as a One-shot timer that will expire in 2.00 seconds
          • Skip remaining actions
        • Else - Actions
      • If (All Conditions are True) then do (Then Actions) else do (Else Actions)
        • If - Conditions
          • i1 Equal to 3
        • Then - Actions
          • Cinematic - Turn cinematic mode Off for (All players) over 2.00 seconds
          • Set i1 = 0
        • Else - Actions
  • Untitled Trigger 131
    • Events
      • Time - timer expires
    • Conditions
    • Actions
      • Set i1 = (i1 + 1)
      • Trigger - Run trig (ignoring conditions)


It does a lot of checks if there are a lot of waits. But I don't really care about that personally.
 
Last edited:
Level 15
Joined
Jul 15, 2005
Messages
356
I was thinking something like this:


  • Untitled Trigger 130
    • Events
      • Unit - A unit enters Region 001 <gen>
    • Conditions
    • Actions
      • If (All Conditions are True) then do (Then Actions) else do (Else Actions)
        • If - Conditions
          • i1 Equal to 0
        • Then - Actions
          • Trigger - Turn off (This trigger)
          • Cinematic - Turn cinematic mode On for (All players) over 2.00 seconds
          • Set trig = Untitled Trigger 130 <gen>
          • Countdown Timer - Start timer as a One-shot timer that will expire in 2.00 seconds
        • Else - Actions
      • If (All Conditions are True) then do (Then Actions) else do (Else Actions)
        • If - Conditions
          • i1 Equal to 1
        • Then - Actions
          • Cinematic - Send transmission to (All players) from Hero named Arthas: Play No sound and display Suck my salty chock.... Modify duration: Add 0.00 seconds and Don't wait
          • Countdown Timer - Start timer as a One-shot timer that will expire in 2.00 seconds
        • Else - Actions
      • If (All Conditions are True) then do (Then Actions) else do (Else Actions)
        • If - Conditions
          • i1 Equal to 2
        • Then - Actions
          • Cinematic - Send transmission to (All players) from Hero named Arthas: Play No sound and display They are deliciuos.. Modify duration: Add 0.00 seconds and Don't wait
          • Countdown Timer - Start timer as a One-shot timer that will expire in 2.00 seconds
        • Else - Actions
      • If (All Conditions are True) then do (Then Actions) else do (Else Actions)
        • If - Conditions
          • i1 Equal to 3
        • Then - Actions
          • Cinematic - Turn cinematic mode Off for (All players) over 2.00 seconds
          • Set i1 = 0
        • Else - Actions
  • Untitled Trigger 131
    • Events
      • Time - timer expires
    • Conditions
    • Actions
      • Set i1 = (i1 + 1)
      • Trigger - Run trig (ignoring conditions)


It does a lot of checks if there are a lot of waits. But I don't really care about that personally.

That would work too. I guess it would reduce the total number of triggers. Effectively it does the same thing though, and since I've alredy started breaking it up into separate triggers I'll stick with that for now...
 
Maker, you could really improve your trigger:


  • Untitled Trigger 130
    • Events
      • Unit - A unit enters Region 001 <gen>
      • Time - timer expires
    • Conditions
      • Or - Any conditions are true
        • (Triggering unit) Equal to no unit
        • Execution count of (This trigger) Equal to 1
    • Actions
      • Game - Display to Player Group - Player 1 (Red) the text: enter
      • If (All Conditions are True) then do (Then Actions) else do (Else Actions)
        • If - Conditions
          • i1 Equal to 0
        • Then - Actions
          • Cinematic - Turn cinematic mode On for (All players) over 2.00 seconds
          • Countdown Timer - Start timer as a One-shot timer that will expire in 2.00 seconds
        • Else - Actions
          • If (All Conditions are True) then do (Then Actions) else do (Else Actions)
            • If - Conditions
              • i1 Equal to 1
            • Then - Actions
              • Cinematic - Send transmission to (All players) from Hero named Arthas: Play No sound and display Suck my salty chock.... Modify duration: Add 0.00 seconds and Don't wait
              • Countdown Timer - Start timer as a One-shot timer that will expire in 2.00 seconds
            • Else - Actions
              • If (All Conditions are True) then do (Then Actions) else do (Else Actions)
                • If - Conditions
                  • i1 Equal to 2
                • Then - Actions
                  • Cinematic - Send transmission to (All players) from Hero named Arthas: Play No sound and display They are deliciuos.. Modify duration: Add 0.00 seconds and Don't wait
                  • Countdown Timer - Start timer as a One-shot timer that will expire in 2.00 seconds
                • Else - Actions
                  • If (All Conditions are True) then do (Then Actions) else do (Else Actions)
                    • If - Conditions
                      • i1 Equal to 3
                    • Then - Actions
                      • Cinematic - Turn cinematic mode Off for (All players) over 2.00 seconds
                      • Set i1 = 0
                    • Else - Actions
      • Set i1 = (i1 + 1)
 

Dr Super Good

Spell Reviewer
Level 64
Joined
Jan 18, 2005
Messages
27,258
You could also try the dynamic execution approach. Placing each section of script into a uniquly but predictable named function and then executing this function via the function name string.

For example TIMEDCODE1 which then gets followed by TIMEDCODE2 etc. Yes I know the function that does this is a lot slower than trigger evaluations but the ability to create an engine which executes based on a predictable pattern would be a lot easier to manage.

The ultimate approach would be to just make triggers with each action block in them and use a trigger array to store them and then incriment through them like a list with delays next between them. This however requires a lot of hard coding each function name. Even better would be an array of function pointers but unfortunatly that is impossible in JASS (it throws an error if you try and array that type).
 
Level 15
Joined
Jul 15, 2005
Messages
356
Thanks for all the advice guys.

What worked best for me was the low-tech approach - a long series of initially disabled triggers, each triggered by an individual (unique) countdown timer. Every trigger in the series enables the next trigger and countdown timer that will set off the next trigger, and each trigger gets destroyed after it's gone off.

It's inelegant, but the timing is consistently perfect, so I'm happy with it.
 
Status
Not open for further replies.
Top