Hey so I'm working on a project/2d game and I'm having some odd behavior from SDL which I'm sure is probably something I'm not understanding. The function ProcessKeys is called and works fine for all the key press downs except SDLK_SPACE and I cannot for the life of me figure out why.
What is even more bizarre is that the SDL_KEYUP switch of SDLK_SPACE works great. I tried using some debugging code to print out which key is being pressed and when you press space down nothing registers. Every other key on the keyboard registers in my debug statement at the top of the SDL_KEYDOWN case.
If anyone can see what is going on I would really appreciate it.
And if you need to see where its being called let me know.
SDLKeyboard::KeyState SDLKeyboard::ProcessKeys(SDL_Event * event)
{
switch(event->type)
{
/* Look for a keypress */
case SDL_KEYDOWN:
{
std::cout << "Key currently pressed" << event->key.keysym.sym << std::endl;
/* Check the SDLKey values and move change the coords */
switch(event->key.keysym.sym)
{
case SDLK_LEFT:
{ // rotate the ship left
c.setIsTurningLeft(true);
return this->keystate = LeftPressed;
// add code when user presses left
break;
}
case SDLK_RIGHT:
{
// rotate the ship right
c.setIsTurningRight(true);
return this->keystate = RightPressed;
// add code when user presses right
break;
}
case SDLK_UP:
{
// accleration
c.setIsAccelerating(true);
return this->keystate = UpPressed;
// add code when user presses up
break;
}
case SDLK_SPACE:
{
// shoot
c.setIsShooting(true);
std::cout << "keystate = " << this->keystate;
return this->keystate = SpacePressed;
// add code when user presses space
break;
}
default:
{
return this->keystate = NotPressed;
break;
}
}
break;
}
/* We must also use the SDL_KEYUP events to zero the x */
/* and y velocity variables. But we must also be */
/* careful not to zero the velocities when we shouldn't*/
case SDL_KEYUP:
{
std::cout << "Key currently pressed" << event->key.keysym.sym << std::endl;
switch(event->key.keysym.sym)
{
case SDLK_LEFT:
{ /* We check to make sure the ship is moving */
/* to the left. If it is then we zero the */
/* velocity. If the ship is moving to the */
/* right then the right key is still press */
/* so we don't touch the velocity */
c.setIsTurningLeft(false);
return this->keystate = LeftReleased;
// code to do things when left isn't pushed anymore but still moving left
break;
}
case SDLK_RIGHT:
{ // code to do things when right isn't pushed anymore but still moving right
c.setIsTurningRight(false);
return this->keystate = RightReleased;
break;
}
case SDLK_UP:
{ // code to do things when up isn't pushed anymore but still moving up
c.setIsAccelerating(false);
return this->keystate = UpReleased;
break;
}
case SDLK_SPACE:
{ // accleration
c.setIsShooting(false);
return this->keystate = SpaceReleased;
// add code when user presses up
break;
}
default:
break;
}
break;
}
default:
{
return this->keystate = NotPressed;
break;
}
}
}
EDIT:
Here is the example requested. The other thing that I've noticed is the latency in response isn't that great. Like if you press a key sometimes the console doesn't print the corresponding key. Probably has to do with the issue I'm having with the space as well.
void GUI::TakeInput(SDL_Event *e)
{
while (SDL_PollEvent(e))
OnEvent(e);
}
void SDLEvent::OnEvent(SDL_Event * event)
{
switch(event->type)
{
case SDL_KEYDOWN:
{
OnKeyDown(event->key.keysym.sym);
break;
}
case SDL_KEYUP:
{
OnKeyUp(event->key.keysym.sym);
break;
}
case SDL_MOUSEMOTION:
{
OnMouseMove(event->motion.x,event->motion.y);
break;
}
case SDL_MOUSEBUTTONDOWN:
{
OnMouseButtonDown(event->button.button, event->button.x,event->button.y);
break;
}
case SDL_MOUSEBUTTONUP:
{
OnMouseButtonUp(event->button.button, event->button.x,event->button.y);
break;
}
case SDL_QUIT: {
OnExit();
break;
}
case SDL_SYSWMEVENT: {
//Ignore
break;
}
case SDL_WINDOWEVENT_RESIZED: {
OnResize();
break;
}
case SDL_WINDOWEVENT_EXPOSED: {
OnExpose();
break;
}
default: {
OnUser(event->user.type,event->user.code,event->user.data1,event->user.data2);
break;
}
}
}
void GUI::Play()
{
Uint32 start_ticks = SDL_GetTicks();
TakeInput(this->setup->GetEvent());
this->keyboard->ProcessKeys(this->setup->GetEvent());
this->setup->RenderBegin();
this->ship->drawBackBuffer();
this->ship->renderSprite();
Uint32 end_ticks = SDL_GetTicks();
int sleep_delay = (1000 / 60) - (end_ticks-start_ticks);
if (sleep_delay > 0) {
SDL_Delay(sleep_delay);
}
}
If you are only writing event->key.keysym.sym on the console, you should know that the spacebar key produces an almost invisible character.
Try this instead:
std::cout << "<" << event->key.keysym.sym << ">"
So you can see whataver invisible character printed between angle brackets.
Related
My program has to quit when I press ESC key. Even not pressing the key, my program exit automatically after some seconds of execution. No errors or notable exceptions found during the execution and the code seems to be correct.
void pollE(bool& _isRunning, build *actionBuild,finance *money,squareId* slotId,squareId map[][MAP_SLOTS_H]) {
while (SDL_PollEvent(&event)) {
// MOUSE
switch (event.button.button) {
case SDL_BUTTON_LEFT:
if (event.button.state == SDL_RELEASED) {
actionBuild->construct(ID_CASA, map);
}
if (event.button.state == SDL_PRESSED) {
}
break;
case SDL_BUTTON_RIGHT:
if (event.button.state == SDL_RELEASED) {
// test
debugPrintMap(map);
}
if (event.button.state == SDL_PRESSED) {
}
break;
}
// KEYBOARD
switch (event.key.keysym.sym) { // ---------------------------- HERE
case SDLK_ESCAPE: // ------------------------------------------ HERE
_isRunning = false; // ------------------- to stop mainLoop()
break;
case SDLK_SPACE:
break;
default:
break;
}
}
The function is called here:
void mainLoop() {
(...)
while (isRunning == true) {
dealWithEvents->pollE(isRunning,actionBuild,money,slotId,map);
preDraw();
draw();
afterDrawEffects();
draw();
(...)
}
(...)
}
i have a question:
(i use winows, visual studio)
i making a program and i need to read keyboard and mouse input istantly so like getch() (because if i use cin i need to press fullstop new line evry time).
i have this:
char p;
while (running) {
if (_kbhit()) {
p = _getch();
switch (p) {
case 'w':
mx = -1;
map(player, mx, 0);
break;
case 'a':
my = -1;
map(player, 0, my);
break;
case 's':
mx = 1;
map(player, mx, 0);
break;
case 'd':
my = 1;
map(player, 0, my);
break;
case 27:
running = false;
break;
}
}
}
the problem is with _getch() i can't read mouse imput.
so how i can get this?
I created an event class and wanted to get text with it. Unfortunately the text isn't reading correctly...
I've set it up so that all text that is gotten is output to the command line when a new key is input, but it obviously isn't working.
Here's my "EventManager" code for my update function:
void EventManager::update(){
while(SDL_PollEvent(&e)){
switch(e.type){
case SDL_QUIT:
running = false;
break;
case SDL_MOUSEBUTTONDOWN:
mousePressed = true;
break;
case SDL_KEYDOWN:
if(shouldCollectText && e.key.keysym.sym == SDLK_BACKSPACE && currentCollectedText.length() > 0){
currentCollectedText.pop_back();
}else if(shouldCollectText && e.key.keysym.sym != SDLK_BACKSPACE){
currentCollectedText += e.text.text; //The problem
std::cout << currentCollectedText << std::endl;
}
}
}
}
I followed the Lazy Foo tutorials, and I can't find the problem.
Some other things to note:
I start text input in my "main.cpp" class:
int main( int argc, char *argv[] ) {
Game *game = new Game();
game->init();
SDL_StartTextInput();
while(game->isRunning()){
game->handleEvents();
game->update();
game->render();
}
game->close();
SDL_StopTextInput();
return 0;
}
I create some of my variables in "EventManager.h":
bool shouldCollectText;
std::string currentCollectedText;
And define them in an "init()" function:
shouldCollectText = false;
currentCollectedText = "";
Your problem is that you are using the wrong event type. Take a second look at Lazy Foo's tutorial and here:
TextInputEvent
e.text.text is reserved for Text Input events and nothing else. Being SDL_Event an union of structures, overlaps may occur in the used memory. That is exactly what you see in the terminal output.
Remove the SDL_KEYDOWN event and try this instead:
case SDL_TEXTINPUT:
currentCollectedText += e.text.text;
break;
I'm not sure about std::cout << currentCollectedText << std::endl; though. It depends on when you want to get output of the text content.
If you want to use SDL_KEYDOWN you will have to access the keysym tables and maybe calculate to which letter they correspond and print those out. I would say, that approach is more complicated for what you want to achieve.
So in conclusion e.text.text will only work if e.type has the SDL_TEXTINPUT value as event. With all the other settings in your code that event should be triggered and may get the text you type in.
So your complete example could look like this:
void EventManager::update(){
while(SDL_PollEvent(&e)){
switch(e.type){
case SDL_QUIT:
running = false;
break;
case SDL_MOUSEBUTTONDOWN:
mousePressed = true;
break;
case SDL_TEXTINPUT:
if(shouldCollectText && currentCollectedText.length() > 0){
currentCollectedText.pop_back();
}else if(shouldCollectText) {
currentCollectedText += e.text.text; //The problem
std::cout << currentCollectedText << std::endl;
}
break;
default: break;
}
}
}
for using arrow keys, first it has to be stored for analyzing it. That's why I am using scanf to store it.
But when I try to run this code, and when I press up key, then it is showing ^[[A and when I press enter then this ^[[A removes and program exit without printing printf statement of printf("%s",c). and printf("UP\n").
#include <stdio.h>
int main()
{
char c[50];
scanf("%s",&c);
printf("%s",c);
if (getch() == '\033'){ // if the first value is esc
getch();// skip the [
getch();// skip the [
switch(getch()) { // the real value
case 'A':
printf("UP\n");
break;
case 'B':
printf("DOWN\n");
break;
}
}
return 0;
}
You will find it easy if you use the ncurses library. Just go through the documentation to see how to install it.
After installing read the part on Interfacing with the key board
Here is a sample code
#include <ncurses.h>
int main()
{
int ch;
initscr();
raw();
keypad(stdscr, TRUE);
noecho();
while(1)
{
ch = getch();
switch(ch)
{
case KEY_UP:
printw("\nUp Arrow");
break;
case KEY_DOWN:
printw("\nDown Arrow");
break;
case KEY_LEFT:
printw("\nLeft Arrow");
break;
case KEY_RIGHT:
printw("\nRight Arrow");
break;
}
if(ch == KEY_UP)
break;
}
endwin();
}
I'm currently playing around with SDL to make a game and I've run into a problem where SDL is not picking up some events. For exampling, I would be pressing 'w' to move forward and at the same time, I'm moving my mouse to look around. But let's say I then press 'a' or 'd', SDL will not pick these events or even when I release 'w', SDL will not pickup the KEYUP event. I first wrote this code in windows and it all worked fine, but after switching to ubuntu, it doesn't work as expected anymore. Here is my main loop where I poll for events:
while(Running)
{
while(SDL_PollEvent(&event))
Events(&event);
if( active ){
Loop();
Render();
}
}
This is the code within Events():
switch(Event->type)
{
case SDL_QUIT:
Running = false;
break;
case SDL_KEYDOWN:
switch(Event->key.keysym.sym)
{
case SDLK_ESCAPE:
Running = false;
break;
case SDLK_a:
keyStates['a'] = true;
break;
case SDLK_s:
keyStates['s'] = true;
break;
case SDLK_d:
keyStates['d'] = true;
break;
case SDLK_w:
keyStates['w'] = true;
break;
case SDLK_LSHIFT:
camera.setSpeed(2.0f);
break;
}
break;
case SDL_KEYUP:
switch(Event->key.keysym.sym)
{
case SDLK_a:
keyStates['a'] = false;
break;
case SDLK_s:
keyStates['s'] = false;
break;
case SDLK_d:
keyStates['d'] = false;
break;
case SDLK_w:
keyStates['w'] = false;
break;
case SDLK_LSHIFT:
camera.setSpeed(1.0f);
break;
}
break;
case SDL_MOUSEBUTTONDOWN:
switch(Event->button.button)
{
case SDL_BUTTON_MIDDLE:
mouse.middle = true;
break;
}
break;
case SDL_MOUSEBUTTONUP:
switch(Event->button.button)
{
case SDL_BUTTON_MIDDLE:
mouse.middle = false;
break;
}
break;
case SDL_MOUSEMOTION:
if( moving ){
camera.lookat(float(Event->motion.x - winWidth/2),float(Event->motion.y - winHeight/2), MOUSE_SENSITIVITY, dt);
SDL_EventState(SDL_MOUSEMOTION, SDL_IGNORE);
SDL_WarpMouse(winWidth/2, winHeight/2);
SDL_EventState(SDL_MOUSEMOTION, SDL_ENABLE);
}
break;
}
keyStates['a'] = true;
There's SDL_GetKeyState for this. Use it instead of manually maintaining array.
Uint8 keys[SDLK_LAST];
Uint8* sdlKeys = SDL_GetKeyState(0);
memcpy(keys, sdlKeys, sizeof(keys));
.
bool keyPressed(SDLKey key){
return keys[key] == SDL_PRESSED;
}
Also check documentation.