Stuttery movement


#1

I’m making a little game with cinder. So far I’ve got everything working just fine, but when I build and run the thing, animation is stuttery.
I expect this has something to do with keyboard input: animation is fairly smooth, but when I hold a key things seem to start stuttering.
I found this: https://forum.libcinder.org/topic/keypresses-repeated-by-windows-make-my-app-lag

This seems to be about the same problem I’m having. The only difference is that the problem on my program persists, even with VSync turned off. (I tried turning vsync off through the nvidia control panel and with gl::enableVerticalSync(false).).

I do feel like this issue is VSync-related though: whenever the stutter happens, the framerate seems to get halved.
I’m using a laptop, and used this little piece of code:
extern "C" { __declspec(dllexport) unsigned long NvOptimusEnablement = 0x00000001; } extern "C" { __declspec(dllexport) int AmdPowerXpressRequestHighPerformance = 1; }

This requests to use an AMD or NVidia GPU when possible, because I couldn’t get line smoothing to work on my Intel (integrated) GPU.

Has anyone else experienced something similar before? And if so, would you happen to know why this happens or how to fix it?


#2

Hi,

the stuttering may have something to do with what you do in your keyDown( ci::app::KeyEvent event ) method.

Windows sends a single WM_KEYDOWN event when you press a key. If you hold the key, Windows starts sending more WM_KEYDOWN events until you let go of the key and a WM_KEYUP event is sent.

Cinder detects the system events for you and calls your application’s keyDown() and keyUp() methods. If you’re doing a lot of processing in those methods, this may lead to stuttering.

I know there have been reports of stuttering, even though the key methods didn’t do much. It happened to me, too. But for what it’s worth: I just ran a demanding Cinder application while holding the q key and it did not stutter. One of my tools is a frame rate monitor and it showed a steady 60 fps. So, at least for me, repeated keys don’t cause any stuttering.

I don’t think it’s related to enabling your discrete GPU.

If you think it might be something in your keyDown() method, perhaps you can share some code?

-Paul


#3

Thanks for the answer!
I’m not using the keyDown and keyUp methods, but a little KeyListener class.
Anyway, here’s how every button gets ‘listened’ for:

bool KeyListener::downKey() { return(GetAsyncKeyState(VK_DOWN) != 0); }
This is a simple example for the down arrow, but every key (up,left,right,‘C’,…) I need has the same code.

Here’s the things that happen when an arrow is pressed:

void Player::movestd(KeyListener &a, double dt) {
	double standardt = (1 / 60.0);
	if(a.xKey() && energy > 7){
		energy -= 0.16;
		if (spedUp == false) {
			spedUp = true;
			maxVel *= 1.9;
		}
	}
	else {
		if (spedUp == true) { 
			maxVel /= 1.9;
			spedUp = false;
		}
		if (!a.xKey()) { energy += energy < max_e ? 0.4 : 0; }
	}
	if (a.upKey()) {
		if (vel > maxVel) { vel *= 0.83; }
		vel += (vel >= maxVel ? 0 : maxVel/10)*(dt/standardt);
	}
	else if (a.downKey()) {
		if (vel < maxVel) { vel *= 0.83; }
		vel -= (vel <= -maxVel / 2 ? 0 : maxVel / 10)*(dt / standardt);
	}
	else {
		vel *= 0.83;
	}
	if (a.rightKey()) {
		the += M_PI / 60.0 * (dt / standardt);
		if (the >= 2 * M_PI) {
			the = 0;
		}
	}
	if (a.leftKey()) {
		the -= M_PI / 60.0 * (dt / standardt);
		if (the < 0) {
			the = 2 * M_PI;
		}
	}

	xp += cos(the)*vel*(dt/standardt);
	yp += sin(the)*vel*(dt/standardt);
}

void Player::behave(KeyListener &a, std::vector<Bullet> *bulletList) {
	if (xp < 0) {
		xp = ci::app::getWindowWidth();
	}
	if (xp > ci::app::getWindowWidth()) {
		xp = 0;
	}
	if (yp < 0) {
		yp = ci::app::getWindowHeight();
	}
	if (yp > ci::app::getWindowHeight()) {
		yp = 0;
	}
	
	if (a.cKey()) {
		if (!shot && energy > 12) {
		Bullet * bull = new Bullet(xp, yp, the, bulV, 5);
		energy -= 8;
		bulletList->push_back(*bull);
		delete bull;
		}
		shot = true;
	}
	else {
		shot = false;
	}
}

Maybe I’m doing some weird stuff with pointers etc., but I’m still very much learning C++ :slight_smile:
(little off-topic: I’m using standardt and dt to adjust movement to the fps the program runs at, that seems to work pretty OK)

This is every piece of code that uses the keylistener, so I don’t think any other code in my program interacts with the listener.


#4

Hi,

apart from potential logic problems, timing problems and coding style (none of which are important at the moment), I think your code is OK. You’re relying on GetAsyncKeyState, effectively circumventing the system events. Your animations simply want to know if a key is pressed and change their behavior based on that. So all looks good.

In order to rule out timing issues, you may want to make sure you either have vertical sync enabled (at a steady 60 fps) or use Cinder’s built-in frame rate limiter (setFrameRate( 60.0f );) and then use a fixed dt when you call:

movestd( keylistener, 1.0 / 60.0 );

If that removes the stutter, you should look into the way you measure elapsed time and the way you apply that to your equations. Otherwise, nothing really stands out as wrong to me.

-Paul

P.S.: an alternative to using dt can be found in this excellent article.


#5

Hi

Thanks for the answer!
Setting a 1/60s timestep and limiting the framerate gives about the same result as relying on framerate-based animation (which I did at first) and then setting the framerate to 60: things move the way they should.

I think I’m going to try to change the way I’m measuring time: the little ‘framerate-monitor’ i put into the program often records ‘framerates’ (the time between calculations actually) of up to a couple hundred (even with the framerate set to 60), so I’m thinking that’s where the issue is at… Thanks :slight_smile:

I’ll also clean up my code a bit, I made it to just kind of work, thanks for reminding me.

The article you linked is really nice, I’d read it yesterday as well, but thought that just the dt would be good enough, considering the only computer this ever has to run on is mine, and I’m not trying to simulate anything very precise. Turns out I was wrong :slight_smile:

I’ll try to clean up my code as well as I can, implement the timestep fix from the article, and if that doesn’t work, try to look for another way of measuring time.

Thank you very much for the answer!
-Arthur


#6

Problem solved (mostly, I think).

I used the semi-fixed-timestep -solution from Fix your timestep, but tweaked it a bit: I changed ‘frametime’ to be the difference in time between 20 frames instead of one, divided by twenty again. My thinking here was that that might correct for eventual inaccuracies that occur when asking for one frame, by taking the average over twenty frames.

Slightly to my surprise, but this seems to have worked pretty well :smiley: .

Obviously this isn’t a perfect fix: sometimes things speed up or slow down a bit, but it’s good enough for now.


#7

This seems to be resolved now but I will throw in my two cents as I had a very similar issue (hence me looking at this thread at all)

I had choppy movement as well due to keyboard input but traced it back to how I was using the key press functions rather than any issues with framerate or precise methods used (I see you were using GetAsyncKeyState instead of the cinder inbuilt functionality).

Rather than acting on an individual key press within the corresponding ‘press’ function I setup a bool to switch whenever a key was pressed/released. Then separately in my update function used this state to act on whatever was needed.
The reason this helped me was that holding a key fires an initial ‘Press’ then there is a pause of around half a second then more ‘presses’ are registered every quarter second or so. Think about what happens when you hold a key in a word processor, the initial character shows, there is a pause, then it keeps popping up at a steady rate. I was surprised Cinder had this behaviour - its probably from some OS settings. This was complicated no end by that fact that when I held one key and pressed some more the first held key stopped getting ‘pressed’ calls despite it still being held down.

By using a state bool for each key it all works peachy (and makes it easy to do frame rate related things as all actions happen in the update function). After all I no longer am relying on a ‘press’ event after the first one, only that there is a release event in due course.
The only assumption that I am relying on is that there will always be a corresponding ‘key release’ for each press. So far this has held true.

Anyway hope that makes sense and is of some help to someone further down the line.


#8

Isn’t that what my code does? It ‘asks’ the pc if a key is pressed and returns if it is with a bool (I think).
I don’t believe there are any events happening.

The only time the code is doing anything with inputs is during the update function; every update certain keys get ‘checked’.

In that sense, how does your code work differently from mine?