前往小程序,Get更优阅读体验!
立即前往
首页
学习
活动
专区
工具
TVP
发布
社区首页 >专栏 >(译)SDL编程入门(4)按键操作

(译)SDL编程入门(4)按键操作

作者头像
arcticfox
发布2020-09-24 15:28:39
9010
发布2020-09-24 15:28:39
举报

按键操作

点X关闭出窗口只是SDL能够处理的事件之一。另一种在游戏中大量使用的输入方式是键盘。在本教程中,我们将根据您所按的键来使不同的图像出现。

代码语言:javascript
复制
//按键表面常量
enum KeyPressSurfaces
{
    KEY_PRESS_SURFACE_DEFAULT,
    KEY_PRESS_SURFACE_UP,
    KEY_PRESS_SURFACE_DOWN,
    KEY_PRESS_SURFACE_LEFT,
    KEY_PRESS_SURFACE_RIGHT,
    KEY_PRESS_SURFACE_TOTAL
};

在源代码的顶部,我们声明了一个不同表面的枚举。枚举是一种做符号常量的简便方法,而不必写const int KEY_PRESS_SURFACE_DEFAULT = 0; const int KEY_PRESS_SURFACE_UP = 1; const int KEY_PRESS_SURFACE_DOWN = 2; 等等。它们默认从0开始计数,你每声明一个枚举就自动加1。这意味着KEY_PRESS_SURFACE_DEFAULT 是0,KEY_PRESS_SURFACE_UP 是1,KEY_PRESS_SURFACE_DOWN 是2,KEY_PRESS_SURFACE_LEFT 是3,KEY_PRESS_SURFACE_RIGHT 是4,KEY_PRESS_SURFACE_TOTAL 是5,可以给它们明确的整数值,但我们在这里不涉及这个问题。在Google上快速搜索一下枚举,应该可以涵盖这些内容。

初级程序员有一个坏习惯,就是使用数字代替符号常量。例如他们会有1个平均的主菜单,2个平均的选项等,这对于小程序来说是很好的。当你要处理数千行代码时(视频游戏通常就是这样),有一行写着 if( option == 1 )的代码会比使用 if( option == MAIN_MENU )产生更多的麻烦。

代码语言:javascript
复制
//Starts up SDL and creates window
bool init();

//Loads media
bool loadMedia();

//释放媒体并关闭SDL
void close();

//加载单个图像
SDL_Surface* loadSurface( std::string path );

//我们要渲染的窗口
SDL_Window* gWindow = NULL;
    
//窗口所包含的表面
SDL_Surface* gScreenSurface = NULL;

//按键对应的图片
SDL_Surface* gKeyPressSurfaces[ KEY_PRESS_SURFACE_TOTAL ];

//当前显示的图像
SDL_Surface* gCurrentSurface = NULL;

除了我们常用的函数原型,我们还有一个新的函数叫loadSurface。有一个普遍的规则,如果你复制/粘贴代码,你就做错了什么。与其每次都复制/粘贴加载代码,不如用一个函数来处理。

对于这个特定的程序来说,重要的是我们有一个指向SDL表面的指针数组,称为gKeyPressSurfaces,以包含我们将使用的所有图像。根据用户按下的键,我们将把 gCurrentSurface (这是将被渲染到屏幕上的图像) 设置为这些表面中的一个。

代码语言:javascript
复制
SDL_Surface* loadSurface( std::string path ){
    //在指定路径加载图像
    SDL_Surface* loadedSurface = SDL_LoadBMP( path.c_str() );
    if( loadedSurface == NULL )
    {
        printf( "Unable to load image %s! SDL Error: %s\n", path.c_str(), SDL_GetError() );
    }

    return loadedSurface;
}

这里是loadSurface函数,它可以加载图像,并在出现问题时报告错误。它和之前的功能差不多,但是把图像加载和错误报告都包含在一个函数中,这样就很容易添加和调试图像加载。

由于新的C++程序员经常问我这个问题,所以这个函数不会泄漏内存。它确实会分配内存来加载一个新的SDL曲面,并在不释放所分配的内存的情况下返回它,但是分配表面并立即deallocating它有什么意义呢?这个函数所做的是加载表面并返回新加载的表面,这样调用这个函数的人就可以在使用完这个曲面后再重新分配它。在这个程序中,加载的表面在close函数中被deallocated。

代码语言:javascript
复制
bool loadMedia(){
    //加载成功标志
    bool success = true;

    //加载默认表面
    gKeyPressSurfaces[ KEY_PRESS_SURFACE_DEFAULT ] = loadSurface( "04_key_presses/press.bmp" );
    if( gKeyPressSurfaces[ KEY_PRESS_SURFACE_DEFAULT ] == NULL )
    {
        printf( "Failed to load default image!\n" );
        success = false;
    }

    //加载up对应的表面
    gKeyPressSurfaces[ KEY_PRESS_SURFACE_UP ] = loadSurface( "04_key_presses/up.bmp" );
    if( gKeyPressSurfaces[ KEY_PRESS_SURFACE_UP ] == NULL )
    {
        printf( "Failed to load up image!\n" );
        success = false;
    }

    //加载down对应的表面
    gKeyPressSurfaces[ KEY_PRESS_SURFACE_DOWN ] = loadSurface( "04_key_presses/down.bmp" );
    if( gKeyPressSurfaces[ KEY_PRESS_SURFACE_DOWN ] == NULL )
    {
        printf( "Failed to load down image!\n" );
        success = false;
    }

    //加载left对应的表面
    gKeyPressSurfaces[ KEY_PRESS_SURFACE_LEFT ] = loadSurface( "04_key_presses/left.bmp" );
    if( gKeyPressSurfaces[ KEY_PRESS_SURFACE_LEFT ] == NULL )
    {
        printf( "Failed to load left image!\n" );
        success = false;
    }

    //加载right对应的表面
    gKeyPressSurfaces[ KEY_PRESS_SURFACE_RIGHT ] = loadSurface( "04_key_presses/right.bmp" );
    if( gKeyPressSurfaces[ KEY_PRESS_SURFACE_RIGHT ] == NULL )
    {
        printf( "Failed to load right image!\n" );
        success = false;
    }

    return success;
}

在这里的loadMedia函数中,我们加载了所有要渲染到屏幕上的图片。

代码语言:javascript
复制
   //Main loop flag
            bool quit = false;

            //Event handler
            SDL_Event e;

            //设置默认的当前表面
            gCurrentSurface = gKeyPressSurfaces[ KEY_PRESS_SURFACE_DEFAULT ];

            //While application is running
            while( !quit )
            {
       //Handle events on queue
                while( SDL_PollEvent( &e ) != 0 )
                {
                    //用户请求退出
                    if( e.type == SDL_QUIT )
                    {
                        quit = true;
                    }
                    //用户按下一个键
                    else if( e.type == SDL_KEYDOWN )
                    {
                        //根据按键选择表面
                        switch( e.key.keysym.sym )
                        {
                            case SDLK_UP:
                            gCurrentSurface = gKeyPressSurfaces[ KEY_PRESS_SURFACE_UP ];
                            break;

                            case SDLK_DOWN:
                            gCurrentSurface = gKeyPressSurfaces[ KEY_PRESS_SURFACE_DOWN ];
                            break;

                            case SDLK_LEFT:
                            gCurrentSurface = gKeyPressSurfaces[ KEY_PRESS_SURFACE_LEFT ];
                            break;

                            case SDLK_RIGHT:
                            gCurrentSurface = gKeyPressSurfaces[ KEY_PRESS_SURFACE_RIGHT ];
                            break;

                            default:
                            gCurrentSurface = gKeyPressSurfaces[ KEY_PRESS_SURFACE_DEFAULT ];
                            break;
                        }
                    }
                }

这是我们的事件循环。正如你所看到的,我们像之前的教程一样处理关闭窗口,然后我们处理SDL_KEYDOWN事件。当你按下键盘上的一个键时,这个事件就会发生。

SDL事件[1]里面有一个SDL Keyboard事件[2],它包含了按键事件的信息。在这个事件中,有一个SDL Keysym[3],它包含了被按下的键的信息。这个Keysym包含了SDL Keycode[4],它标识了被按下的键。

正如你所看到的,这段代码的作用是根据被按下的键来设置表面。如果您想知道其他键的键码是什么,请查阅SDL文档。

代码语言:javascript
复制
//Apply the current image
SDL_BlitSurface( gCurrentSurface, NULL, gScreenSurface, NULL );
            
//Update the surface
 SDL_UpdateWindowSurface( gWindow );

在处理完按键并设置好表面后,我们将选定的表面显示到屏幕上。

参考资料

[1]

SDL事件: https://wiki.libsdl.org/SDL_Event?highlight=%28SDL_Event%29

[2]

SDL Keyboard事件: https://wiki.libsdl.org/SDL_KeyboardEvent

[3]

SDL Keysym: https://wiki.libsdl.org/SDL_Keysym

[4]

SDL Keycode: https://wiki.libsdl.org/SDL_Keycode

[5]

这里: http://www.lazyfoo.net/tutorials/SDL/04_key_presses/04_key_presses.zip

[6]

原文链接: http://www.lazyfoo.net/tutorials/SDL/04_key_presses/index.php

本文参与 腾讯云自媒体分享计划,分享自微信公众号。
原始发表:2020-09-20,如有侵权请联系 cloudcommunity@tencent.com 删除

本文分享自 编程之路从0到1 微信公众号,前往查看

如有侵权,请联系 cloudcommunity@tencent.com 删除。

本文参与 腾讯云自媒体分享计划  ,欢迎热爱写作的你一起参与!

评论
登录后参与评论
0 条评论
热度
最新
推荐阅读
目录
  • 按键操作
    • 参考资料
    相关产品与服务
    云开发 CloudBase
    云开发(Tencent CloudBase,TCB)是腾讯云提供的云原生一体化开发环境和工具平台,为200万+企业和开发者提供高可用、自动弹性扩缩的后端云服务,可用于云端一体化开发多种端应用(小程序、公众号、Web 应用等),避免了应用开发过程中繁琐的服务器搭建及运维,开发者可以专注于业务逻辑的实现,开发门槛更低,效率更高。
    领券
    问题归档专栏文章快讯文章归档关键词归档开发者手册归档开发者手册 Section 归档