游戏手柄和操纵杆

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

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

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

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

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

bool init()
{//Initialization flagbool success = true;//Initialize SDLif( 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 imagesgArrowTexture.free();//Close game controllerSDL_JoystickClose( gGameController );gGameController = NULL;//Destroy window    SDL_DestroyRenderer( gRenderer );SDL_DestroyWindow( gWindow );gWindow = NULL;gRenderer = NULL;//Quit SDL subsystemsIMG_Quit();SDL_Quit();
}

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

//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 quitif( e.type == SDL_QUIT ){quit = true;}else if( e.type == SDL_JOYAXISMOTION ){//Motion on controller 0if( e.jaxis.which == 0 ){                        //X axis motionif( 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来检查操纵杆是否已经移动。"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 );

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

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

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

原文链接

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

SDL编程入门(19)游戏手柄和操纵杆相关推荐

  1. SDL编程入门(20)触力反馈

    触力反馈 我们知道了如何用SDL使用操纵杆,现在我们可以使用新的触觉API来使控制器震动. //带有触力反馈的游戏控制器1处理程序 SDL_Joystick* gGameController = NU ...

  2. SDL编程入门(27)碰撞检测

    碰撞检测 在游戏中,你经常需要判断两个物体是否相互撞击.对于简单的游戏来说,通常用边界框碰撞检测来完成. 碰撞框是检查两个对象之间碰撞的标准方法.当两个多边形没有分开时,它们就会发生碰撞. 这里我们有 ...

  3. SDL编程入门(28)每像素碰撞检测

    每像素碰撞检测 一旦你知道如何检查两个矩形之间的碰撞,你可以检查任何两个图像之间的碰撞,因为所有的图像都是由矩形构成的. 在电子游戏中,所有的东西都可以用矩形来做,甚至这个点: 没看到?我们把它放大: ...

  4. SDL编程入门(8)几何图形渲染

    几何图形渲染 除了新的纹理API,SDL还有新的基元渲染调用作为其渲染API的一部分.因此,如果你需要渲染一些基本的形状,而你又不想为它们创建额外的图形,SDL可以为你省力. bool loadMed ...

  5. 【SDL游戏编程入门第一卷】配置SDL环境

    一.前言 这段时间正好使用 SDL,所以打算开一个新的系列,作为经验分享 -- SDL 游戏编程入门. 这也是 AnnihilateSword 在此站的第一个系列,文中可能有许多不足,还请多多包涵,如 ...

  6. Pygame游戏编程入门笔记

    目录 1. Python游戏编程入门 2. 建立开发环境 3. 简单示例 4. 绘制不同形状 5. 事件监听举例 6. 用pygame打印文本 7. 键盘事件 8. 鼠标事件 9. 轮询键盘 10. ...

  7. c#对象集合去重_《C#编程入门》概览

    # [前言] # 01.[C#简介](<C#编程入门>01-C#简介) # 02.[集成开发环境](<C#编程入门> 02-C#集成开发环境) # 03.[初识C# 控制台输入 ...

  8. python编程入门经典教程-python编程入门经典

    第七章主要是文件操作相关,这么看用python---便,是一个不错的工具. <Python编程入门经典>主要内容:介绍用于存储和操作数据的变量的概念:讨论用于读写数据的文件和输入/输出:总 ...

  9. 脑残式网络编程入门(三):HTTP协议必知必会的一些知识

    为什么80%的码农都做不了架构师?>>>    本文原作者:"竹千代",原文由"玉刚说"写作平台提供写作赞助,原文版权归"玉刚说&q ...

最新文章

  1. c++ resizereserve
  2. rust军用船指令_RUST物品指令清单(英文版)
  3. 命名实体识别——日期识别
  4. 如何在移动端复制到剪切板
  5. 护理方面关于人工智能的构想_如何提出惊人的AI,ML或数据科学项目构想。
  6. 详细js读取execl内容并展示
  7. Rolling cURL: PHP并发最佳实践
  8. [导入]Asp.net 2.0 自定义控件开发[创建自定义浮动菜单FloadMenu控件][示例代码下载]...
  9. sshpass简介及安装
  10. 66岁比尔盖茨突然宣布离婚!27年前与下属恋爱修成正果,现在“无法共同成长”,分割8000亿财产...
  11. 汽车软件常用名称缩写
  12. 【智能无线小车系列九】在树莓派上使用USB摄像头
  13. QQ文件保险柜与Truecrypt之对比.
  14. 系统创建定时执行任务bat批处理删除指定N天前文件夹的文件
  15. Java利用libreOffice(jodconverter)将office(ppt,Excel,word,text)文档转换成pdf
  16. AIGC时代,推荐几个高质量的人工智能公众号!
  17. Matlab:向图中添加注释
  18. 用Python分析了7000多个交易日的涨跌数据,看看A股有没有“黑色星期五”
  19. python支付宝蚂蚁森林_Python+appium自动化实例(一):使用Python3+appium实现自动收取支付宝蚂蚁森林能量...
  20. 微众银行java开发待遇如何,内含福利

热门文章

  1. Android 安卓动画 补间动画 - 透明/渐变 动画
  2. 一款强大的路由器都能干些什么有趣的事?
  3. layui form表单提交无法触发问题。
  4. android 读取手机mp3,Android四大组件之ContentResolver读取手机音乐文件
  5. 预渲染插件prerender-spa-plugin使用总结
  6. 常用获取日期相关方法
  7. Group Norm 学习笔记
  8. The Open Group 25周年全球盛典|完整议程抢先看,庆典主场一周倒计时
  9. 嘀嗒拼车成为全国首家获得政府备案的合乘平台
  10. PaperReading:《Rethinking Computer-aided Tuberculosis Diagnosis》