Adventure Game Studio | Forums

AGS Support => Beginners' Technical Questions => Topic started by: kanth on Wed 08/06/2016 11:07:27

Title: Skip through custom typewriter effect
Post by: kanth on Wed 08/06/2016 11:07:27
Hey everyone!
First i want to thank you all for your help, i have been cruising the forum as a guest for weeks and resolved all my problems thanks to you guys.

Well until now, my limited scripting knowledge is showing.
I've got a typewriting script and it works great, but i want to be able to skip the typewriter effect and show the entire line being typed at once (on mouse click or key press):

Code (ags) Select

    Overlay *TypedText;
   
      void CommentNARRATOR(int delay, String text){
                                                         

     int x;
     int y;
     AudioClip *sound;
     sound = aNarrator_voice;
     String displayedLine = "";
     int i = 0;
 
  while (i < text.Length) {
   
     displayedLine = String.Format ("%s%c", displayedLine, text.Chars[i]);
     TypedText = Overlay.CreateTextual(85, 530, 555, eFontnarrator, 65535, displayedLine);
   
    if (text.Chars[i] == ' ')
       Wait(delay/2);
    else if (text.Chars[i] == '[')
       Wait(delay/2);
    else {
      if (sound)
        sound.Play ();
       Wait(delay);
       
     }

     i++;

  }
if (TypedText.Valid)
     WaitMouseKey(TYPEnarrator_MAXIMUM_DISPLAY_TIME * (delay * 4));
     TypedText.Remove();
     }



I tried multiple things, but nothing worked.

if (mouse.IsButtonDown(eMouseLeft))
i = text.Length;
is a start but only type the first letter?
Title: Re: Skip through custom typewriter effect
Post by: Snarky on Wed 08/06/2016 11:38:41
Instead of

Code (ags) Select
     displayedLine = String.Format ("%s%c", displayedLine, text.Chars[i]);

Try

Code (ags) Select
     displayedLine = text.Truncate(i);

(The problem is that you were building the displayedLine character by character, so by skipping all the intermediate steps it would miss out all of the corresponding characters. Here instead we just set displayedLine directly to the first i characters of the text.)

Also, don't set i to text.Length; set it to text.Length-1. Otherwise the body of the loop won't run.
Title: Re: Skip through custom typewriter effect
Post by: Danvzare on Wed 08/06/2016 11:47:28
I tested this out to see if it works, and it does.

Code (ags) Select

    Overlay *TypedText;
   
      void CommentNARRATOR(int delay, String text){
                                                         

     int x;
     int y;
     AudioClip *sound;
     sound = aNarrator_voice;
     String displayedLine = "";
     int i = 0;
  StartCutscene(3);
  while (i < text.Length) {
   
     displayedLine = String.Format ("%s%c", displayedLine, text.Chars[i]);
     TypedText = Overlay.CreateTextual(85, 530, 555, eFontnarrator, 65535, displayedLine);
   
    if (text.Chars[i] == ' ')
       Wait(delay/2);
    else if (text.Chars[i] == '[')
       Wait(delay/2);
    else {
      if (sound)
        sound.Play ();
       Wait(delay);
       
     }

     i++;

  }
EndCutscene();
if (TypedText.Valid)
     WaitMouseKey(TYPEnarrator_MAXIMUM_DISPLAY_TIME * (delay * 4));
     TypedText.Remove();
     }



Only two lines of code, and it's done.

By the way, those lines are StartCutscene(3) and EndCutscene().
(They're on lines 12 and 32.)
Title: Re: Skip through custom typewriter effect
Post by: kanth on Wed 08/06/2016 12:21:15
Hi Snarky!

Code (ags) Select

displayedLine = text.Truncate(i);


I loose my last letter!
(thanks for the text.Length-1 tip)


Hey Danvzare!

It works perfectly indeed, thank you! I didn't know it was "proper" to use StartCutscene/EndCutscene like that.
Title: Re: Skip through custom typewriter effect
Post by: Snarky on Wed 08/06/2016 12:56:41
Quote from: kanth on Wed 08/06/2016 12:21:15
Hi Snarky!

Code (ags) Select

displayedLine = text.Truncate(i);


I loose my last letter!
(thanks for the text.Length-1 tip)

Oh, right. Unlike the version you had, Truncate(i) doesn't include the i'th character, so to behave the same way you should change the loop to go from 1 to text.Length, instead of from 0 to text.Length-1. (And then set the value back to text.Length in the skip event.) Like this:

Code (ags) Select
  int i = 1;     // 1 instead of 0
  while (i <= text.Length) // Notice the equals sign
  {
    // ...
    i++;
  }


The StartCutscene()/EndCutscene() solution certainly works, but it's a bit inefficient internally. If you have background animations going on at the same time, they will jump ahead any time you skip, which you may or may not want.
Title: Re: Skip through custom typewriter effect
Post by: kanth on Wed 08/06/2016 14:11:17
Ooookay thanks i see now. Works the same!

I can skip, but i think it's messing with the waitmousekey, if i click when the line is done it's getting to the next line directly whithout the typing effect.

I've got:

Code (ags) Select


     i++;

      if (mouse.IsButtonDown(eMouseLeft)){
      i = text.Length;   
      } 
  }
      if (TypedText.Valid)
     WaitMouseKey(TYPEnarrator_MAXIMUM_DISPLAY_TIME * (delay * 4));
     // if i put a Wait() here it's solving the problem but not for the first line in the dialog (which is triggered by an option)
     TypedText.Remove();
      }


I think i'm missing a stupid detail as always :/
Title: Re: Skip through custom typewriter effect
Post by: Snarky on Wed 08/06/2016 16:15:10
If you're happy with the StartCutscene()/EndCutscene() solution, just go with that.

Otherwise, off the top of my head the best solution has to do with setting a flag when you skip to the end of the typewriting (e.g. typingInterrupted = true), and treat that case separately. Depending on how robust you want to make it (i.e. what happens if the user presses the mouse button and doesn't let go?) it could get a bit complicated, though.
Title: Re: Skip through custom typewriter effect
Post by: Khris on Wed 08/06/2016 16:55:30
Try this:

bool MyWait(int delay) {
  int i = 0;
  bool down;
  while (i < delay) {
    Wait(1);
    down = mouse.IsButtonDown(eMouseLeft);
    if (down) i = delay;
    i++;
  }
  return down;
}

Overlay *TypedText;

void CommentNARRATOR(String text, int delay) {
 
  int x;
  int y;
  AudioClip *sound;
  sound = aNarrator_voice;
  String displayedLine = "";
  int i = 0;
  bool skip = false;
 
  while (i < text.Length) {
   
    displayedLine = text.Truncate(i + 1);
    TypedText = Overlay.CreateTextual(85, 530, 555, eFontnarrator, 65535, displayedLine);
   
    if (text.Chars[i] == 32 || text.Chars[i] == 91) {
      skip = MyWait(delay / 2);
      if (skip) i = text.Length - 2;
    }
    else {
      if (sound != null && !skip)
        sound.Play();
      skip = MyWait(delay); 
      if (skip) i = text.Length - 2;
    }
    i++;
  }
  if (skip) {
    Game.StopAudio(eAudioTypeSound);
    while (mouse.IsButtonDown(eMouseLeft)) Wait(1);
  }
 
  if (TypedText.Valid && !skip)
    WaitMouseKey(TYPEnarrator_MAXIMUM_DISPLAY_TIME * (delay * 4));
  TypedText.Remove();
}
Title: Re: Skip through custom typewriter effect
Post by: kanth on Wed 08/06/2016 18:03:20
Hi Khris!

I get a "Error (line 15): Parameter type does not match prototype" :/

Title: Re: Skip through custom typewriter effect
Post by: Khris on Wed 08/06/2016 19:25:54
Sorry, I completely forgot; I switched around the order of the parameters because I wanted to make delay into an optional parameter.

Look at your GlobalScript.ash for the line that says
import void CommentNARRATOR(int delay, String text);
Change it to
import void CommentNARRATOR(String text, delay = 4);  // default value, delay is now optional

However, if you already have lots of function calls in your script, you might probably switch the order in the function definition instead, otherwise you have to change all those function calls.
Title: Re: Skip through custom typewriter effect
Post by: kanth on Thu 09/06/2016 10:47:53
Okay thanks a lot! Works like a charm :) i kept the int delay, i like being able to change the speed directly.

But i still get the same problem as with Snarky's script: when i click on a finished line, it skips to the next without typing.
If i put a wait() just after the waitmousekey it's good, but when i click on a dialog option for example the next first line skip the typing.
Title: Re: Skip through custom typewriter effect
Post by: Khris on Thu 09/06/2016 12:10:15
At the very start of the function, add this:
  while (mouse.IsButtonDown(eMouseLeft)) Wait(1);

As for stating the delay, the key word is "optional".
By using the import line like I suggested, you can state the delay or omit it, which will set it to 4.

  CommentNARRATOR("Standard delay");  // uses delay = 4
  CommentNARRATOR("Slow talking", 10);
Title: Re: Skip through custom typewriter effect
Post by: kanth on Thu 09/06/2016 15:54:31
Quote
As for stating the delay, the key word is "optional".
By using the import line like I suggested, you can state the delay or omit it, which will set it to 4.

Ok yes got it, even more handy.

And yes thank you that solved it!! I don't quite understand all of it for now but i'll make sure to study it :)
Thanks for the quick reply and taking time to explain, you guys are awesome.
Title: Re: Skip through custom typewriter effect
Post by: shaun9991 on Tue 16/11/2021 16:57:00
I'm sorry to dredge up this ancient post!

I'm using this CommentNARRATOR typewriter code for my next game, and was wondering how to go about rendering the typed text in a GUI label rather than as an overlay? This is because I have lighting/shadow GUI layers running in the game, and I'd like the text to be "above" this. The overlay is always drawn behind the GUI in the Z order, if that makes sense.

I've been fiddling around with no avail. Any help would be greatly appreciated :)

Many thanks,
Shaun

Code (ags) Select
     Overlay *TypedText;

void CommentNARRATOR(String text, int delay) {
 
   while (mouse.IsButtonDown(eMouseLeft)) Wait(1);

  int x;
  int y;
  AudioClip *sound;
  sound = null;
  String displayedLine = "";
  int i = 0;
  bool skip = false;

  while (i < text.Length) {
   
    displayedLine = text.Truncate(i + 1);
    TypedText = Overlay.CreateTextual(10, 140, 300, eFontMunro2, 65535, displayedLine);
   
    if (text.Chars[i] == 32 || text.Chars[i] == 91) {
      skip = MyWait(delay / 2);
      if (skip) i = text.Length - 2;
    }
    else {
      if (sound != null && !skip)
        sound.Play();
      skip = MyWait(delay);
      if (skip) i = text.Length - 2;
    }
    i++;
  }
  if (skip) {
    Game.StopAudio(eAudioTypeSound);
    while (mouse.IsButtonDown(eMouseLeft)) Wait(1);
  }

  if (TypedText.Valid && !skip)
    WaitMouseKey(delay*4);
   WaitMouseKey(4000 * (delay * 4));
   //WaitMouseKey(TYPEnarrator_MAXIMUM_DISPLAY_TIME * (delay * 4));
  TypedText.Remove();
}

Title: Re: Skip through custom typewriter effect
Post by: Crimson Wizard on Tue 16/11/2021 17:59:08
@shaun9991, it seems simple, just replace
Code (ags) Select

TypedText = Overlay.CreateTextual(10, 140, 300, eFontMunro2, 65535, displayedLine);

with
Code (ags) Select

myLabel.Text = displayedLine;


Of course you'd also have to make gui visible before typewriter effect starts, and replace "TypedText.Remove();" with "gMyGui.Visible = false;" or similar.
Title: Re: Skip through custom typewriter effect
Post by: shaun9991 on Wed 17/11/2021 08:43:07
That worked a charm, thank you so much CW! :)