Adventure Game Studio

AGS Support => Advanced Technical Forum => Topic started by: bx83 on Thu 21/03/2019 20:48:59

Title: Using timers and aSound.Play() to do a non-blocking fade-in/fade-out
Post by: bx83 on Thu 21/03/2019 20:48:59
I'm trying to use timers as a way of achieving a non-blocking fade-in/out. This is because I want the screen to go gradually black *at the same time* as a piece of fading-out audio ending; not immediately after.
This timer/audio playing is done instead of:

cCharacter.Say("&1 Blah blah blah blah blah blah....");
FadeOut();
Wait(GetGameSpeed()*1);
FadeIn();
cCharacter.Say("&2 .....blah blah blah blah blah blah....");
FadeOut();
Wait(GetGameSpeed()*1);
FadeIn();
cCharacter.Say("&3 .....blah blah blah blah blah blah.");

...because speech is always blocking, so the screen fade-out starts after the audio finishes.
The audio itself fades-out, so for this to happen at the same time as the screen fade-out is ideal.

This is what I've come up with at the moment, which obviously doesn't work.
I've also tried SayBubble() instead of SayBackground() - but of course speech is blocking, so even timers and timer-checking is not worried about.

GlobalScript.asc:

function BuddhistCowIslandSpeech()
{
  game.bgspeech_stay_on_display = 1;

  gTitleCard.BackgroundGraphic=3144;       //size-of-background black graphic
  gTitleCard.Transparency=100;  //invisible
  gTitleCard.Visible=true;

  SetTimer(TIMER_BUDDHIST_FADE_IN_OUT, GetGameSpeed()*22);
  BuddhistFadeInOut=100;
 
  BuddhistFadeInOut_1=true;
 
  aBUDD64.Play(eAudioPriorityNormal, eOnce);    //This audio is the speech part to the following line - so normally it would be: cBuddhistCow.Say("&64 Mooaclah was bored.....
  cBuddhistCow.SayBackground("Mooaclah was a bored creature, with many supernatural powers, and a life many years beyond our own; seriously, he had a better chance than someone who eats fruit and vegetables and does an hour of cardio a day. Like hundreds of times. He was old. One day, Mooaclah knew he couldn't control his kingdom on videogames and pizza alone, so he created many cow-shaped vessels to store his power...");

  //no time to pause here since SayBackground is non-blocking. But... Say is blocking. So....?

  SetTimer(TIMER_BUDDHIST_FADE_IN_OUT,GetGameSpeed()*1);
  BuddhistFadeInOut_1=false;
  BuddhistFadeInOut_2=true;

  aBUDD66.Play(eAudioPriorityNormal, eOnce);
  cBuddhistCow.SayBackground("...and they fought, spears and chains clashing against eachother until the god Arktus was finally vanquished; he changed quickly into a mountain sized pile of dirt, and we name him now ''Moorardna'', or, ''the third mountain''. After a time, it became the second age of Agnor, and pending a great flood (caused by the introduction of a new mountain), he built a large boat and fit all of the animals on board.");

  aBUDD67.Play(eAudioPriorityNormal, eOnce);
  cBuddhistCow.SayBackground("Horses, cows, ducks and crows; deer and peacock and dog; and some which no longer exist, such as the monkey...");

  SetTimer(TIMER_BUDDHIST_FADE_IN_OUT, GetGameSpeed()*5);
  BuddhistFadeInOut_2=false;
  BuddhistFadeInOut_3=true;
 
  aBUDD69.Play(eAudioPriorityNormal, eOnce);
cBuddhistCow.SayBackground("...and so Elargro said to the one true king, ''Escapod, bring my golden to--");
SetTimer(TIMER_BUDDHIST_FADE_IN_OUT,GetGameSpeed()*1);
  BuddhistFadeInOut_3=false;
  BuddhistFadeInOut_4=true;
 
  gTitleCard.Visible=false;    //turn off the black GUI; everything back to normal at this point
}

.......

function repeatedly_execute()
{
  //various non-blocking fade-in/out blocks according to which bool is true:

  while(IsTimerExpired(TIMER_BUDDHIST_FADE_IN_OUT)) {
    if (BuddhistFadeInOut_1) {
      BuddhistFadeInOut-=10;
      if (BuddhistFadeInOut<0) BuddhistFadeInOut=0;
      gTitleCard.Transparency=BuddhistFadeInOut;
      SetTimer(TIMER_BUDDHIST_FADE_IN_OUT, 15);
    }
    else if (BuddhistFadeInOut_2) {
      BuddhistFadeInOut+=10;
      if (BuddhistFadeInOut>100) BuddhistFadeInOut=100;
      gTitleCard.Transparency=BuddhistFadeInOut;
      SetTimer(TIMER_BUDDHIST_FADE_IN_OUT, 5);
    }
    else if (BuddhistFadeInOut_3) {
      BuddhistFadeInOut-=10;
      if (BuddhistFadeInOut<0) BuddhistFadeInOut=0;
      gTitleCard.Transparency=BuddhistFadeInOut;
      SetTimer(TIMER_BUDDHIST_FADE_IN_OUT, 15);
    }
    else if (BuddhistFadeInOut_4) {
      BuddhistFadeInOut+=10;
      if (BuddhistFadeInOut>100) BuddhistFadeInOut=100;
      gTitleCard.Transparency=BuddhistFadeInOut;
      SetTimer(TIMER_BUDDHIST_FADE_IN_OUT, 5);
    }
  }
}


Any help anyone can give would be great ;P
Title: Re: Using timers and aSound.Play() to do a non-blocking fade-in/fade-out
Post by: bx83 on Sun 24/03/2019 00:20:16
No one?....
Title: Re: Using timers and aSound.Play() to do a non-blocking fade-in/fade-out
Post by: eri0o on Sun 24/03/2019 04:16:53
I have done something using tween module and gui for custom transition and use timer module for timer, but I never used speech.
Title: Re: Using timers and aSound.Play() to do a non-blocking fade-in/fade-out
Post by: bx83 on Sun 24/03/2019 05:26:29
What about sound playing?
Title: Re: Using timers and aSound.Play() to do a non-blocking fade-in/fade-out
Post by: jahnocli on Sun 24/03/2019 09:16:21
In other software you could display a black rectangle covering the screen. You would start with maximum transparency, and gradually decrease the transparency until the rectangle is completely black. Would this work?
Title: Re: Using timers and aSound.Play() to do a non-blocking fade-in/fade-out
Post by: eri0o on Sun 24/03/2019 09:55:02
You can maybe check which channels has something playing and then use tween to also lower volumes.
Title: Re: Using timers and aSound.Play() to do a non-blocking fade-in/fade-out
Post by: bx83 on Sun 24/03/2019 09:57:16
jahnocli This is exactly what I did. The problem is SayBackground() doesn't work like I think it will
Title: Re: Using timers and aSound.Play() to do a non-blocking fade-in/fade-out
Post by: bx83 on Sun 24/03/2019 10:10:42
I mean how the hell do you put a blocking event after the SayBackgrond() so it doesn't just happen instantly? Yet to make it work, you must follow the SayBackground() command with something that blocks; it doesn't occur to me what this is.
Title: Re: Using timers and aSound.Play() to do a non-blocking fade-in/fade-out
Post by: morganw on Sun 24/03/2019 10:23:04
SayBackground returns a pointer to an Overlay, and the Overlay will become invalid when the speech ends.
https://www.adventuregamestudio.co.uk/manual/ags69.htm#Overlay.Valid (https://www.adventuregamestudio.co.uk/manual/ags69.htm#Overlay.Valid)
Title: Re: Using timers and aSound.Play() to do a non-blocking fade-in/fade-out
Post by: bx83 on Sun 24/03/2019 18:12:53
So if I loop checking Overlay after SayBackground, this will work, and it won't just instantly skip over SayBackground to move on to the next blocking event? How would I get a blocking event here, if not a loop?
Title: Re: Using timers and aSound.Play() to do a non-blocking fade-in/fade-out
Post by: Crimson Wizard on Sun 24/03/2019 18:24:01
Quote from: bx83 on Sun 24/03/2019 18:12:53
So if I loop checking Overlay after SayBackground, this will work, and it won't just instantly skip over SayBackground to move on to the next blocking event? How would I get a blocking event here, if not a loop?

Wait(1) in a loop blocks the script while updating the game and screen.

Code (ags) Select

Overlay *o = character.SayBackground(...);
while (o.Valid) Wait(1);


EDIT: But! I see in your posted code you have something in rep_exec. Wait() stops rep_exec too, so maybe this won't do. Need to read your code more...

EDIT2: Ok, not 100% certain, but maybe changing it to rep_exec_always will make it work.

EDIT3: Also, this line does not make sense to me:
Code (ags) Select

while(IsTimerExpired(TIMER_BUDDHIST_FADE_IN_OUT))

maybe it should be
Code (ags) Select

if (IsTimerExpired(TIMER_BUDDHIST_FADE_IN_OUT))

?
Title: Re: Using timers and aSound.Play() to do a non-blocking fade-in/fade-out
Post by: bx83 on Sun 24/03/2019 22:47:25
This is the variable that controls fading in and out in globalscript repexec. It's a timer with a #defined name.
Title: Re: Using timers and aSound.Play() to do a non-blocking fade-in/fade-out
Post by: Crimson Wizard on Sun 24/03/2019 22:59:57
Quote from: bx83 on Sun 24/03/2019 22:47:25
This is the variable that controls fading in and out in globalscript repexec. It's a timer with a #defined name.

Yes, I understand it's a #defined timer id, what I mean is there's no sense to have "while" there, because it won't repeat in this loop anyway. IsTimerExpired will only return true once per started timer, and next timers will run out later during next visits to rep_exec.

For example, let's assume it gets there when first timer has expired. It goes under "while", does some fading and starts one of the next timers. Then it will check IsTimerExpired again, but it will be false because the new timer has not even run a little yet. So it will quit rep_exec until the next game update. It will never actually loop inside there.
Title: Re: Using timers and aSound.Play() to do a non-blocking fade-in/fade-out
Post by: bx83 on Mon 25/03/2019 08:36:56
Understood, changed while to if.

while (o.Valid) Wait(1);
Still won't work because this is SayBackground(), but blocking. The game will get stuck here and not update timers, not alter the transparency of the black screen, etc.
Unless, once again I've missed something. Put the timer/screen blackening in the "while (o.Valid)" loop?
Title: Re: Using timers and aSound.Play() to do a non-blocking fade-in/fade-out
Post by: Crimson Wizard on Mon 25/03/2019 10:41:16
Quote from: bx83 on Mon 25/03/2019 08:36:56
while (o.Valid) Wait(1);
Still won't work because this is SayBackground(), but blocking. The game will get stuck here and not update timers, not alter the transparency of the black screen, etc.
Unless, once again I've missed something. Put the timer/screen blackening in the "while (o.Valid)" loop?

I feared this, seeing you have stuff in rep_exec. I would experiment changing rep_exec to rep_exec_always, but unfortunately I don't remember if timers update when there's a blocking command?

If they don't then you need to do this differently. Probably you should put everything under "if (timer expired)" in rep_exec: saybackground commands and so on (in which case you should remove Waits and rely on solely on timers).
I don't have a time to think this over better or test right now, will come back later (or maybe someone else can take a look).
Title: Re: Using timers and aSound.Play() to do a non-blocking fade-in/fade-out
Post by: Cassiebsg on Mon 25/03/2019 10:55:19
Alternatively, drop the built in timer and make your own, so that you can update it manually inside your while along side the wait command...

Code (ags) Select

while (timer<800) //or whatever value you need it to be
{
  wait(1);
  timer++;
}