C# Timer tick inaccurate with progressbar

Collapse
X
 
  • Time
  • Show
Clear All
new posts
  • appelsinagurk
    New Member
    • Mar 2008
    • 6

    C# Timer tick inaccurate with progressbar

    Hi

    I'm fairly new to .Net programming so I'll try to explain my problem as easy as I can, and in advanced sorry for my poor english.

    I've got some spare hours where I work, so I've decided to spend them learning C# .Net.
    I've done some smaller programming assignments and decided now to try a larger program.

    I'm trying to create a basic game where you the "hero" meets "villains" and monsters in an arena. I want the fighting to be like final fantasy (for those of you who have played it), after each attack you have to wait some seconds before you can attack again(depending on the speed of your weapon).
    Here is where my problem lies, I can't get the timer to be accurate. I'll try to explain.

    -I got this windows form: Arena, which loads in the player and monster when certain buttons are pressed.

    - When all is set, you press the "Fight" button.
    Code:
    private void FightBtn_Click(object sender, EventArgs e)
    {
                Thread playerAttack = new Thread(new ThreadStart(startPlayer));
                Thread monsterAttack = new Thread(new ThreadStart(startMonster));
                playerAttack.Start();
                monsterAttack.Start();
    }
    I want the player and monster to run in threads, so they run independent of each other.

    -The monster thread is not importent right now, so I'll just follow the player thread.
    Code:
    public delegate void new_startPlayer_delegate();
    
    private void startPlayer()
    {
        Invoke(new new_startPlayer_delegate(new_startPlayer));
    }
    
    public void new_startPlayer()
    {
       playerAttackPnl.Visible = true;            
       PlayerTimer.Tick += new EventHandler(PlayerTimer_Tick);
    }
    I'll explain the PlayerTimer.Tic k later.
    playerAttackPnl is a panel which contains a button called playerattackBtn .
    Code:
    private void playerattackBtn_Click(object sender, EventArgs e)
    {
    playerattackBtn.Visible = false;
    PlayerTimer.Interval = 100;
    playerProgressbar.Maximum = 50;
    startTime = DateTime.Now;
    PlayerTimer.Enabled = true;
    PlayerTimer.Start()
    }
    I have a Windows.Form.Ti mer called PlayerTimer and a progressbar called playerProgressb ar.
    So I set the timer interval to 100 and progressbar maximum to 50.
    startTime is a datetime and I use it to measure the time.
    I also set the button visible to false, so you cant press it again.

    -Then we have the PlayerTimer_Tic k method.
    Code:
    private void PlayerTimer_Tick(object sender, EventArgs e)
    {
                playerProgressbar.Increment(1);
                if (playerProgressbar.Value >= playerProgressbar.Maximum)
                {
                    PlayerTimer.Stop();
                    PlayerTimer.Enabled = false;
                    playerProgressbar.Value = 0;
                    playerattackBtn.Visible = true;
                    stopTime = DateTime.Now;
                    TimeSpan time = stopTime.Subtract(startTime);
                    MessageBox.Show(Convert.ToString(time));
                }
    }
    So each time the tick fires, I increase the progressbar value with 1 and check if it has reached maximum. If it has, I stop the timer, disable it, set progressbarvalu e to 0, show the attack button again and calculate the time this has taken.

    The reason I added this "PlayerTimer.Ti ck += new EventHandler(Pl ayerTimer_Tick) ;" in the "public void new_startPlayer ()" method is because I experienced if I had it in the button click method, the runtime got faster and faster and faster for each run. This I don't know why, maybe some of you know?

    But anyhow, now we have a timer with interval 100, and a progress bar who counts to 50, correct me if I'm wrong, but shoulnt this take 5 second?
    When I run this, it takes: 2,73455 sec.

    If I change the interval to 1000 and max to 10 it takes 5 sec.
    Interval 50 and max 100 = 3,1252 sec.

    Where am I doing wrong?
    I've also tried with System.Timers.T imer, and still not accurate.

    Ask if something is unclear.

    Thanks in advanced :)

    Marius
  • shweta123
    Recognized Expert Contributor
    • Nov 2006
    • 692

    #2
    Hi,

    Before the progressbar you should first set the following properties of the progressbar :

    1) progressBar1.Ma ximum
    2) progressBar1.Mi nimum
    3) progressBar1.St ep
    4) progressBar1.Va lue

    Now in your code , you should set the above properties to the following values:

    private void playerattackBtn _Click(object sender, EventArgs e)
    {
    playerattackBtn .Visible = false;
    PlayerTimer.Int erval = 100;
    playerProgressb ar.Maximum = 50;
    playerProgressb ar.Minimum= 0;
    playerProgressb ar.Value= 0;

    startTime = DateTime.Now;
    PlayerTimer.Ena bled = true;
    PlayerTimer.Sta rt()
    }

    To increment the value of the progressbar you can use one of the following methods :
    1) Use increment() method.
    e.g. progressbar1.in crement(1);
    2) Increment the value of progressbar using its Value property.
    e.g. progressBar1.Va lue += 1;

    So , in your code you may try it like this :

    private void PlayerTimer_Tic k(object sender, EventArgs e)
    {
    playerProgressb ar.value +=1;
    ............... ..
    }





    Originally posted by appelsinagurk
    Hi

    I'm fairly new to .Net programming so I'll try to explain my problem as easy as I can, and in advanced sorry for my poor english.

    I've got some spare hours where I work, so I've decided to spend them learning C# .Net.
    I've done some smaller programming assignments and decided now to try a larger program.

    I'm trying to create a basic game where you the "hero" meets "villains" and monsters in an arena. I want the fighting to be like final fantasy (for those of you who have played it), after each attack you have to wait some seconds before you can attack again(depending on the speed of your weapon).
    Here is where my problem lies, I can't get the timer to be accurate. I'll try to explain.

    -I got this windows form: Arena, which loads in the player and monster when certain buttons are pressed.

    - When all is set, you press the "Fight" button.
    Code:
    private void FightBtn_Click(object sender, EventArgs e)
    {
                Thread playerAttack = new Thread(new ThreadStart(startPlayer));
                Thread monsterAttack = new Thread(new ThreadStart(startMonster));
                playerAttack.Start();
                monsterAttack.Start();
    }
    I want the player and monster to run in threads, so they run independent of each other.

    -The monster thread is not importent right now, so I'll just follow the player thread.
    Code:
    public delegate void new_startPlayer_delegate();
    
    private void startPlayer()
    {
        Invoke(new new_startPlayer_delegate(new_startPlayer));
    }
    
    public void new_startPlayer()
    {
       playerAttackPnl.Visible = true;            
       PlayerTimer.Tick += new EventHandler(PlayerTimer_Tick);
    }
    I'll explain the PlayerTimer.Tic k later.
    playerAttackPnl is a panel which contains a button called playerattackBtn .
    Code:
    private void playerattackBtn_Click(object sender, EventArgs e)
    {
    playerattackBtn.Visible = false;
    PlayerTimer.Interval = 100;
    playerProgressbar.Maximum = 50;
    startTime = DateTime.Now;
    PlayerTimer.Enabled = true;
    PlayerTimer.Start()
    }
    I have a Windows.Form.Ti mer called PlayerTimer and a progressbar called playerProgressb ar.
    So I set the timer interval to 100 and progressbar maximum to 50.
    startTime is a datetime and I use it to measure the time.
    I also set the button visible to false, so you cant press it again.

    -Then we have the PlayerTimer_Tic k method.
    Code:
    private void PlayerTimer_Tick(object sender, EventArgs e)
    {
                playerProgressbar.Increment(1);
                if (playerProgressbar.Value >= playerProgressbar.Maximum)
                {
                    PlayerTimer.Stop();
                    PlayerTimer.Enabled = false;
                    playerProgressbar.Value = 0;
                    playerattackBtn.Visible = true;
                    stopTime = DateTime.Now;
                    TimeSpan time = stopTime.Subtract(startTime);
                    MessageBox.Show(Convert.ToString(time));
                }
    }
    So each time the tick fires, I increase the progressbar value with 1 and check if it has reached maximum. If it has, I stop the timer, disable it, set progressbarvalu e to 0, show the attack button again and calculate the time this has taken.

    The reason I added this "PlayerTimer.Ti ck += new EventHandler(Pl ayerTimer_Tick) ;" in the "public void new_startPlayer ()" method is because I experienced if I had it in the button click method, the runtime got faster and faster and faster for each run. This I don't know why, maybe some of you know?

    But anyhow, now we have a timer with interval 100, and a progress bar who counts to 50, correct me if I'm wrong, but shoulnt this take 5 second?
    When I run this, it takes: 2,73455 sec.

    If I change the interval to 1000 and max to 10 it takes 5 sec.
    Interval 50 and max 100 = 3,1252 sec.

    Where am I doing wrong?
    I've also tried with System.Timers.T imer, and still not accurate.

    Ask if something is unclear.

    Thanks in advanced :)

    Marius

    Comment

    • appelsinagurk
      New Member
      • Mar 2008
      • 6

      #3
      Hi

      Thanks for quick response.

      I've done what you said, but it still doesnt work.


      I've tried both: playerProgressb ar.increment(1) ; and
      playerProgressb ar.Value += 1;
      playerProgressb ar.step is 1.

      But still returns the same value: 2, 7343 sec when interval is 100 and maximum is 50.

      Regards
      Marius

      Originally posted by shweta123
      Hi,

      Before the progressbar you should first set the following properties of the progressbar :

      1) progressBar1.Ma ximum
      2) progressBar1.Mi nimum
      3) progressBar1.St ep
      4) progressBar1.Va lue

      Now in your code , you should set the above properties to the following values:

      private void playerattackBtn _Click(object sender, EventArgs e)
      {
      playerattackBtn .Visible = false;
      PlayerTimer.Int erval = 100;
      playerProgressb ar.Maximum = 50;
      playerProgressb ar.Minimum= 0;
      playerProgressb ar.Value= 0;

      startTime = DateTime.Now;
      PlayerTimer.Ena bled = true;
      PlayerTimer.Sta rt()
      }

      To increment the value of the progressbar you can use one of the following methods :
      1) Use increment() method.
      e.g. progressbar1.in crement(1);
      2) Increment the value of progressbar using its Value property.
      e.g. progressBar1.Va lue += 1;

      So , in your code you may try it like this :

      private void PlayerTimer_Tic k(object sender, EventArgs e)
      {
      playerProgressb ar.value +=1;
      ............... ..
      }

      Comment

      • shweta123
        Recognized Expert Contributor
        • Nov 2006
        • 692

        #4
        Hi,

        I think the difference in the no of seconds is coming because
        you are calculating startTime in the procedure playerattackBtn _Click(). Instead of this if you calculate startTime in PlayerTimer_Tic k() procedure you might get the correct result.

        e.g.

        private void PlayerTimer_Tic k(object sender, EventArgs e)
        {
        if(startTime == "")
        {
        //set the startTime value here when timer starts
        startTime = DateTime.Now;
        }
        playerProgressb ar.Increment(1) ;
        if (playerProgress bar.Value >= playerProgressb ar.Maximum)
        {
        PlayerTimer.Sto p();
        PlayerTimer.Ena bled = false;
        playerProgressb ar.Value = 0;
        playerattackBtn .Visible = true;
        stopTime = DateTime.Now;
        TimeSpan time = stopTime.Subtra ct(startTime);
        MessageBox.Show (Convert.ToStri ng(time));
        }
        }




        Originally posted by appelsinagurk
        Hi

        Thanks for quick response.

        I've done what you said, but it still doesnt work.


        I've tried both: playerProgressb ar.increment(1) ; and
        playerProgressb ar.Value += 1;
        playerProgressb ar.step is 1.

        But still returns the same value: 2, 7343 sec when interval is 100 and maximum is 50.

        Regards
        Marius

        Comment

        • appelsinagurk
          New Member
          • Mar 2008
          • 6

          #5
          Nope, still didnt work, got the same value: 2,73.
          Correct me if I'm wrong but when you have interval = 100 and maximum = 50, you go one step each tick, shouldnt the time running this be 5 sec?
          Then 2,73 is pretty far off. Cant be a minor code delay, I must have typed something wrong somewhere.
          The problem is to find out where.

          Regards
          Marius

          Originally posted by shweta123
          Hi,

          I think the difference in the no of seconds is coming because
          you are calculating startTime in the procedure playerattackBtn _Click(). Instead of this if you calculate startTime in PlayerTimer_Tic k() procedure you might get the correct result.

          e.g.

          private void PlayerTimer_Tic k(object sender, EventArgs e)
          {
          if(startTime == "")
          {
          //set the startTime value here when timer starts
          startTime = DateTime.Now;
          }
          playerProgressb ar.Increment(1) ;
          if (playerProgress bar.Value >= playerProgressb ar.Maximum)
          {
          PlayerTimer.Sto p();
          PlayerTimer.Ena bled = false;
          playerProgressb ar.Value = 0;
          playerattackBtn .Visible = true;
          stopTime = DateTime.Now;
          TimeSpan time = stopTime.Subtra ct(startTime);
          MessageBox.Show (Convert.ToStri ng(time));
          }
          }

          Comment

          • Plater
            Recognized Expert Expert
            • Apr 2007
            • 7872

            #6
            Everytime you add an event handler, it will do just that ADD ANOTHER event handler, so the first run with get a single eventhandler, the 2nd run will get two and so on and so.
            Meaning the speed is cut in half each time.
            An interval of 100 is 1/10 of a second, so you should be getting a 5second total wait time.

            Only add the event handler ONCE and don't do it again, unless you remove it (which i think is almost identical commands except instead of += you say -=)

            Comment

            • appelsinagurk
              New Member
              • Mar 2008
              • 6

              #7
              Thanks alot :)

              The event got created in the background when the form loaded, so I just had to remove the event in my code.
              The time is still of by 0,4 but I'm sure it just has something to do with where I start and stop my timecount.

              Regards
              Marius

              Originally posted by Plater
              Everytime you add an event handler, it will do just that ADD ANOTHER event handler, so the first run with get a single eventhandler, the 2nd run will get two and so on and so.
              Meaning the speed is cut in half each time.
              An interval of 100 is 1/10 of a second, so you should be getting a 5second total wait time.

              Only add the event handler ONCE and don't do it again, unless you remove it (which i think is almost identical commands except instead of += you say -=)

              Comment

              • shweta123
                Recognized Expert Contributor
                • Nov 2006
                • 692

                #8
                Hi,

                I have two suggestions :

                1) You can try DateDiff function for calculating the difference in time.
                e.g. DateDiff("s", startTime, stopTime) .

                2) Also , in your code you are checking for progressbar value >= progressbar.max imum. Instead of this you can compare it using progressbar value = progressbar.max imum

                Originally posted by appelsinagurk
                Nope, still didnt work, got the same value: 2,73.
                Correct me if I'm wrong but when you have interval = 100 and maximum = 50, you go one step each tick, shouldnt the time running this be 5 sec?
                Then 2,73 is pretty far off. Cant be a minor code delay, I must have typed something wrong somewhere.
                The problem is to find out where.

                Regards
                Marius

                Comment

                • appelsinagurk
                  New Member
                  • Mar 2008
                  • 6

                  #9
                  I think I've figured out why the time is so off.

                  When I use long intervals and small progressbar.max I get an accurate time.
                  e.g. interval = 1000 and max = 5 equals 5,000067 sec
                  but when I use interval 100 and max = 50 I get 5,75

                  So the more steps you have, the more the "left over" time 000067 gets accumulated into a bigger off time.

                  Which brings me to my next question, If I use longer intervals and smaller max values, the progressbar jumps 1/3 for each tick, this does not look very nice. Is there a way to get it to go smooth?
                  I've tried using the style=continuou s on the progressbar properties with no luck.

                  Regards
                  Marius

                  Originally posted by shweta123
                  Hi,

                  I have two suggestions :

                  1) You can try DateDiff function for calculating the difference in time.
                  e.g. DateDiff("s", startTime, stopTime) .

                  2) Also , in your code you are checking for progressbar value >= progressbar.max imum. Instead of this you can compare it using progressbar value = progressbar.max imum

                  Comment

                  • appelsinagurk
                    New Member
                    • Mar 2008
                    • 6

                    #10
                    I was wrong, I found out that the program ran an extra tick.

                    So interval 1000 and max 5 became 6 sec

                    So thats why the time is so off when using large max values, another tick is fired after the code is supposed to be finished.


                    Originally posted by appelsinagurk
                    I think I've figured out why the time is so off.

                    When I use long intervals and small progressbar.max I get an accurate time.
                    e.g. interval = 1000 and max = 5 equals 5,000067 sec
                    but when I use interval 100 and max = 50 I get 5,75

                    So the more steps you have, the more the "left over" time 000067 gets accumulated into a bigger off time.

                    Which brings me to my next question, If I use longer intervals and smaller max values, the progressbar jumps 1/3 for each tick, this does not look very nice. Is there a way to get it to go smooth?
                    I've tried using the style=continuou s on the progressbar properties with no luck.

                    Regards
                    Marius

                    Comment

                    Working...