I have managed to create a system that allows game objects to move according to the change in time (rather than the change in number of frames). I am now, for practise's sake, trying to impose a FPS limiter.
The problem I'm having is that double the amount of game loops are occurring than what I expect. For example, if I try to limit the number of frames to 1 FPS, 2 frames will pass in that one second - one very long frame (~1 second) and 1 extremely short frame (~15 milliseconds). This can be shown by outputting the difference in time (in milliseconds) between each game loop - an example output might be 993, 17, 993, 16...
I have tried changing the code such that delta time is calculated before the FPS is limited, but to no avail.
Timer class:
#include "Timer.h"
#include <SDL.h>
Timer::Timer(void)
{
_currentTicks = 0;
_previousTicks = 0;
_deltaTicks = 0;
_numberOfLoops = 0;
}
void Timer::LoopStart()
{
//Store the previous and current number of ticks and calculate the
//difference. If this is the first loop, then no time has passed (thus
//previous ticks == current ticks).
if (_numberOfLoops == 0)
_previousTicks = SDL_GetTicks();
else
_previousTicks = _currentTicks;
_currentTicks = SDL_GetTicks();
//Calculate the difference in time.
_deltaTicks = _currentTicks - _previousTicks;
//Increment the number of loops.
_numberOfLoops++;
}
void Timer::LimitFPS(int targetFps)
{
//If the framerate is too high, compute the amount of delay needed and
//delay.
if (_deltaTicks < (unsigned)(1000 / targetFps))
SDL_Delay((unsigned)(1000 / targetFps) - _deltaTicks);
}
(Part of the) game loop:
//The timer object.
Timer* _timer = new Timer();
//Start the game loop and continue.
while (true)
{
//Restart the timer.
_timer->LoopStart();
//Game logic omitted
//Limit the frames per second.
_timer->LimitFPS(1);
}
Note: I am calculating the FPS using a SMA; this code has been omitted.
The problem is part of how your timer structure is setup.
_deltaTicks = _currentTicks - _previousTicks;
I looked though the code a few times and based on how you have the timer setup this seems to be the problem line.
Walking though it at the start of your code _currentTicks will equal 0 and _previousTicks will equal 0 so for the first loop your _deltaTicks will be 0. This means regardless of your game logic LimitFPS will misbehave.
void Timer::LimitFPS(int targetFps)
{
if (_deltaTicks < (unsigned)(1000 / targetFps))
SDL_Delay((unsigned)(1000 / targetFps) - _deltaTicks);
}
We just calculated that _deltaTicks was 0 at the start of the loop, thus we wait the full 1000ms regardless of what happens in your game logic.
On the next frame we have this, _previousTicks will equal 0 and _currentTicks will now equal approximately 1000ms. This means the _deltaTicks will be equal to 1000.
Again we hit the LimitFPS function but this time with a _deltaTicks of 1000 which makes it so we wait for 0ms.
This behavior will constantly flip like this.
wait 1000ms
wait 0ms
wait 1000ms
wait 0ms
...
those wait 0ms essentially double your FPS.
You need to test for time at the start and end of your game logic.
//The timer object.
Timer* _timer = new Timer();
//Start the game loop and continue.
while (true)
{
//Restart the timer.
_timer->LoopStart();
//Game logic omitted
//Obtain the end time
_timer->LoopEnd();
//Now you can calculate the delta based on your start and end times.
_timer->CaculateDelta();
//Limit the frames per second.
_timer->LimitFPS(1);
}
Hope that helps.
Assuming your gameloop is triggered only when SDL_Delay() expired wouldn't it be enough to write:
void Timer::LimitFPS(int targetFps)
{
SDL_Delay((unsigned)(1000 / targetFps));
}
to delay your gameloop by the right amount of milliseconds depending on the requested target FPS?
Related
In a while loop I am calling an update function of an object:
void ParticleEmitter::update(float deltaTime) {
time += deltaTime;
if (time >= delay) {
addParticle();
time = 0;
}
}
time variable is set to 0 by default. It's basically elapsed time.
delay is 0.01. Meaning that after each 0.01 second, it should do whatever is in the if statement.
This seems frame rate-independent. But it is not. When I cap the FPS to 60 or turn on VSync, less particles seem to be added.
The delta time is being calculated properly, I have tested it. But I am confused to why this code isn't frame rate-independent.
As mentioned in the comments, you are probaly not factoring in the remaining time in deltaTime.
For example imagine that you have deltaTime = 0.05 or deltaTime = 0.1 as you are only checking that it is greater or equal then, it will only generate one particle each time that update is called. So if deltaTime is smaller (framerate higher) then update will be called more often than if deltaTime is bigger.
The solution is to apply a function like so which generates a number of particles based in the timeElapsed (extracted from my own particle generator)
void particleSystem::generateParticles(float timeStep)
{
float particlesToCreate = particlesPerSecond * timeStep;
unsigned int count = static_cast <unsigned int> (particlesToCreate);
for (unsigned int i = 0; i < count; i++)
{
emitParticle();
}
}
With particlesPerSecond being a configurable parameter in the particleSystem
Hope it helps.
It's not framerate-independent.
For simplicity, let's assume that deltaTime is fixed.
If it is 0.1, you will add one particle every 0.1 seconds, because 0.1 > 0.01.
If it is 0.01, you will add one particle every 0.01 seconds.
If it is 1/60 (60 FPS), you will add one particle every 1/60 (~0.01667) seconds, because 1/60 is larger than 0.01.
If it is 1/120, you will also add one particle every 1/60 seconds, because 1/120 is smaller than 0.01 and 2 * 1/120 is larger than 0.01.
If you want a fixed number of particles per time, you need to add several if the delta is large.
Something like
while (time >= delay)
{
addParticle();
time -= delay;
}
You also don't want to set time to 0, but save the "spill time" for the next update.
There is a drawback with this approach; adding more particles takes time so the next update may come later. This can cause a long ripple effect.
If that happens, you will need a more sophisticated approach.
I'm measuring execution time for several functions in an image processing program in C++. In particular, I want to have the actual execution time for capturing a frame with my USB camera.
The problem is that the results don't seem consistent with the camera parameters: the camera is supposed to be 30 fps at most, and I often get a measured time that is less than 33 ms for getting a frame, which is the value I think should be expected. For instance, I get a lot of 12 ms intervals and that really seems too little.
Here is the code:
#include <time.h>
#include <sys/time.h>
double get_wall_time(){
struct timeval time;
if (gettimeofday(&time,NULL)){
// Handle error
return 0;
}
return (double)time.tv_sec + (double)time.tv_usec * .000001;
}
int main(){
while (true) {
double previoustime = get_wall_time();
this->camera.readFrame();
double currenttime = get_wall_time();
std::cout << currenttime-previoustime << std::endl;
// Other stuff
// ...
// ...
usleep(3000);
}
}
As #Revolver_Ocelot remarked, you are measuring time spent from the end of get_wall_time to the end of another similar call. To fix your code, do this:
double currenttime = get_wall_time();
while (true) {
double previoustime = currenttime;
this->camera.readFrame();
...
currentime = get_wall_time();
}
Can you spot the difference? This code measures the interval between each pass, which is what you want to get frames per second.
The speed at which you can read your camera will not be the same as the rate at which it will complete a new frame. Your camera could be recording at 30 FPS and you could be reading it at 15 FPS or 90 FPS, thus subsampling or oversampling the frame stream.
The limit at which you can oversample is 1 / time that it takes to read in an image and store it.
That's what #Jacob Hull meant with blocking; if readFrame just reads the last frame, it's not blocking until a new frame and you will get the results like you do with your measurement.
I'm trying to define a time step for the physics simulation in a PhysX application, such that the physics will run at the same speed on all machines. I wish for the physics to update at 60FPS, so each update should have a delta time of 1/60th of a second.
My application must use GLUT. Currently, my loop is set up as follows.
Idle Function:
void GLUTGame::Idle()
{
newElapsedTime = glutGet(GLUT_ELAPSED_TIME);
deltaTime = newElapsedTime - lastElapsedTime;
lastElapsedTime = newElapsedTime;
glutPostRedisplay();
}
The frame rate does not really matter in this case - it's only the speed at which my physics update that actually matters.
My render function contains the following:
void GLUTGame::Render()
{
// Rendering Code
simTimer += deltaTime;
if (simTimer > m_fps)
{
m_scene->UpdatePhys(m_fps);
simTimer = 0;
}
}
Where:
Fl32 m_fps = 1.f/60.f
However, this results in some very slow updates, due to the fact that deltaTime appears to equal 0 on most loops (which shouldn't actually be possible...) I've tried moving my deltaTime calculations to the bottom of my rendering function, as I thought that maybe the idle callback was called too often, but this did not solve the issue. Any ideas what I'm doing wrong here?
From the OpenGL website, we find that glutGet(GLUT_ELAPSED_TIME) returns the number of passed milliseconds as an int. So, if you call your void GLUTGame::Idle() method about 2000 times per second, then the time passed after one such call is about 1000 * 1/2000 = 0.5 ms. Thus more than 2000 calls per second to void GLUTGame::Idle() results in glutGet(GLUT_ELAPSED_TIME) returning 0 due to integer rounding.
Likely you're adding very small numbers to larger ones and you get rounding errors.
Try this:
void GLUTGame::Idle()
{
newElapsedTime = glutGet(GLUT_ELAPSED_TIME);
timeDelta = newElapsedTime - lastElapsedTime;
if (timeDelta < m_fps) return;
lastElapsedTime = newElapsedTime;
glutPostRedisplay();
}
You can do something similar in the other method if you want to.
I don't now anything about GLUT or PhysX, but here's how to have something execute at the same rate (using integers) no matter how fast the game runs:
if (currentTime - lastUpdateTime > msPerUpdate)
{
DWORD msPassed = currentTime - lastUpdateTime;
int updatesPassed = msPassed / msPerUpdate;
for (int i=0; i<updatesPassed; i++)
UpdatePhysX(); //or whatever function you use
lastUpdateTime = currentTime - msPassed + (updatesPassed * msPerUpdate);
}
Where currentTime is updated to timeGetTime every run through the game loop, lastUpdateTime is the last time PhysX updated, and msPerUpdate is the amount of milliseconds you assign to each update - 16 or 17 ms for 60fps
If you want to support floating-point update factors (which is recommended for a physics application), then define float timeMultiplier and update it every frame like so: timeMultiplier = (float)frameRate / desiredFrameRate; - where frameRate is self-explanatory and desiredFramerate is 60.0f if you want the physics updating at 60 fps. To do this, you have to update UpdatePhysX as taking a float parameter that it multiplies all update factors by.
I want a bullet to move when I click Space. First the bullet image is blitted when space is pressed, at the same time a timer starts and when it reaches 5000 ms ticks the x-value of the image should change. This is my code:
SDL_Rect bulletRect;
bulletRect.x = dstX+31; //dstX/Y is the source destination of another image where the bullet should be drawn
bulletRect.y = dstY+10.5;
SDL_Surface *bullet = IMG_Load(bullet.png");
if (drawBullet) //bool set to true in the space key event.
{
SDL_BlitSurface(bullet, NULL, screen, &bulletRect);
//timer
my_timer.start(); //starts the timer
if (SDL_GetTicks() == 5000) //if 5 sec
{
bulletRect.x += 10;
}
}
The image is only blitted but nothing happens after 5 sec. What is wrong?
Your conditional statement
if (SDL_GetTicks() == 5000) //if 5 sec
{
bulletRect.x += 10;
}
is inside the statement
if (drawBullet) //bool set to true in the space key event
which means you only check the timer once when the spacebar is pressed. Move this outside the if(drawBullet)
You should have SDL_GetTicks() >= 5000, instead of checking for ==5000, otherwise you'll only enter the condition if you happen to hit 5000 by pure luck.
from SDL's documentation, SDL_GetTicks function: Returns the number of milliseconds since SDL library initialization. This value wraps around if the program runs for more than 49.7 days
so if you're checking that it's been 5 seconds since it moved last (not sure what else you could be trying to do here) you want to store the current number of ticks and use that to compare against during the next loop (check that the difference between previous and current is > 5000)
I am attempting to insert a delay in Processing sketch. I tried Thread.sleep() but I guess it will not work because, as in Java, it prevents rendering of the drawings.
Basically, I have to draw a triangle with delays in drawing three sides.
How do I do that?
Processing programs can read the value of computer’s clock. The current second is read with the second() function, which returns values from 0 to 59. The current minute is read with the minute() function, which also returns values from 0 to 59. - Processing: A Programming Handbook
Other clock related functions : millis(), day(), month(), year().
Those numbers can be used to trigger events and calculate the passage of time, as in the following Processing sketch quoted from the aforementioned book:
// Uses millis() to start a line in motion three seconds
// after the program starts
int x = 0;
void setup() {
size(100, 100);
}
void draw() {
if (millis() > 3000) {
x++;
line(x, 0, x, 100);
}
}
Here's an example of a triangle whose sides are drawn each one after 3 seconds (the triangle is reset every minute):
int i = second();
void draw () {
background(255);
beginShape();
if (second()-i>=3) {
vertex(50,0);
vertex(99,99);
}
if (second()-i>=6) vertex(0,99);
if (second()-i>=9) vertex(50,0);
endShape();
}
As #user2468700 suggests, use a time keeping function. I like millis().
If you have a value to keep track of the time at certain intervals and the current time (continuously updated) you can check if one timer(manually updated one) falls behind the other(continuous one) based on a delay/wait value. If it does, update your data (number of points to draw in this case) and finally the local stop-watch like value.
Here's a basic commented example.
Rendering is separated from data updates to make it easier to understand.
//render related
PVector[] points = new PVector[]{new PVector(10,10),//a list of points
new PVector(90,10),
new PVector(90,90)};
int pointsToDraw = 0;//the number of points to draw on the screen
//time keeping related
int now;//keeps track of time only when we update, not continuously
int wait = 1000;//a delay value to check against
void setup(){
now = millis();//update the 'stop-watch'
}
void draw(){
//update
if(millis()-now >= wait){//if the difference between the last 'stop-watch' update and the current time in millis is greater than the wait time
if(pointsToDraw < points.length) pointsToDraw++;//if there are points to render, increment that
now = millis();//update the 'stop-watch'
}
//render
background(255);
beginShape();
for(int i = 0 ; i < pointsToDraw; i++) {
vertex(points[i].x,points[i].y);
}
endShape(CLOSE);
}