首页
学习
活动
专区
工具
TVP
发布
社区首页 >专栏 >(译)SDL编程入门(19)游戏手柄和操纵杆

(译)SDL编程入门(19)游戏手柄和操纵杆

作者头像
arcticfox
发布2021-01-06 11:42:21
1.7K0
发布2021-01-06 11:42:21
举报

游戏手柄和操纵杆

就像[鼠标输入]和[键盘输入]一样,SDL也有能力读取来自操纵杆/游戏手柄/游戏控制器的输入。在本教程中,我们将根据操纵杆的输入使箭头旋转。

//模拟手柄死区
const int JOYSTICK_DEAD_ZONE = 8000;

SDL处理游戏控制器上的模拟杆的方式是,它将其位置转换为-32768和32767之间的数字。这意味着一个轻敲可以报告一个1000+的位置。我们想忽略轻敲,所以我们想创建一个死区,在这个死区中,来自操纵杆的输入被忽略。这就是我们定义这个常数的原因,我们稍后会看到它是如何工作的。

//游戏控制器1处理机
SDL_Joystick* gGameController = NULL;

游戏控制器的数据类型是SDL_Joystick[1]。在这里,我们声明全局操纵杆手柄,我们将使用它来与操纵杆进行交互。

bool init()
{
    //Initialization flag
    bool success = true;

    //Initialize SDL
    if( SDL_Init( SDL_INIT_VIDEO | SDL_INIT_JOYSTICK ) < 0 )
    {
        printf( "SDL could not initialize! SDL Error: %s\n", SDL_GetError() );
        success = false;
    }

这一点很重要。

到目前为止,我们一直只初始化视频,以便我们可以渲染到屏幕上。现在我们需要初始化操纵杆子系统,否则从操纵杆读取数据将无法工作。

//将纹理过滤设置为线性
if( !SDL_SetHint( SDL_HINT_RENDER_SCALE_QUALITY, "1" ) )
{
    printf( "Warning: Linear texture filtering not enabled!" );
}

//检查操纵杆
if( SDL_NumJoysticks() < 1 )
{
    printf( "Warning: No joysticks connected!\n" );
}
else
{
    //加载操纵杆
    gGameController = SDL_JoystickOpen( 0 );
    if( gGameController == NULL )
    {
        printf( "Warning: Unable to open game controller! SDL Error: %s\n", SDL_GetError() );
    }
}

在初始化操纵杆子系统后,我们要打开我们的操纵杆。首先我们调用SDL_NumJoysticks来检查是否至少有一个操纵杆连接。如果有,我们调用SDL_JoystickOpen来打开索引0的操纵杆。操纵杆打开后,现在它将向SDL事件队列报告事件。

void close()
{
    //Free loaded images
    gArrowTexture.free();

    //Close game controller
    SDL_JoystickClose( gGameController );
    gGameController = NULL;

    //Destroy window    
    SDL_DestroyRenderer( gRenderer );
    SDL_DestroyWindow( gWindow );
    gWindow = NULL;
    gRenderer = NULL;

    //Quit SDL subsystems
    IMG_Quit();
    SDL_Quit();
}

完成操纵杆的操作后,请使用SDL_JoystickClose[2]将其关闭。

//Main loop flag
bool quit = false;

//Event handler
SDL_Event e;

//正常化方向
int xDir = 0;
int yDir = 0;

在这个演示中,我们要跟踪x和y的方向。如果x等于-1,则操纵杆的x位置指向左边。如果是+1,则x位置指向右。操纵杆的y位置有正的为上,负的为下,所以y=+1为上,y=-1为下。如果x或y为0,说明它在死区,处于中心位置。

//Handle events on queue
while( SDL_PollEvent( &e ) != 0 )
{
    //User requests quit
    if( e.type == SDL_QUIT )
    {
        quit = true;
    }
    else if( e.type == SDL_JOYAXISMOTION )
    {
        //Motion on controller 0
        if( e.jaxis.which == 0 )
        {                        
            //X axis motion
            if( e.jaxis.axis == 0 )
            {
                //死区左侧
                if( e.jaxis.value < -JOYSTICK_DEAD_ZONE )
                {
                    xDir = -1;
                }
                //死区右侧
                else if( e.jaxis.value > JOYSTICK_DEAD_ZONE )
                {
                    xDir =  1;
                }
                else
                {
                    xDir = 0;
                }
            }

在我们的事件循环中,通过检查SDL_JoyAxisEvent[3]来检查操纵杆是否已经移动。"which"变量表示轴的运动来自哪个控制器,这里我们检查事件来自操纵杆 0。

接下来我们要检查它是x方向的运动还是y方向的运动,"axis"变量表示。通常情况下,0轴是x轴。

"value"变量表示模拟杆在轴上的什么位置。如果x位置小于死区,则方向设置为负。如果位置大于死区,则方向设置为正。如果在死区,则方向设置为0。

//Y轴运动
else if( e.jaxis.axis == 1 )
{
    //死区下方
    if( e.jaxis.value < -JOYSTICK_DEAD_ZONE )
    {
        yDir = -1;
    }
    //死区上方
    else if( e.jaxis.value > JOYSTICK_DEAD_ZONE )
    {
        yDir =  1;
    }
    else
    {
        yDir = 0;
    }
}
}
}
}

在这里,我们再次对y轴(用轴ID 1标识)执行相同的操作。

//Clear screen
SDL_SetRenderDrawColor( gRenderer, 0xFF, 0xFF, 0xFF, 0xFF );
SDL_RenderClear( gRenderer );

//Calculate angle
double joystickAngle = atan2( (double)yDir, (double)xDir ) * ( 180.0 / M_PI );

//Correct angle
if( xDir == 0 && yDir == 0 )
{
    joystickAngle = 0;
}

在我们渲染箭头之前,我们需要计算出箭头的角度。我们使用cmath函数atan2进行此操作,该函数代表反正切2,即AKA反正切2。

对于熟悉三角函数的人来说,这基本上是反正切函数,其中包含一些附加代码,这些附加代码考虑了值来自哪个象限。

对于只熟悉几何的人来说,只要知道您给它的y位置和x位置,它就会为您提供以弧度为单位的角度。SDL想要以度为单位的旋转角度,所以我们必须将弧度转换成度,将它乘以Pi的180。

当x和y位置均为0时,我们可以得到一个无意义的角度,因此我们将该值校正为等于0。

//Render joystick 8 way angle
gArrowTexture.render( ( SCREEN_WIDTH - gArrowTexture.getWidth() ) / 2, ( SCREEN_HEIGHT - gArrowTexture.getHeight() ) / 2, NULL, joystickAngle );

//Update screen
SDL_RenderPresent( gRenderer );

最后我们将箭头呈现在屏幕上旋转。

还有其他的操纵杆事件,比如按钮按下[4]、pov hats[5]和插入或移除控制器[6]。它们都相当简单,你应该可以通过查看文档和实验来了解它们。

在 这里[7]下载本教程的媒体和源代码。

原文链接[8]

「关注我的公众号:编程之路从0到1」

Reference

[1]

SDL_Joystick: http://wiki.libsdl.org/CategoryJoystick

[2]

SDL_JoystickClose: http://wiki.libsdl.org/SDL_JoystickClose

[3]

SDL_JoyAxisEvent: http://wiki.libsdl.org/SDL_JoyAxisEvent

[4]

按钮按下: http://wiki.libsdl.org/SDL_JoyButtonEvent

[5]

pov hats: http://wiki.libsdl.org/SDL_JoyHatEvent

[6]

插入或移除控制器: http://wiki.libsdl.org/SDL_JoyDeviceEvent

[7]

这里: http://www.lazyfoo.net/tutorials/SDL/19_gamepads_and_joysticks/19_gamepads_and_joysticks.zip

[8]

原文链接: http://www.lazyfoo.net/tutorials/SDL/19_gamepads_and_joysticks/index.php

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

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

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

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

评论
登录后参与评论
0 条评论
热度
最新
推荐阅读
目录
  • 游戏手柄和操纵杆
    • Reference
    领券
    问题归档专栏文章快讯文章归档关键词归档开发者手册归档开发者手册 Section 归档