[Mono-list] Bug in GetTickCount...
Maurizio Colucci
seguso.forever@tin.it
Thu, 22 May 2003 20:45:40 +0200
Hello,
After days debugging my game, I arrived at the conclusion that there
must be a terrible bug in System.Environment.GetTickCount().
I don't know where, but maybe this will help you find it.
When the frame rate of the game got above 60 FPS, the following Timer
class started misbehaving: the values returned by the Dt property were
wrong, and the game had a jerky motion.
With the Microsoft runtime, everything was smooth.
After switching to SDL::GetTicks(), everything is smooth under linux
also. Therefore the bug must be in mono.
The misbehaving code is:
using System;
using SDLDotNet;
using N_Logica_del_tennis;
namespace N_Timer{
public class Timer {
float dt_;
float[] delta_t_= new float[]{
1.0f/90000.0f,
1.0f/90000.0f,
1.0f/90000.0f
};
float previous_frame_time_;
float num_frames_since_last_fps_display_;
float time_of_latest_fps_calculation_;
float fps_;
readonly SDL sdl_; // per getticks
public float FPS {
get {
return fps_;
}
}
/// <summary>
/// Deve essere chiamata all'inizio di ogni fotogramma.
/// </summary>
public void Update() {
#region update the current dt based on the draw time of the latest frame
//int current_time=System.Environment.TickCount; // BUG!!
uint current_time=sdl_.GetTicks();
float delta_t_passed_since_last_frame_in_milliseconds =
(float) (current_time - previous_frame_time_);
/// so far it is in milliseconds. COnvert to
/// seconds by DIVIDING by 1000.
float delta_t_passed_since_last_frame_in_seconds=
delta_t_passed_since_last_frame_in_milliseconds/1000.0f;
#region insert this lapse of time into the array
for (int i=1; i< delta_t_.Length; i++)
delta_t_[i-1] = delta_t_[i];
/// nell'ultimo elemento metto il nuovo deltaT
delta_t_[delta_t_.Length-1] =
delta_t_passed_since_last_frame_in_seconds;
#endregion
#region calculate dt by averaging the values in the array
dt_=0;
foreach (float f in delta_t_)
dt_+= f;
dt_ /= (float) delta_t_.Length;
if(dt_>1.0f){
dt_=1.0f/90.0f;
Console.WriteLine("dt >1. I set dt equal to 1/90 seconds.");
}
#endregion
#endregion
previous_frame_time_ = current_time;
#region Calculate frame rate
num_frames_since_last_fps_display_ ++;
if (current_time-
time_of_latest_fps_calculation_
>=1000) {
/// if more than 1 second has passed...
time_of_latest_fps_calculation_
=current_time;
fps_=num_frames_since_last_fps_display_;
num_frames_since_last_fps_display_=0;
}
#endregion
}
public float Dt {
get {
return dt_;
}
}
public Timer(SDL sdl) {
Debug.Assert(sdl!=null, "sdl=null");
sdl_=sdl;
dt_=1.0f/900.0f;
previous_frame_time_= sdl_.GetTicks(); //System.Environment.TickCount; BUG!!
fps_ = 50;
num_frames_since_last_fps_display_ = 0;
time_of_latest_fps_calculation_ = sdl_.GetTicks(); //System.Environment.TickCount;
}
/// <summary>
/// If you pause the game, call this function just before resuming.
/// </summary>
public void ResetAfterLongPause() {
previous_frame_time_=sdl_.GetTicks(); //System.Environment.TickCount;
}
}
}