如何在 sdl2 中正确检测按键按下和释放

How to correctly detect key press and release in sdl2

本文关键字:释放 检测 sdl2      更新时间:2023-10-16

我的完整代码 -

#include <SDL.h>
#include <SDL_opengl.h>
#include <GLGLU.h>
#include <fstream>
using namespace std;

int index = 0;
int speed = 0;
int frames = 0;
int lasttime = 0;
int mousex = 0;
int mousey = 0;
bool postRedraw = true;
int screenWidth = 640;
int screenHeight = 480;
float screenAspect = screenWidth/screenHeight;
bool init();
bool initGL();
void handleKeys( unsigned char key, int x, int y );
void update();
void render();
void close();
void Initialize();
void handleEvents();

ofstream logFile;
SDL_Window* gWindow = NULL;
bool isRunning = true;
SDL_GLContext gContext;
float xpos = 0.0;
float ypos = 0.0;
float zpos = 0.0;

void Initialize()
{
    gluPerspective(60.0f, screenAspect, 1.0, 400.0);
    glEnable(GL_COLOR_MATERIAL);
    glEnable(GL_NORMALIZE);
    glTranslatef(0.0f, 0.0f, -5.0f);
    glFrontFace(GL_CCW);
    glEnable(GL_LIGHT0);
}

void render()
{
    glTranslatef(xpos, ypos, zpos);
    glClear(GL_COLOR_BUFFER_BIT | GL_DEPTH_BUFFER_BIT);
    glColor3f(1.0, 0.0, 0.0);
    glBegin(GL_TRIANGLES);
        glVertex3f(-1.0f,0.0f,-1.0f);
        glVertex3f(0.0f, 1.0f, -1.0f);
        glVertex3f(0.0f, 2.0f, -2.0f);
    glEnd();
    postRedraw = true;
}

void handleEvents()
{
    const Uint8* keystates = SDL_GetKeyboardState(NULL);
    if(keystates[SDL_GetScancodeFromKey(SDLK_w)])
    {
        zpos += 0.01;
    }
    if(keystates[SDL_GetScancodeFromKey(SDLK_s)])
    {
        zpos -= 0.01;
    } else {
    }
}
bool init()
{
    bool success = true;
    if( SDL_Init( SDL_INIT_VIDEO ) < 0 )
    {
        logFile<<"SDL could not initialize! SDL Error: "<<SDL_GetError()<<endl;
        success = false;
    }
    else
    {
        SDL_GL_SetAttribute( SDL_GL_CONTEXT_MAJOR_VERSION, 2 );
        SDL_GL_SetAttribute( SDL_GL_CONTEXT_MINOR_VERSION, 1 );
        gWindow = SDL_CreateWindow( "SDL Tutorial", SDL_WINDOWPOS_UNDEFINED, SDL_WINDOWPOS_UNDEFINED, screenWidth, screenHeight, SDL_WINDOW_OPENGL | SDL_WINDOW_RESIZABLE );
        if( gWindow == NULL )
        {
            logFile<<"Window could not be created! SDL Error: "<<SDL_GetError()<<endl;
            success = false;
        }
        else
        {
            gContext = SDL_GL_CreateContext( gWindow );
            if( gContext == NULL )
            {
                logFile<<"OpenGL context could not be created! SDL Error: "<<SDL_GetError()<<endl;
                success = false;
            }
            else
            {
                if( SDL_GL_SetSwapInterval( 1 ) < 0 )
                {
                    logFile<<"Warning: Unable to set VSync! SDL Error: "<<SDL_GetError()<<endl;
                }
                if( !initGL() )
                {
                    logFile<<"Unable to initialize OpenGL!"<<endl;
                    success = false;
                }
            }
        }
    }
    logFile.open("log.txt");
    if(logFile.is_open())
    {
        success = true;
    } else {
        success = false;
    }
    return success;
}
bool initGL()
{
    bool success = true;
    GLenum error = GL_NO_ERROR;
    glMatrixMode( GL_PROJECTION );
    glLoadIdentity();
    error = glGetError();
    if( error != GL_NO_ERROR )
    {
        logFile<<"Error initializing OpenGL! "<<gluErrorString( error )<<endl;
        success = false;
    }
    glMatrixMode( GL_MODELVIEW );
    glLoadIdentity();
    glEnable(GL_CULL_FACE);
    glEnable(GL_DEPTH_TEST);
    error = glGetError();
    if( error != GL_NO_ERROR )
    {
        logFile<<"Error initializing OpenGL! "<<gluErrorString( error )<<endl;
        success = false;
    }
    glClearColor( 0.f, 0.f, 0.f, 1.f );
    error = glGetError();
    if( error != GL_NO_ERROR )
    {
        logFile<<"Error initializing OpenGL! "<<gluErrorString( error );
        success = false;
    }
    return success;
}

void close()
{
    logFile.close();
    SDL_DestroyWindow( gWindow );
    gWindow = NULL;
    SDL_Quit();
}
int main( int argc, char* args[] )
{
    if( !init() )
    {
        logFile<<"Failed to initialize!"<<endl;
    }
    else
    {
        SDL_Event event;
        Initialize();
        lasttime = SDL_GetTicks();
        while(isRunning)
        {
            while( SDL_PollEvent( &event ) != 0 )
            {
                if(event.type == SDL_QUIT)
                {
                    isRunning = false;
                } else if(event.type == SDL_MOUSEMOTION) {
                    SDL_GetMouseState(&mousex, &mousey);
                } else if(event.type == SDL_MOUSEBUTTONDOWN) {
                    SDL_GetMouseState(&mousex, &mousey);
                } else if(event.type == SDL_MOUSEBUTTONUP) {
                    SDL_GetMouseState(&mousex, &mousey);
                }
            }
            handleEvents();
            if(postRedraw)
            {
                postRedraw = false;
                render();
                SDL_GL_SwapWindow( gWindow );
            }
            if((SDL_GetTicks()-lasttime)>=1000)
            {
                lasttime = SDL_GetTicks();
                speed = frames;
                logFile<<speed<<endl;
                frames = 0;
            } else {
                frames++;
            }
        }
    }
    close();
    return 0;
}

上面的代码仅用于测试,我有问题的简约代码是 -

void handleEvents()
{
    const Uint8* keystates = SDL_GetKeyboardState(NULL);
    if(keystates[SDL_GetSancodeFromKey(SDLK_w)]) {
        zpos += 0.01;
    }
    if(keystates[SDL_GetScancodeFromKey(SDLK_s)])
    {
        zpos -= 0.01;
    } else {
    }
}

预期: 绘制的 trangle 将在按下 W/S 键时向后移动。

输出: 即使释放了钥匙,三角形也会继续向所需的方向移动。

随着时间的推移,你会累积矩阵的变化。 glTranslatef 通过平移修改当前矩阵。下一帧它再次修改它。再说一遍....

你用glLoadIdentity()调用重置矩阵。请注意,它会修改当前选定的矩阵,并将撤消您在Initialize中所做的矩阵更改(至少您在此处glTranslatef - 透视应该转到GL_PROJECTION矩阵,您尚未完成)。