Empresas
Empregos
  • Sobre nós
  • Soluções
    • Publicação de vagas
      Publique sua vaga e receba candidatos qualificados em 48h.
    • Avaliações de candidatos
      Mais de 500 testes técnicos e psicológicos, mais anti-fraude.
    • Headhunting
      Busca executiva personalizada do início ao fim.
    • Folha de Pagamento + EOR
      Dispersão de folha e EOR em mais de 15 países da LATAM.
  • Preços
  • Empregos

0

226
Visualizações
C# Manually stopping an asynchronous for-statement (typewriter effect)

I'm making a retro-style game with C# .NET-Framework, and for dialogue I'm using a for-statement, that prints my text letter by letter (like a typewriter-effect):

enter image description here

I'm working with different scenes, and I have a skip button (bottom right) that skips the current dialogue and passes to the next scene. My typewriter-effect automatically stops when all the text is displayed, but when I click on the skip button, it automatically skips to the next scene.

I would like it, when the typewriter is still active, and if I click on the skip button, that it first shows all the text, instead of skipping to the next scene.

So that it only skips to the next scene when all the text is displayed (automatically or manually).

This is the (working code) that I'm using for my typewriter method (+ variables):

    public string FullTextBottom;
    public string CurrentTextBottom = "";
    public bool IsActive;
    
    public async void TypeWriterEffectBottom()
    {
        if(this.BackgroundImage != null) // only runs on backgrounds that arent black
        {
            for(i=0; i < FullTextBottom.Length + 1; i++)
            {
                CurrentTextBottom = FullTextBottom.Substring(0, i); // updating current string with one extra letter
                LblTextBottom.Text = CurrentTextBottom; // "temporarily place string in text box"
                await Task.Delay(30); // wait for next update
                
                #region checks for IsActive // for debugging only!

                if(i < FullTextBottom.Length + 1)
                {
                    IsActive = true;
                    Debug1.Text = "IsActive = " + IsActive.ToString();
                }
                if(CurrentTextBottom.Length == FullTextBottom.Length)
                {
                    IsActive = false;
                    Debug1.Text = "IsActive = " + IsActive.ToString();
                }

                #endregion
            }
        }

    }

And this is the code that I want to get for my skip button (named Pb_FastForward):

    private void PbFastForward_Click(object sender, EventArgs e)
    {
        if( //typewriter is active)
        {
             //print all text into the textbox
        }
        
        else if( //all text is printed)
        {
             // skip to the next scene
        }
    }   

But I don't know how to formulate the 2nd part of code. I've tried many different approaches, like using counters that increase on a buttonclick (and using that to check in an if-statement), and many different types of if-statements to see if the typewriter is still active or not, but I haven't got anything to work yet.

Edit

This is the sequence in which different components need to be loaded (on button click), which is related to the way different variables are updated:

  1. Gamestate_Cycle() --> called for loading new scene.
  2. FullTextBottom = LblTextBottom.Text --> called to refresh variables for typewriter.
  3. TypeWriterEffectBottom() --> called to perform typewriter effect.
over 4 years ago · Santiago Trujillo
2 Respostas
Responde à pergunta

0

Avoid async void. Otherwise you can get an Exception that will break your game and you will not able to catch it.

Then use as less global variables in async methods as possible.

I suggest CancellationTokenSource as thread-safe way to stop the Type Writer.

public async Task TypeWriterEffectBottom(string text, CancellationToken token)
{
    if (this.BackgroundImage != null)
    {
        Debug1.Text = "TypeWriter is active";
        StringBuilder sb = new StringBuilder(text.Length);
        try
        {
            foreach (char c in text)
            {
                LblTextBottom.Text = sb.Append(c).ToString();
                await Task.Delay(30, token);
            }
        }
        catch (OperationCanceledException)
        {
            LblTextBottom.Text = text;
        }
        Debug1.Text = "TypeWriter is finished";
    }
}

Define CTS. It's thread-safe, so it's ok to have it in global scope.

private CancellationTokenSource cts = null;

Call TypeWriter from async method to be able to await it.

// set button layout as "Skip text" here
using (cts = new CancellationTokenSource())
{
    await TypeWriterEffectBottom(yourString, cts.Token);
}
cts = null;
// set button layout as "Go to the next scene" here

And finally

private void PbFastForward_Click(object sender, EventArgs e)
{
    if (cts != null)
    {
        cts?.Cancel();
    }
    else
    {
        // go to the next scene
    }
}   
over 4 years ago · Santiago Trujillo Relatório

0

I adjusted your code a little bit to achieve your goal. I'm not sure it's the best way to do it, but it should work.

public async void TypeWriterEffectBottom()
{
    if(this.BackgroundImage == null)
    {
        return;
    }
    IsActive = true;
    for(i=0; i < FullTextBottom.Length && IsActive; i++)
    {
        CurrentTextBottom = FullTextBottom.Substring(0, i+1);
        LblTextBottom.Text = CurrentTextBottom;
        await Task.Delay(30);
        Debug1.Text = "IsActive = " + IsActive.ToString();
    }
    IsActive = false;
}

private void PbFastForward_Click(object sender, EventArgs e)
{
    if(IsActive)
    {
        LblTextBottom.Text = FullTextBottom;
        IsActive = false;
        return;
    }
    
    // IsActive == false means all text is printed
    // skip to the next scene
}

UPD: Just noticed that Hans Kesting has suggested pretty much exactly this in his comment.

over 4 years ago · Santiago Trujillo Relatório
Responde à pergunta
Encontrar trabalhos remotos

Descubra a nova forma de encontrar um emprego!

melhores empregos
Principais categorias de trabalho
Empresas
Postar vaga Preços Comercial
Jurídico
Termos e Condições Política de privacidade
© 2026 PeakU Inc. All Rights Reserved.
Andres GPT
Recomende algumas ofertas para mim
Preciso de ajuda