1

I am making a game where a nozzle of a tank rotates around when space is pressed to shoot enemies. However, right in the beginning when the space is pressed, it seems to stop for a few milliseconds and then continues without any problems. How can I make it so that the rotations is smooth and consistent as soon as the space is pressed, right from the start? Here is a minimal reproducible example:

#include "SDL.h"
#include <iostream>

class Nozzle
{
public:
    void draw(SDL_Renderer* renderer, int cx, int cy, int l)
    {
        float x = ((float)cos(angle) * l) + cx;
        float y = ((float)sin(angle) * l) + cy;
        SDL_RenderDrawLine(renderer, cx, cy, (int)x, (int)y);
    }

    void plusAngle(float a)
    {
        angle += a;
    }

private:
    float angle = 0.0f;
};


int main(int argc, char* argv[])
{
    SDL_Window* window = SDL_CreateWindow("RGame", SDL_WINDOWPOS_CENTERED, SDL_WINDOWPOS_CENTERED, 1200, 600, false);
    SDL_Renderer* renderer = SDL_CreateRenderer(window, -1, 0);
    SDL_Event event;
    Nozzle nozzle;
    bool running = true;

    while (running)
    {
        while (SDL_PollEvent(&event))
        {
            if (event.type == SDL_QUIT)
                running = false;
            if (event.type == SDL_KEYDOWN)
            {
                if (event.key.keysym.sym == SDLK_SPACE)
                    nozzle.plusAngle(0.1f);
            }
        }

        SDL_SetRenderDrawColor(renderer, 255, 255, 255, 255);
        SDL_RenderClear(renderer);
        SDL_SetRenderDrawColor(renderer, 0, 0, 0, 0);
        nozzle.draw(renderer, 600, 300, 70);
        
        SDL_RenderPresent(renderer);
        
    }

    SDL_DestroyWindow(window);
    SDL_Quit();

    return 1;
}
  • Profile. Find out where the delays are by profiling. No use in guessing (that's a waste of your time). You can also use "benchmarking". Search the internet for "C++ profile" and add your IDE or compiler. – Thomas Matthews Oct 02 '20 at 23:00
  • Long time ago, in the present galaxy, when computers were slow, there were multiple "frame" buffers. The processor would draw into one frame buffer while the hardware was drawing another. Multiple buffers would be used to smooth out the percepted speed. – Thomas Matthews Oct 02 '20 at 23:03
  • @ThomasMatthews -:) Thank you for the suggestion. I will probably look into how to do what you are suggesting in the future since I don't know because I am a beginner. But I don't think delay is the problem here. There is probably something wrong with the way I am reading keys because the result is a same (a little delay and continues) even when I don't render anything and just print "nozzle supposed to rotate" –  Oct 02 '20 at 23:09
  • 1
    Are you just seeing keyboard autorepeat? – Davis Herring Oct 03 '20 at 03:35
  • Possible duplicate of [c++ - SDL Smoother movement in game - Stack Overflow](https://stackoverflow.com/questions/34780013/sdl-smoother-movement-in-game) – user202729 Oct 03 '20 at 07:53

1 Answers1

1
if (event.type == SDL_KEYDOWN)
{
    if (event.key.keysym.sym == SDLK_SPACE)
        nozzle.plusAngle(0.1f);
}

This is not how you do controls in a game.

If you open a text editor and hold a key, you'll see one letter being typed, then, after a delay, a steady stream of the same repeated letter. And SDL does the same thing, it gives you fake repeated "key down" events in this manner. This is normally used for editing text, not for game controls. (Those repeated events are marked by event.key.repeat == true).

What you should do is to create something like bool space_key_down, set it to true when you get SDL_KEYDOWN for the space key, and to false when you get SDL_KEYUP for the same key. Then, outside of the event loop, if the variable is set, you rotate your nozzle.

Or you can use SDL_GetKeyboardState. SDL does this thing automatically for every key, and you can access the list of flags it maintains using this function.

Also, while we're at it, you normally don't want to use keycodes (.sym == SDLK_SPACE) for game controls. Prefer scancodes (.scancode == SDL_SCANCODE_SPACE). The difference only becomes apparent on exotic layouts (e.g. AZERTY): keycodes represent the letters printed on the keycaps, while scancodes represent physical key locations. For example, on AZERTY you want to use ZQSD instead of WASD. If you use scancodes, it will happen automatically (SDL_SCANCODE_W will represent Z, and so on).


scaling rotation with frame-rate isn't really what I am looking for. Its a different problem

You need to solve this problem too. If you don't want the rotation speed to depend on FPS (bad thing), you must either mutliply the rotation angle by the frame length (it works, but it's easy to make mistakes this way), or make sure your game logic runs the fixed amount of times per second regardless of the FPS (I prefer this solution). See Fix Your Timestep!.

HolyBlackCat
  • 78,603
  • 9
  • 131
  • 207