Hi guys,
How do I put a delay on a key input in SDL? For example:
On a shoot 'em up game, if the player holds the fire button, there should be a delay between each missile created by his space ship.
Hi guys,
How do I put a delay on a key input in SDL? For example:
On a shoot 'em up game, if the player holds the fire button, there should be a delay between each missile created by his space ship.
Operating systems and APIs can simulate 'key repeat', pretending and telling your application that the same key was repeatedly pressed. If I hold down the letter 'A', for example, usually the OS does: A <long pause>, AAAAAAAAAAAAAAAA
This is useful for text editing and things of that nature, and you can customize the delay in the OS and sometimes in the API itself, but it's not very useful for games.
It doesn't really enforce that keypresses don't occur sooner or more frequently. This allows players to cheat by mashing their button a whole bunch to spam attacks faster than the developer intended, or to write programs to spam the button in software for them.
Really, the proper "game development" way of doing this is to code it yourself.
You don't really want "fire every time the key is pretended to be pressed by the operating system", what you really want is "fire every N millaseconds that the key is held down for".
So when SDL tells you, 'Spacebar was pressed', you mark 'bool spacebarIsHeld = true', and when they say 'Spacebar was released', you say, 'spacebarIsHeld = false'. (Or you can check the current state directly)
Then, on your programs time-controlled update tick, you say, "if enough time has passed, fire again".
void PlayerShip::Update(float timePassedInSeconds)
{
accumulatedTime += timePassedInSeconds; //Save up the amount of time passed, incase we didn't get enough to fire anything.
int bulletsToFire = (accumulatedTime / FIRE_DELAY); //Get the amount of bullets that we can fire, given the amount of time passed.
accumulatedTime = fmod(accumulatedTime, FIRE_DELAY); //'Use up' the time that we are spending here.
if(holdingSpacebarDown)
{
//Fire the bullets.
for(bulletsToFire)
{
FireBullet();
}
}
bulletsToFire = 0;
}
Basically, you want your keypresses and other events to change your game's logic state. Then, every update, you use your game's logic state, with the amount of time passed, to change your game's actual state.
Likewise, you have your enemy AI 'think' every so often, which changes their logic state, but then every update frame you use their logic state to affect their actual state based on the amount of time passed.
Drawing happens every frame (60 times a second or more). Events happen every so often depending on the user. AI thinking doesn't need to occur except maybe 5 or so times a second (depending on your game's needs). Game updating based on time and logic state doesn't need to occur except twenty or thirty times a second.
You don't really want "fire every time the key is pretended to be pressed by the operating system", what you really want is "fire every N millaseconds that the key is held down for".
So when SDL tells you, 'Spacebar was pressed', you mark 'bool spacebarIsHeld = true', and when they say 'Spacebar was released', you say, 'spacebarIsHeld = false'. (Or you can check the current state directly)
I did it! I already had my own function that returned 1 for key is down, 0 for key is being released and -1 for key is not being used. What I did, I just put a variable in the beginning of my update function:
frameStart = SDL_GetTicks();
Then I had my function update it using a variable to hold the current frame time and compare it with my delay:
if(GetKeyboardInput(SDL_SCANCODE_SPACE, event) == 1)
{
frameTime += frameStart;
if(frameTime >= fireDelay)
{
missiles.push_back(new Missile());
missiles.back()->load("misslie", (position.GetX() + srcRect.w / 2), position.GetY(), renderer);
frameTime -= fireDelay;
}
}
Thanks a lot mate!
Also you could put in a timer function to enforce delay, to put a maximum effectiveness or gimp modded controllers/programs.