Multiple movements with keyboard in C++ - c++

Im trying to get my movement of a ball to just move in a fluid like motion. How can I have it that when I press the up key, down key, left key, or right key, it doesnt move up one unit, stop, then keep moving. Also, how can i have it move in two directions at the same time wthout stopping another direction when letting off a key?
Thanks
if(GetAsyncKeyState(VK_UP))
{
if(g_nGameState == SETTINGUPSHOT_GAMESTATE || g_nGameState == INITIAL_GAMESTATE)
{
g_cObjectWorld.AdjustCueBallY(MOVEDELTA);
g_cObjectWorld.ResetImpulseVector();
}
}
if(GetAsyncKeyState(VK_DOWN))
{
if(g_nGameState == SETTINGUPSHOT_GAMESTATE || g_nGameState == INITIAL_GAMESTATE)
{
g_cObjectWorld.AdjustCueBallY(-MOVEDELTA);
g_cObjectWorld.ResetImpulseVector();
}
}
if(GetAsyncKeyState(VK_LEFT))
{
if(g_nGameState == SETTINGUPSHOT_GAMESTATE || g_nGameState == INITIAL_GAMESTATE)
{
g_cObjectWorld.AdjustCueBallX(-MOVEDELTA);
g_cObjectWorld.ResetImpulseVector();
}
}
if(GetAsyncKeyState(VK_RIGHT))
{
if(g_nGameState == SETTINGUPSHOT_GAMESTATE || g_nGameState == INITIAL_GAMESTATE)
{
g_cObjectWorld.AdjustCueBallX(MOVEDELTA);
g_cObjectWorld.ResetImpulseVector();
}
}

You can do something like this:
Use SetTimer to create a timer on your window event loop 10ms interval should be good for what you want. The reason it has to be on the window thread is that GetAsyncKeyState will not give you the desired results when called from a different thread.
We use a timer since the call to GetAsyncKeyState should be on a different message then the key processing events so the key is still in the queue.
Within the timer function you can do something like this
int deltaX = 0, deltaY = 0;
unsigned int downDown = GetAsyncKeyState(VK_DOWN);
unsigned int upDown = GetAsyncKeyState(VK_UP);
unsigned int leftDown = GetAsyncKeyState(VK_LEFT);
unsigned int rightDown = GetAsyncKeyState(VK_RIGHT);
if(downDown & 0x00008000)deltaY -= MOVEDELTA;
if(upDown & 0x00008000)deltaY += MOVEDELTA;
if(leftDown & 0x00008000)deltaX -= MOVEDELTA;
if(rightDown & 0x00008000)deltaX += MOVEDELTA;
g_cObjectWorld.AdjustCueBallX(deltaX);
g_cObjectWorld.AdjustCueBallY(deltaY);
g_cObjectWorld.ResetImpulseVector();
In this way you can also make sure that the movement stops on keyup (deltaX == 0 && deltaY == 0)
I'm not sure what are the semantics of AdjustCueBall(X|Y) but if you make sure they stop moving in that direction when they get 0 it should work just fine.
Also you should notice that your keyboard must support multiple key press in the hardware for you to be able to move diagonally using two keys - If it does the solution above will work if it doesn't you will still be able to move in either one of the four fundamental directions.

One design is to use the keyboard only for changing directions.
Let the ball continue in its present direction until a keypress is received that would change its direction. This reduces the load on the processor from continuously being interrupted by keypresses.
As for going in non-orthogonal directions, use more keys. Look at a "keypad". Some keys are diagonal from the '5' keys. Use those.

Related

GLUT Timer/Idle function not updating

I want to keep an object moving forward without the user having to do anything. I understand that this is a job for glutTimerFunc and I believe I'm implementing it properly as shown below. For some reason, if I leave the screen untouched nothing updates; but if I move the mouse (or create any kind of 'event') the scene then updates. If I wait a few seconds and then retrigger an update myself, the object moves the amount that it should have in those few seconds (e.g. if it moves one unit per second, after waiting 3 seconds and retriggering the object jumps 3 units). Therefore the timer is working but I just don't know why the screen isn't redisplayed constantly.
void myTimer(int v) {
if (forward == 1) {
//increment movement variable
}
if (backward == 1) {
//increment movement variable
}
glutPostRedisplay;
glutTimerFunc(100 / n, myTimer, v);
}
Below is the snippet for my up and down (forward and backward) keys:
if (key == GLUT_KEY_UP)
{
forward = 1;
backward = 0;
}
if (key == GLUT_KEY_DOWN)
{
forward = 0;
backward = 1;
}
I also have the callback glutTimerFunc(1000, myTimer, n); in my main before glutMainLoop().
Why isn't my timer causing the screen to re-render without my triggering it?
glutPostRedisplay;
^ missing something?
That just evaluates the address of glutPostRedisplay which doesn't really do anything.
You need the empty parens to actually call glutPostRedisplay():
glutPostRedisplay();

Why does the function in the event polling loop trigger less frequently than the function outside it

I have a cube that rotates by itself and one that rotates when a key is being pressed. The problem is that the one that rotates by itself always rotates faster(much faster) than the one that rotates only when a key is being pressed.
while(!quit())
{
handleInput();
update();
render();
}
When I put my rotation here:
update()
{
cube.rotation += 0.09f;
}
The cube rotates fast.
But when i put it here:
handleinput()
{
while(pollevent(&event))
{
if(event.type == keydown)
{
if(event.key.symbol == KEY_r )
{
cube.rotation += 0.09f;
}
}
}
It is much slower. Though I assume that both should be getting called once each loop when the key is being held down.
And I don't know what this question must be tagged.
Your keydown event is simply fired less frequently than your game logic is updated.
A common solution is to keep track of the keyboard's state.
SDL way
I suggest storing the keyboard state as an array of booleans, which size is the number of keys you will check against, e.g. bool[SDL_KEYLAST].
So you'll have to modify it whenever an event is fired. Finally, at each loop, check for the saved keyboard state.
Example code:
handleInput()
{
while(pollEvent(&ev))
{
if(event.type = keydown)
ks[event.key.symbol] = true;
else if(event.type = keyup)
ks[event.key.symbol] = false;
}
}
update()
{
if(ks[KEY_R]) cube.rotation += 0.05f;
}
SDL2 way
const Uint8* ks = SDL_GetKeyboardState(NULL).
This function returns the keyboard state array, which is not a bool[] but a Uint8[] containing 0/1 values (so you can still check on false/true values).
But also, you'll have to check against SDL_Scancode index values if you want to use that array, which are listed here: https://wiki.libsdl.org/SDL_Scancode
handleinput()
{
//pump events so that SDL can update the keyboard state array...
}
update()
{
const Uint8* ks = SDL_GetKeyboardState(NULL);
if(ks[SDL_SCANCODE_R]) cube.rotation += 0.05f;
}
Reference: https://wiki.libsdl.org/SDL_GetKeyboardState
dmg is likely correct.
Pollevent doesn't just iterate over a list of keys currently pressed, you're iterating over a list of events to handle, and it only gets updated at your repeat rate. You probably want to internally handle the state of the button, and toggle it on and off with the events, handling the rotation in the update (better separation of functionality, anyway).

SFML Input Not responsive at start

I am making a 2D game where we are supposed to control the character through arrow keys.
if((win.GetInput().IsKeyDown(sf::Key::Down)))
{
y = y + Speed;
}
if((win.GetInput().IsKeyDown(sf::Key::Left)))
{
x = x - Speed;
}
I have set Speed to 10. And then a i use the Sprite.SetPosition(x,y) to actually animate my character.
Everything works fine. But the problem is whenever i press an arrow key, the character moves for 1/2 seconds, stops for about 1/2 seconds and then moves again smoothly. This happens whenever i press any arrow key.
And yes, i am using a while loop on top to handle multiple events simultaneously.
I hope my question was clear enough. Please help me out!
Thanks.
I think you're not handling events the right way. What you're doing here is checking on each event (which could be keyboard input or not) whether the sf::Key::Down key is pressed (and the same for sf::Key::Left).
Firstly, it's not effective, because you don't get the result you want.
Secondly, it performs useless checks admitting that the events could be mouse moves, mouse clicks or anything else : checking whether those keys are pressed in such cases is pointless for your program.
I can't see your whole code, but you should try something of this taste as your main loop :
bool isMovingLeft = false;
bool isMovingDown = false;
sf::Event event;
while (win.IsOpen())
{
// While window catches events...
while(win.GetEvent(event))
{
// If the caught event is a click on the close button, close the window
if (event.Type == sf::Event::Closed)
win.Close();
// If it's a key press, check which key and move consequently
else if (event.Type == sf::Event::KeyPressed)
{
if(event.Key.Code == sf::Key::Left)
isMovingLeft = true;
else if(event.Key.Code == sf::Key::Down)
isMovingDown = true;
}
// If it's a key release, stop moving in the following direction
else if (event.Type == sf::Event::KeyReleased)
{
if(event.Key.Code == sf::Key::Left)
isMovingLeft = false;
else if(event.Key.Code == sf::Key::Down)
isMovingDown = false;
}
}
// Now that we have caught events, we move the lil' thing if we need to.
if(isMovingLeft)
x = x - SPEED;
if(isMovingDown)
y = y - SPEED;
win.Clear();
// Draw things on the screen...
win.Display();
}
In this code, the whole process is split in two parts :
We first intercept the user input to see if we need to change the moving state of the thing.
Then, once every event has been caught and thoroughly analyzed, we move the thing if it has to. It is done through two bools (that you may need to increase to four if you want a four-direction control. If you want to handle diagonal directions, it would be wiser to use an enum than eight bool, which begins to be rather memory-consuming for such a simple task.)
Note : you will maybe notice that I changed "Speed" to "SPEED". I can't see if it was a define, a const var or simply a var from the code you have given, but the best option would be one of the two first ones. I prefer using #define for such things, to make constants easily reachable (as they're put in the preprocessor) and the fully capped writing make it more differentiable from classic vars once in the code. But that's just coding style we're talking of here :)

How I can prevent every key being sent to KeyboardUpFunc in GLUT?

I'm fairly new to OpenGL, and I am writing a simple game in 2D, for fun. However, I ran into an issue I am having a hard time wrapping my head around.
It seems that whenever my keyboardUpFunc is called, that not only the key that has actually come up sent to the function, but every single key currently being pressed as well.
I'm using a simple key buffer to manage the keys, keyUp marks the key as up and is only called in this function. keyDown is called in my keyboardFunc. isDown returns a boolean value of whether or not the key is pressed. Take this code for example:
#include <iostream>
...
void keyboardUp(unsigned char key, int x, int y)
{
keys.keyUp(key);
if (keys.isDown('s') == false)
{
std::cout << "It's resetting s as well!" << std::endl;
}
// reset acceleration here, for each key
if ( (key == 'w') || (key == 's') )
{
yStep = 0.1;
}
if ( (key == 'a') || (key == 'd') )
{
xStep = 0.1;
}
std::cout << key << " is now up." << std::endl;
}
If you run this code, if you for example, hold S and D, then release the D key, you will note that S has been marked as up too, since this is the only location keyUp is being called.
Assuming my keyBuffer code is working correctly (and it is, but let me know if you want me to post it...), is there any way to get around this? Where if you were holding a key, and then pressed another key, the application would go back to what you were doing when you were just holding the original key? Instead of marking both as up? Or is this not feasible with GLUT?
Not very clear what is going wrong.. But where/how exactly are you calling this function ?? Directly in the Main Game loop, or are you checking certain conditions in an 'update' function. I ask because you need to check for input every run of the infinite loop, and if you are using a boolean to determine if a key is down, you should essentially reset it after its corresponding action has been performed. Anyway, just my 2 cents.
I changed my implementation of the keyboard buffer, and what I was describing above now works. The difference is that before I was using a vector to pile on the keys that were being pressed, whereas now, I am using a fixed-size array of boolean values.
Apparently, a vector implementation of a key buffer won't work properly with GLUT.

OpenGL pausing problems

I have the following function that is used as the glutKeyboardFunc function parameter:
void handleKeypress(unsigned char key, //The key that was pressed
int x, int y) { //The current mouse coordinates
switch (key) {
case 27: //Escape key
exit(0); //Exit the program
}
if (key == 'a')
{
moveCircleLeft(0);
}
if (key == 'w')
{
moveCircleUp(0);
}
if (key == 's')
{
moveCircleDown(0);
}
if (key == 'd')
{
moveCircleRight(0);
}
}
Now I will show you moveCircleLeft as an example of how the moveCircle functions are written:
void moveCircleLeft(int x)
{
characterX = characterX - 0.1;
glutPostRedisplay();
x++;
if (x < 10)
{
glutTimerFunc(10, moveCircleLeft, x);
}
}
The other moveCircle functions work similar and the only differences between the four functions is whether its plus of minus 0.1 or if it is characterY as opposed to characterX.
Now, here is the problem:
All the directions are moving in the right direction but, there is a delay/pause in movement of the character when I try to press keys. So, if I press just the d key (moveCircleRight) it moves right a little, stops a for a small amount of time, then moves across the screen in that direction at a constant speed with no pauses. Then if I change to a different key it pause for a little bit before changing directions then moves at a constant speed in that direction.
Any suggestion around this would be appreciated!
Create a boolean variable for each key (preferably an array). Then use KeyDown/KeyUp instead of KeyPress (i believe in GLUT its something like KeyboardUpFunc and KeyboardFunc, but cant remember now). On KeyDown, set the appropriate variable to true, on KeyUp, set it to false. Now you probably have an Idle function or something like that. Call there your "move" functions based on the boolean variables. There should be no pauses now. Beware though that you might need to keep track of the time elapsed between frames and scale the distance moved appropriately.