0

I am making a multiplayer game in c# windows form application with web service which is requires us to put a timer on the gameform, so that when the countdown timer becomes 0, it would be the opponent's turn. Now, this is my timer code.

private void StartTimer()
{
   timeLeft = 11;
   while (TimerRunning)
   {
    if (timeLeft > 0)
     {
       if (this.InvokeRequired)
           lb_Timer.Invoke((MethodInvoker)delegate ()
           {
               timeLeft = timeLeft - 1;
               if (timeLeft < 10)
                   lb_Timer.Text = "0: 0" + timeLeft;
               else
                   lb_Timer.Text = "0: " + timeLeft;
           });
       else
       {
           timeLeft = timeLeft - 1;
           if (timeLeft < 10)
               lb_Timer.Text = "0: 0" + timeLeft;
           else
               lb_Timer.Text = "0: " + timeLeft;
       }
     }
     else
     {
       if (this.InvokeRequired)
           lb_Timer.Invoke((MethodInvoker)delegate ()
           {
               TimerRunning = false;
               lb_Timer.Text = "0:00";
           });
       else
       {
           TimerRunning = false;
           lb_Timer.Text = "0:00";

       }
       break;
    }
      Thread.Sleep(2200);
   }
}

Notes:

  • the countdown timer span is 10 seconds, I gave the timeleft value 11 so that when the timer starts, it would start at exactly 10s.
  • The thread.sleep becomes the interval for my timer, because 1000 or 1s is too fast, that's why I decided to make it to 2.2s.
  • can you give me an advice on how to make the thread stop, when the user attacks, so that the timer would reset?
  • can you give me any idea or tips on how should I implement my timer using the webservice? thank you!
  • I guess the given 'StartTimer()' method is a worker thread callback method, am I right? But, if you put the thread to sleep for 2200ms multiplied by 10, this is 22s, not 10s. You should also put your copy-and-pasted code (for invocation) into methods, that can be invoked, that is not so error-prone. Have a look at the 'Task' class and 'CancellationToken' struct in the 'System.Threading.Tasks' namespace. – KBO Nov 21 '17 at 14:02
  • Thanks for the suggestion KBO! will look at those later, and also what do you mean by the copy-pasted code? The one that I used to call the method start timer? – Garry Stephenson Nov 21 '17 at 23:47

1 Answers1

0

Here is a simple example how a countdown can be implemented. Create a new WinForms project and add two buttons and two labels. A click on btn_Start starts the countdown, a click on btn_Cancel cancels it. So you can play around a little bit. In your game, after the countdown task has finished with the boolean result, you can fire an event, set a shared boolean variable, set an AutoResetEvent or ...

public partial class Form1 : Form
{
  CancellationTokenSource _cancelSource = null;

  public Form1()
  {
    InitializeComponent();
  }

  private async void btn_Start_Click(object sender, EventArgs e)
  {
    btn_Start.Enabled = false;
    lb_Result.Text    = "Countdown started...";

    if(_cancelSource == null)
      _cancelSource = new CancellationTokenSource();
    else if (_cancelSource.IsCancellationRequested)
    { 
      _cancelSource.Dispose();
      _cancelSource = new CancellationTokenSource();
    }

    bool countDownCancelled = await PerformCountdown(_cancelSource.Token);

    if(countDownCancelled)
      lb_Result.Text = "Countdown cancelled";
    else
      lb_Result.Text = "Countdown finished";

    btn_Start.Enabled = true;
  }

  private void btn_Cancel_Click(object sender, EventArgs e)
  {
    if (_cancelSource != null && !_cancelSource.IsCancellationRequested)
      _cancelSource.Cancel();
  }

  private void UpdateTimeLabel(int remainingSeconds)
  {
    lb_Timer.Text = string.Format("0: {0}s", remainingSeconds);
  }

  private async Task<bool> PerformCountdown(CancellationToken cancelToken)
  {
    bool cancelled = false;

    try
    {
      int timeLeft = 3;

      Invoke((MethodInvoker)delegate() { UpdateTimeLabel(timeLeft); });
      do
      {
        await Task.Delay(1000, cancelToken);

        if (cancelToken.IsCancellationRequested)
          break;

        timeLeft--;
        Invoke((MethodInvoker)delegate() { UpdateTimeLabel(timeLeft); });
      }
      while (timeLeft > 0);
    }
    catch (OperationCanceledException)
    {
      cancelled = true;
      Debug.WriteLine("PerformCountdown cancelled");
    }
    catch (Exception ex)
    {
      Debug.WriteLine("PerformCountdown unhandled exception: " + ex);
    }

    return cancelled;
  }
}
KBO
  • 653
  • 7
  • 17