SDL_Events how to make it - c++

I wrote a func that help me move my car with SDL
if (events.type == SDL_KEYDOWN)
{
switch(events.key.keysym.sym)
{
case SDLK_UP:
y_val -=main_car_speed;
break;
case SDLK_DOWN:
y_val +=main_car_speed;
break;
case SDLK_RIGHT:
x_val +=main_car_speed;
break;
case SDLK_LEFT:
x_val -=main_car_speed;
break;
}
It's pretty simple. But I got a problem that when I press up and left. My car just go ahead, instead of go ahead and left at the sametime.
How can I solve this problem?

Using events, if you press 'left' after having pressed 'up', your program will stop receiving events for the 'up' key-presses and will instead receive only 'left' key-presses. If you want to know whether keys are pressed or not pressed at any moment in time, rather than react to when they are first pressed, the following code should help you:
// inside main loop, after events have been handled
const Uint8* keystates = SDL_GetKeyboardState(NULL);
if (keystate[SDL_SCANCODE_UP]){
y_val -= main_car_speed;
}
if (keystate[SDL_SCANCODE_LEFT]){
x_val -= main_car_speed;
}
Have a look at the Documentation for SDL_GetKeyboardState for details

Related

C++ How do I Handle all possible Player Movement inputs?

I am trying to clean up movement code I followed from a video tutorial series that was never finished. My intent is for the character to only ever be able to move on X or Y at any given time (so no diagonal). The character has direction facing to keep in mind.
My issue is the player can still press any key they want, or accidently press two keys at the same time.
Ex. if you move Up and make a right turn, accidentally press Right before letting go of Up.
Or if you press Up, press and let go Right to make a slight movement right while continuing to press Up, the player should continue to move up after letting go of Right without having to re-press Up. etc.
Just to make sure all possible input cases are handled intuitively.
EDIT: This is the code so far and I'm getting weird errors I don't know what's wrong
#pragma once
#include "../game.h"
#include "ECS.h"
#include "Components.h"
#include <list>
using namespace std;
class KeyboardController : public Component
{
public:
TransformComponent *transform;
SpriteComponent *sprite;
std::list<SDL_Event> keyDownList;
SDL_Event lastDirection;
void updateKeyState()
{
if (Game::event.type == SDLK_ESCAPE) {
Game::isRunning = false;
}
else if (Game::event.type == SDL_KEYDOWN) {
keyDownList.push_back(Game::event.key.keysym.sym);
}
else if (Game::event.type == SDL_KEYUP) {
keyDownList.remove(Game::event.key.keysym.sym);
}
}
void init() override
{
transform = &entity->getComponent<TransformComponent>();
sprite = &entity->getComponent<SpriteComponent>();
}
void update() override
{
void updateKeyState();
void updateMovement();
}
};
Severity Code Description Project File Line Suppression State
Error (active) E0304 no instance of overloaded function "std::list<_Ty, _Alloc>::push_back [with _Ty=SDL_Event, _Alloc=std::allocator]" matches the argument list Sandbox C:\file_path\KeyboardController.h 31
Severity Code Description Project File Line Suppression State
Error (active) E0415 no suitable constructor exists to convert from "SDL_Keycode" to "SDL_Event" Sandbox C:\file_path\KeyboardController.h 34
You should basically clean up your code by separating the logic between key events and player movement. So your update() method could look like this:
void update() override
{
updateKeyState();
updateMovement();
}
Since you want the player to move only vertically or horizontally (never diagonally), you have to store the key press order in a data structure that can be easily accessed. I think you could use a doubly-linked list:
std::list<SDL_Event> keyDownList;
and we should also store the last key pressed in order to restore the idle animation of the player:
SDL_Event lastDirection;
The updateKeyState() method should add or remove the key to/from the linked list. We should also check if the player wants to leave the game by pressing ESC:
void updateKeyState() {
if (Game::event.type == SDLK_ESCAPE) {
Game::isRunning = false;
} else if (Game::event.type == SDL_KEYDOWN) {
keyDownList.push_back(Game::event.key.keysym.sym);
} else if (Game::event.type == SDL_KEYUP) {
keyDownList.remove(Game::event.key.keysym.sym);
}
}
The updatePlayerMovement() method is where the magic happens. We should basically check which key was pressed first and update the player position accordingly. We also save the down key in the lastDirection field in order to use it when no key is pressed.
void updateMovement() {
// if any key is down
if (keyDownList.size() > 0) {
const SDL_Event downKey = keyDownList.front();
switch (downKey) {
case SDLK_w:
transform->velocity.y = -1;
transform->velocity.x = 0;
sprite->Play("BackWalk");
lastDirection = downKey;
break;
case SDLK_a:
transform->velocity.x = -1;
transform->velocity.y = 0;
sprite->Play("SideWalk");
sprite->spriteFlip = SDL_FLIP_HORIZONTAL;
lastDirection = downKey;
break;
case SDLK_s:
transform->velocity.y = 1;
transform->velocity.x = 0;
sprite->Play("FrontWalk");
lastDirection = downKey;
break;
case SDLK_d:
transform->velocity.x = 1;
transform->velocity.y = 0;
sprite->Play("SideWalk");
sprite->spriteFlip = SDL_FLIP_NONE;
lastDirection = downKey;
break;
}
} else {
// no key is down, handle idle situations
transform->velocity.x= 0;
transform->velocity.y = 0;
switch (lastDirection) {
case SDLK_w:
sprite->Play("BackIdle");
break;
case SDLK_a:
sprite->Play("SideIdle");
break;
case SDLK_s:
sprite->Play("FrontIdle");
break;
case SDLK_d:
sprite->Play("SideIdle");
break;
}
}
}
Note: I haven't tested this code because I don't have the code and structures from your game. So you may have to edit a piece here and there to make it work for you.

Detect only one keypress in C++

I'm trying to use the glut framework to handle keypresses for a game I'm writing in c++. When a specific key is pressed, I want to start drawing a new curve and so I create a new curve and add it to my container of curves. However, when I use onKeyboard and debug I see that this function is called over and over when a key is pressed, not just on the initial press. Therefore, it's creating about 12 curves every time a key is pressed. My code for onKeyboard is below. Any help would be appreciated greatly!
void onKeyboard(unsigned char key,int x, int y) {
keysPressed[key] = true;
switch (key) {
case 'l':
curvesContainer.addCurve(new lCurve());
break;
case 'p':
curvesContainer.addCurve(new pCurve());
}
glutPostRedisplay();
}
You would simply check if keyPressed[key] is already true, and only add your curve if it is false.
void onKeyboard(unsigned char key,int x, int y)
{
if (keysPressed[key] == false)
{
keysPressed[key] = true;
switch (key)
{
case 'l':
curvesContainer.addCurve(new lCurve());
break;
case 'p':
curvesContainer.addCurve(new pCurve());
break;
}
}
glutPostRedisplay();
}
You will additionally need to clear keysPressed[key] in an onKeyUp event, using glutKeyboardUpFunc
void onKeyUp(unsigned char key,int x, int y)
{
keysPressed[key] == false;
}
glutIgnoreKeyRepeat(1) is probably what you want. (1 = on)
Use input flush define in studio.in
It avoid rest of input

exit from while loop

Here i am having function like this. problem i am facing while changing Set parameter section.
first: i could not able to change Set_parameter Window
Second: Since in my loop i am saying if none key pressed display clock.because of that when i enter into Section menu it directly bounce back to Main displaying clock. Is there any way, where i can stay menu section unless Exit/LEFT key pressed
This main function where i am calling my LCD_call Function
void loop()
{
int button;
while(( button = read_LCD_buttons()) != btnNONE)
{
lcd_call();digitalClockDisplay();
}
}
LCD_call being called here.
LCD_call
break command should break/exit the loop.
It could be that the if condition is not coming out to be true, for any input case.
Try debugging your code by placing a break point inside if.
if(button==btnSELECT)
{
break; // place your breakpoint here.
}
and check if your code satifies the if condition for any possible input.
This should work :
void lcd_call()
{
while ( (button = read_LCD_buttons()) != btnSELECT)
{
DS_Counter=Display_selection();
switch (DS_Counter)
{
case 1:
lcd.setCursor(0,0);
digitalClockDisplay();
timedBeep(shortBeep,1);
break;
case 2:
lcd.setCursor(0,0);
Display_angle();
timedBeep(shortBeep,1);
break;
case 3:
lcd.setCursor(0,0);
Display_coordinate();
timedBeep(shortBeep,1);
break;
case 4:
lcd.setCursor(0,0);
Display_Wind();
timedBeep(shortBeep,1);
break;
case 5:
break;
}
}
}
You have already given a condition in While loop. As soon as the condition is false, it will break the while loop

Handling key events in SDL and C++

I'm in the process of migrating a program from GLUT to SDL. In my current program pressing the a key results in a different response then pressing the A key. This was pretty straightforward to do in GLUT as it the keyboard function callback passed in the ASCII value of the key that was pressed.
void keyPressedFn(unsigned char key, int x, int y){
switch(key){
case 'a':
// do work for a
break;
case 'A':
// do work for A
break;
}
}
I'm struggling to replicate similar functionality in SDL as pressing the a key produces the same response regardless of if SHIFT or CAPS LOCK are pressed as well.
Is there a simple way of replicating the above function in SDL?
Edit: In the example above I only show how to handle one key, in practice however, I am going to have a list of about 15 keys that I want to respond to differently if the shift key is pressed as well.
Check the keyboard modifiers that are present when you get a keydown event. For example:
while(SDL_PollEvent(&event))
{
switch(event.type)
{
case SDL_KEYDOWN:
if(event.key.keysym.sym == SDLK_a)
{
if(event.key.keysym.mod & KMOD_SHIFT)
{
// Handle 'A'
}
else
{
// Handle 'a'
}
}
break;
...
}
}
SDL_keysym has mod field, which contains state of modifier keys at the time the event has been emitted. Bit-AND it with KMOD_SHIFT to check whether Shift has been active. See SDL wiki.
Why not just do this?
void keyPressedFn(unsigned char key, int x, int y){
switch(key){
case 'a':
case 'A':
// do work for A or a
break;
}
}
Do you have some other concerns that you cannot do as what I have suggested? If not I think this is as simple as it can get.

How to handle multiple keypresses at once with SDL?

been getting myself familiar with OpenGL programming using SDL on Ubuntu using c++. After some looking around and experimenting I am starting to understand. I need advice on keyboard event handling with SDL.
I have a 1st person camera, and can walk fwd, back, strafe left and right and use the mouse to look around which is great. Here is my processEvents function:
void processEvents()
{
int mid_x = screen_width >> 1;
int mid_y = screen_height >> 1;
int mpx = event.motion.x;
int mpy = event.motion.y;
float angle_y = 0.0f;
float angle_z = 0.0f;
while(SDL_PollEvent(&event))
{
switch(event.type)
{
case SDL_KEYDOWN:
switch(event.key.keysym.sym)
{
case SDLK_ESCAPE:
quit = true;
break;
case SDLK_w:
objCamera.Move_Camera( CAMERASPEED);
break;
case SDLK_s:
objCamera.Move_Camera(-CAMERASPEED);
break;
case SDLK_d:
objCamera.Strafe_Camera( CAMERASPEED);
break;
case SDLK_a:
objCamera.Strafe_Camera(-CAMERASPEED);
break;
default:
break;
}
break;
case SDL_MOUSEMOTION:
if( (mpx == mid_x) && (mpy == mid_y) ) return;
SDL_WarpMouse(mid_x, mid_y);
// Get the direction from the mouse cursor, set a resonable maneuvering speed
angle_y = (float)( (mid_x - mpx) ) / 1000;
angle_z = (float)( (mid_y - mpy) ) / 1000;
// The higher the value is the faster the camera looks around.
objCamera.mView.y += angle_z * 2;
// limit the rotation around the x-axis
if((objCamera.mView.y - objCamera.mPos.y) > 8) objCamera.mView.y = objCamera.mPos.y + 8;
if((objCamera.mView.y - objCamera.mPos.y) <-8) objCamera.mView.y = objCamera.mPos.y - 8;
objCamera.Rotate_View(-angle_y);
break;
case SDL_QUIT:
quit = true;
break;
case SDL_VIDEORESIZE:
screen = SDL_SetVideoMode( event.resize.w, event.resize.h, screen_bpp, SDL_OPENGL | SDL_HWSURFACE | SDL_RESIZABLE | SDL_GL_DOUBLEBUFFER | SDL_HWPALETTE );
screen_width = event.resize.w;
screen_height = event.resize.h;
init_opengl();
std::cout << "Resized to width: " << event.resize.w << " height: " << event.resize.h << std::endl;
break;
default:
break;
}
}
}
now while this is working, it has some limitations. The biggest one and the purpose of my question is that it seems to only process the latest key that was pressed. So if I am holding 's' to walk backwards and I press 'd' to strafe right, I end up strafing right but not going backwards.
Can someone point me in the right direction for better keyboard handling with SDL, support for multiple keypresses at once, etc?
Thanks
SDL keeps track of the current state of all keys. You can access this state via:
SDL_GetKeyState()
So, each iteration you can update the movements based on the key state. To make the movement smooth you should update the movement magnitude based on the time elapsed between updates.
A good approach will be to write a keyboard ("input") handler that will process input events and keep the event's state in some sort of a structure (associative array sounds good - key[keyCode]).
Every time the keyboard handler receives a 'key pressed' event, it sets the key as enabled (true) and when it gets a key down event, it sets it as disabled (false).
Then you can check multiple keys at once without pulling events directly, and you will be able to re-use the keyboard across the entire frame without passing it around to subroutines.
Some fast pseudo code:
class KeyboardHandler {
handleKeyboardEvent(SDL Event) {
keyState[event.code] = event.state;
}
bool isPressed(keyCode) {
return (keyState[keyCode] == PRESSED);
}
bool isReleased(keyCode) {
return (keyState[keyCode] == RELEASED);
}
keyState[];
}
...
while(SDL Pull events)
{
switch(event.type) {
case SDL_KEYDOWN:
case SDL_KEYUP:
keyHandler.handleKeyboardEvent(event);
break;
case SDL_ANOTHER_EVENT:
...
break;
}
}
// When you need to use it:
if(keyHandler.isPressed(SOME_KEY) && keyHandler.isPressed(SOME_OTHER_KEY))
doStuff(TM);
If you're using SDL2 then use SDL_GetKeyboardState.
Example:
const Uint8 *keyboard_state_array = SDL_GetKeyboardState(NULL);
SDL_PollEvent(&event);
if(event.type == SDL_KEYDOWN || event.type == SDL_KEYUP)
{
// Move centerpoint of rotation for one of the trees:
if (keyboard_state_array[SDL_SCANCODE_UP] && !(keyboard_state_array[SDL_SCANCODE_DOWN]))
{
--location.y;
}
else if (!keyboard_state_array[SDL_SCANCODE_UP] && keyboard_state_array[SDL_SCANCODE_DOWN])
{
++location.y;
}
if (keyboard_state_array[SDL_SCANCODE_RIGHT] && !keyboard_state_array[SDL_SCANCODE_LEFT])
{
++location.x;
}
else if (!keyboard_state_array[SDL_SCANCODE_RIGHT] && keyboard_state_array[SDL_SCANCODE_LEFT])
{
--location.x;
}
}
Instead of only looking at keydown events, any solution which is going to be caring about multiple keys at once is going to have to be looking at both keydown and keyup events, and keeping track of the state of the keys in question.
So instead of (pseudocode):
on keydown:
case left_key:
object.setMovement(left)
case forward_key:
object.setMovement(forward)
instead you'd have something more like (again pseudocode):
on keydown:
case left_key:
keystates[left] = true
object.updateMovement(keystates)
case forward_key:
keystates[forward] = true
object.updateMovement(keystates)
on keyup:
case left_key:
keystates[left] = false
object.updateMovement(keystates)
case forward_key:
keystates[forward] = false
object.updateMovement(keystates)
Then the updateMovement routine would look at keystates and figure out a composite movement based on the states of all movement keys together.
use SDL_GetKeyState to get the keyboard state