Rotation and FPS regulation

Started by
4 comments, last by Mnisape 1 year, 4 months ago

So, I have these two functions:

void CircleOrbit(int x, int y, int x1, int y1, int rad, bool is_filled = false,  
				  int angle = 0, RGB3 color = GetCurrentColor(), 
				  RGB3 bkcolor = GetCurrentBkColor()) 
{
	float theta = (float)(angle * PI) / 180;
	int a1 = 0, b1 = 0;
	int dx = x1 - x, dy = y1 - y;
	a1 = x + (int)((dx)*cos(theta) - (dy)*sin(theta));
	b1 = y + (int)((dx)*sin(theta) + (dy)*cos(theta));
	RGB3 tc = GetCurrentColor();
	RGB3 tbkc = GetCurrentBkColor();
	SetColors(color, bkcolor);
	Circle(a1, b1, rad, is_filled, color);
	SetColors(tc, tbkc);
}

And:

void RotationTest() {
	for (int i = 0; i <= 360; i++) {
 		StartFpsTimer();
 		PrintTitleText();
 		// CircleOrbit(x1, y1, x2, y2, radius, filled, angle, color);
		CircleOrbit(Mid.x, Mid.y, Mid.x + 100, Mid.y, 10, true, i, clr::RED);
 		SwapPages();
 		Delay(1);  
 		CalculateFps();
 		if (UserInput()) break;
	}
}

I want to limit the speed of rotation by a velocity, which I know I need to add, and fps which I have calculated. Normally it is just the new x and y positions are += (vel / fps), but I can not seem to figure it out. My fps is figured as such: fps = (1000 / milliseconds) / 1000), which gives me 60-64 fps. This normally works fine for just moving objects. However, no matter what I do, it orbits at the same speed even if I remove the Delay(1) from the code. Any help would be appreciated. Thanks.

Advertisement

Mnisape said:
fps = (1000 / milliseconds) / 1000

I had to reduce this and got: fps = 1 / milliseconds

Which is wrong, it should be: fps = 1000 / milliseconds

So maybe, because you still get seemingly correct results of 60fps, your time unit is not milliseconds but seconds.
Which might cause some confusion, so just mentioning that.

About your actual question, there are some issues which make it hard for you:

You want to integrate time. So work with time (measured realtime), not with the reciprocal of it (fps). Fps is rarely useful in general.

Because you integrate time, which is a real number, use real numbers, not integers. It provides the necessary precision to do integration, and avoids the costly conversation from float to int as well.

That said, i do not exactly understand what you try to do, but i assume you want some rotation at constant speed, not matter what's the actual fps.
This could work for example like so:

int64_t prevTimestamp = GetTime(); // function might return nanoseconds since computer was turned on, or seconds since some day in the 70's, or something like that
float objectAngle = 0;
float angularVelocity = 5; // angles per second
while (true)
{
	int64_t curTimestamp = GetTime();
	float deltaTime = ConvertDifferenceToSeconds(curTimestamp - prevTimestamp); // calculate seconds since the last iteration of our loop
	prevTimestamp = curTimestamp;
	
	objectAngle += angularVelocity * deltaTime;
	DisplaySomeObjectAtAngle(objectAngle);
	SwapImagesAndAllThatRenderingCrap();
} 

With your approach you try something different:

while (true)
{
	objectAngle += some constant like one degree;
	Render();
	Try to make the system pause for a given constant time, like 16 millisenonds to get 60 fps
}

Your mistake likely is the short delay of 1 (milliseconds?). That's not enough.
And likely your render framerate is capped to 60 fps by enabling vsync anyway.
So it already waits for 16 milliseconds anyway, and likely this wait factors in your given delay of one millisecond, so there is no observable effect in the end.

Assuming you're making it work as expected anyway, your approach may break e.g. if user changes a setting affecting vsync.
Or, your game becomes too slow to hit 60fps in some sections. Again your assumption of a constant timestep per frame would break, causing the game to feel wrong and not synced to realtime.
That's why it's actually better to (additionally) care about this time synchronization no matter if vsync is on or off.
But my code is just a basic example.
Usually you want to have constant timesteps for your physics updates, which brings us to the things discussed in the famous ‘fix your timestep’ article.
Google for it. But unfortunately it needs walls of text for what should be actually explained with 10 sentences at most. Still worth to read.

Awesome, thanks so much for the help. I had not thought of that. I will read the article as well. Thanks so much.

And movement speed solved:

int CircleOrbit2(int x, int y, int x1, int y1, int rad, int vel = 1, 
bool is_filled = false, int angle = 0,
RGB3 color = GetCurrentColor(), 
RGB3 bkcolor = GetCurrentBkColor()) {
int i = 0;
int a1 = 0, b1 = 0;
RGB3 tc = GetCurrentColor();
RGB3 tbkc = GetCurrentBkColor();
SetColors(color, bkcolor);
float theta = (float)(angle * PI) / 180;
int dx = x1 - x, dy = y1 - y;
WhileXisLessThanY(i, vel) {
 a1 = x + (int)((dx)*cos(theta) - dy)*sin(theta));
 b1 = y + (int)((dx)*sin(theta) + (dy)*cos(theta));
}
Circle(a1, b1, rad, is_filled, color);
SetColors(tc, tbkc);
return i;
}

Woot woot.

Oops, LOL. And the call to the function is thus:

while(is_run() {
	int circ1ang = 1;
	for (int i = 0; i <= 360; i++) {
	StartFpsTimer();
	PrintTitleText();
	circ1ang += CircleOrbit2(Mid.x, Mid.y, Mid.x - 100, Mid.y, 30, 2, false, circ1ang, clr::RED);
	SwapPages();
	CalculateFps();
	if (UserInput()) break;
	}
}

This topic is closed to new replies.

Advertisement