0
\$\begingroup\$

I'm trying to program a simple space shooter and my goal right now is that when the player presses down and holds a key, the ship accelerates to a max velocity.

I have that somewhat; the problem is that when starting the game I can press the directional/arrow keys on my keyboard about 4 or 5 times (in any direction) and get the desired result before further key presses have no effect on the velocity and the ship just floats.

It's like the keyboard gets disabled. Here are the relevant parts of the program:

void Ship::handleEvent( SDL_Event &e ) { 290 291 const Uint8* keystate = SDL_GetKeyboardState(NULL); 292 293 bool keydown = false; 294 295 if ( e.type == SDL_KEYDOWN ) 296 keydown = true; 297 298 if ( keydown ) { 299 300 // std::cout << std::boolalpha << "keydown: " << keydown << "\n" << "keyup: " << keyup << "\n"; 301 302 // std::cout << holdTime << "\n"; 303 304 if ( keystate[SDL_SCANCODE_UP] && std::abs(mVelY) <= SHIP_MAX_VELOCITY ) { 305 306 if (mVelY <= SHIP_MAX_VELOCITY) { 307 mVelY -= SHIP_ACCELERATION; 308 direction = UP; 309 } 310 } 311 312 if ( keystate[SDL_SCANCODE_DOWN] && std::abs(mVelY) <= SHIP_MAX_VELOCITY ) { 313 314 if (mVelY <= SHIP_MAX_VELOCITY) { 315 mVelY += SHIP_ACCELERATION; 316 direction = DOWN; 317 } 318 } 319 320 if ( keystate[SDL_SCANCODE_LEFT] && std::abs(mVelX) <= SHIP_MAX_VELOCITY ) { 321 322 if (mVelX <= SHIP_MAX_VELOCITY) { 323 mVelX -= SHIP_ACCELERATION; 324 direction = LEFT; 325 } 326 } 327 328 if ( keystate[SDL_SCANCODE_RIGHT] ) { 329 330 if (mVelX <= SHIP_MAX_VELOCITY) { 331 mVelX += SHIP_ACCELERATION; 332 direction = RIGHT; 333 } 334 } 335 336 } 337 338 // std::cout << std::boolalpha << "keydown: " << keydown << "\n" << "keyup: " << keyup << "\n"; 339 340 } 357 void Ship::move() { 358 359 mPosX += mVelX; 360 shipCollBox.x = mPosX; 361 362 if ( mPosX < 0 || mPosX + SHIP_WIDTH > LEVEL_WIDTH || checkCollision( shipCollBox, wall1 ) || checkCollision( ship CollBox, wall2) || checkCollision( shipCollBox, wall3 ) ) { 363 mPosX -= mVelX; 364 shipCollBox.x = mPosX; 365 } 366 367 mPosY += mVelY; 368 shipCollBox.y = mPosY; 369 std::cout << "mVelY: " << mVelY << "\n" << "mPosY: " << mPosY << "\n"; 370 // SDL_Delay(100); 371 if ( mPosY < 0 || mPosY + SHIP_HEIGHT > LEVEL_HEIGHT || ( checkCollision( shipCollBox, wall1 ) || checkCollision( shipColl Box, wall2) || checkCollision( shipCollBox, wall3 ) ) ) { 372 mPosY -= mVelY; 373 shipCollBox.y = mPosY; 374 } 375 } 379 void Ship::render( int camX, int camY ) { 380 381 switch (direction) { 382 383 case UP: shipTextureUp.render( mPosX - camX, mPosY - camY ); break; 384 case DOWN: shipTextureDown.render(mPosX - camX, mPosY - camY ); break; 385 case LEFT: shipTextureLeft.render(mPosX - camX, mPosY - camY ); break; 386 case RIGHT: shipTextureRight.render(mPosX - camX, mPosY - camY ); break; 387 } 388 } 445 int main( int argc, char* args[] ) { 446 447 bool quit = false; 448 SDL_Event e; 449 Ship ship; 450 Projectile bullet; 451 SDL_Rect camera = { 0, 0, SCREEN_WIDTH, SCREEN_HEIGHT }; 452 init(); 453 loadMedia(); 454 455 while( !quit ) { 456 457 while ( SDL_PollEvent( &e ) !=0 ) { 458 if( e.type == SDL_QUIT ) { 459 quit = true; 460 } 461 462 ship.handleEvent( e ); 463 bullet.handleEvent( e, ship.getDirection(), ship.getPosX(), ship.getPosY() ); 464 } 465 466 bullet.update(); 467 ship.move(); 468 camera.x = ( ship.getPosX() + Ship::SHIP_WIDTH / 2 ) - SCREEN_WIDTH / 4; 469 camera.y = ( ship.getPosY() + Ship::SHIP_HEIGHT / 2 ) - SCREEN_HEIGHT / 4; 470 471 if (camera.x < 0) 472 camera.x = 0; 473 if (camera.y < 0) 474 camera.y = 0; 475 if (camera.x > LEVEL_WIDTH - camera.w) 476 camera.x = LEVEL_WIDTH - camera.w; 477 if (camera.y > LEVEL_HEIGHT - camera.h) 478 camera.y = LEVEL_HEIGHT - camera.h; 479 480 // Clear the screen 481 SDL_SetRenderDrawColor( gRenderer, 0xFF, 0xFF, 0xFF, 0xFF ); 482 SDL_RenderClear( gRenderer ); 483 484 bullet.render(); 485 backgroundTexture.render( 0, 0, &camera ); 486 ship.render( camera.x, camera.y ); 487 488 // Update screen 489 SDL_RenderPresent( gRenderer ); 490 SDL_Delay(10); 491 } 492 493 close(); 494 495 return 0; 496 } ``` 
\$\endgroup\$
2
  • \$\begingroup\$ I don't have time to write a more detailed answer for now, but you could take a look at the previous Q&A we have involving SDL_GetKeyboardState. Maybe you'll see a pattern emerging and get an idea on how you could approach the issue. \$\endgroup\$ Commented Sep 26, 2022 at 11:04
  • 1
    \$\begingroup\$ A good debugging tactic is to pretend you're the CPU, and walk through your code line by line, executing it in your head, or writing down the values of variables on each iteration. Imagine you press down enough times that mVelY is just a hair shy of SHIP_MAX_VELOCITY. Now walk through this function, pressing down again. What's the value of mVelY? Now walk through the loop one more time, this time pressing up. What does your code say should happen? \$\endgroup\$ Commented Sep 26, 2022 at 12:52

1 Answer 1

0
\$\begingroup\$

Try simplifying your if conditions, and enforce the max speed by clamping instead:

if ( keystate[SDL_SCANCODE_UP] ) { mVelY = std::max(mVelY - SHIP_ACCELERATION, -SHIP_MAX_VELOCITY); direction = UP; } if ( keystate[SDL_SCANCODE_DOWN] ) { mVelY = std::min(mVelY + SHIP_ACCELERATION, SHIP_MAX_VELOCITY); direction = DOWN; } 

This ensures you can accelerate to your max speed exactly, never exceeding it by any loose change, and it ensures you don't skip processing key presses if you're already travelling at max speed.

Bonus: shorter, simpler, less repetitive code with fewer branches.

There are other problems in this code though. You're handling an SDL_KEYDOWN event, but then applying effects from any keys that are currently held down. So if I press and hold say the UP button, then rapidly tap an unrelated key like Q, I'll get more vertical acceleration each time I press Q. That's not what you want.

Either read the event's keysym field to determine the single key that was pressed in this event, or move this code to your update loop to react to all keys equally, once per frame.

\$\endgroup\$

You must log in to answer this question.

Start asking to get answers

Find the answer to your question by asking.

Ask question

Explore related questions

See similar questions with these tags.