JoyStick游戏杆编程实践

您所在的位置:网站首页 飞行摇杆使用方法 JoyStick游戏杆编程实践

JoyStick游戏杆编程实践

2023-08-14 12:26| 来源: 网络整理| 查看: 265

概述

最近突然对如何编程读取游戏手柄输入比较感兴趣。所以上网找了找相关的资料,发现没有什么简单明了的教程,所以在此将收集到跟joystick游戏杆编程相关资料整理一下,方便大家参考使用。

JoyStick简介

先给出JoyStick的维基百科介绍 维基百科词条:JoyStick 按照维基百科中的介绍,JoyStick事实上就是电子输入装置,可以输入按键,方向等数据。可以用来控制电子游戏,也可以用来控制飞行器、汽车或者其他装置等。事实上,一般的JoyStick游戏手柄或者摇杆的输入都有遵循的标准,这样我们就可以使用统一的joystick接口来读取对应的输入数据。 在我的认识中,至少我们玩飞行模拟游戏所使用的飞行摇杆,以及我们玩PS4/Xbox等游戏所使用的USB游戏手柄都属于joystick装置的。我们可以使用统一的编程接口来读取输入。

本文的目标

本文的目的是简单介绍游戏手柄输入的读取方法,并给出一些简单快捷的joystick编程方法。

JoyStick编程方法 1. 基于底层操作直接操作游戏手柄

有一篇文章Windows下对游戏杆编程也列出列了几个游戏杆的使用方法,其中第一个和第二个就是通过驱动开发接口DDK或者通过读取USB设备直接访问。只能说这样做的难度不小,而且未必能够达到我们想要的目标。喜欢探索或者编程大触可以尝试一下。

2. 使用Windows API

在Windows系统下,使用VS写读取joystick的C/C++代码是非常容易的,此处给出一篇参考文章:JoyStick编程学习笔记。 给出一段测试读取游戏手柄输入的代码如下:

#include #include #include #include //添加joystick操作api的支持库 #include #pragma comment(lib, "Winmm.lib") int main(int argc, char* argv[]) { JOYINFO joyinfo;//定义joystick信息结构体 JOYINFOEX joyinfoex; joyinfoex.dwSize = sizeof(JOYINFOEX); joyinfoex.dwFlags = JOY_RETURNALL; while(1) { //读取手柄信息 UINT joyNums; joyNums = joyGetNumDevs(); // printf("当前手柄数量:%d \n",joyNums); if (joyNums>=1) { MMRESULT joyreturn = joyGetPosEx(JOYSTICKID1, &joyinfoex); if(joyreturn == JOYERR_NOERROR) { printf("0x%09d ", joyinfoex.dwXpos); printf("0x%09d ", joyinfoex.dwYpos); //printf("0x%09X ", joyinfoex.dwZpos); //printf("0x%09X ", joyinfoex.dwPOV); //printf("0x%09X ", joyinfoex.dwButtons); printf("\n"); }else { switch(joyreturn) { case JOYERR_PARMS : printf("bad parameters\n"); break; case JOYERR_NOCANDO : printf("request not completed\n"); break; case JOYERR_UNPLUGGED : printf("joystick is unplugged\n"); break; default: printf("未知错误\n"); break; } } } if(kbhit()) break; Sleep(300); } return 0; }

上述代码实现的效果是在命令行窗口中循环读取游戏手柄设备输入 ,并将读取到到数据打印出来。如果有游戏手柄插入,并按下对应的按键,则对应的打印数据就会发生变化。 测试时用的是我之前买的一个老旧的杂牌游戏手柄。在测试代码是否有效时遇到的非常多的问题:

首先,不管我插不插游戏手柄,joyGetNumDevs的返回值始终是16,后来查了些资料:在C++ Builder中使用游戏操纵杆说如果电脑有游戏端口,那么joyGetNumDevs 返回值通常为16。。。但是也没告诉我怎样判断游戏手柄是不是插入了,所以只能通过joyGetPosEx的返回值来进行判断了。第二个问题是使用上述代码编译出来的exe运行时,在不同的电脑和系统上读取游戏手柄输入的效果时灵时不灵。测试环境就是win10,win7和xp,分别测试了使用vc6.0以及vs2010编译运行,总之测试结果达不到编译一个exe然后到其他平台使用的效果。 3. 使用Directlnput或者XInput技术

DirectInput是微软提供的一个输入设备的API,用于结合键盘、鼠标、摇杆,或其它的游戏控制器。如果是想要在Windows平台下使用摇杆的,可以参考Directlnput和XInput这两篇文章。 如果是游戏开发,可能对操纵杆或者输入设备的操作比较复杂,而且对兼容性要求较高,而DirectInput和XInput提供的接口比较全面,而且和direct X的技术结合紧密。所以这个技术应该是开发Windows平台游戏的不二选择了。

4. 使用joystick接口库

以前曾经用过一个windwos平台上的JoyStick库,使用这个库操作joystick很是方便。可是忘记了这个库叫什么。不过我在github上找了找,还真找到了一些joystick库,先给出两个结果:

SDL-mirror/SDLTasssadar/libenjoy

SDL全称是Simple DirectMedia Layer,是一个很全面的跨平台媒体/游戏开发库,但是我没精力折腾这些,所以转向了libenjoy。这是一个简单的JoyStick操作接口库,使用C语言实现,可以与任何C/C++应用程序一起使用,而且是跨平台的,可以说非常方便。在此给出libenjoy工程中的测试例程和libenjoy库的源代码与测试工程:

//测试例程 #include #ifdef __linux #include #else #include #endif //包含libenjoy库的头文件 #include "../src/libenjoy.h" // This tels msvc to link agains winmm.lib. Pretty nasty though. // 导入winmm.lib库 #pragma comment(lib, "winmm.lib") int main() { // libenjoy初始化 libenjoy_context *ctx = libenjoy_init(); // initialize the library libenjoy_joy_info_list *info; // Updates internal list of joysticks. If you want auto-reconnect // after re-plugging the joystick, you should call this every 1s or so // 更新joystick可用列表,如果想要实现热插拔效果,则需要每隔1秒调用一次这个函数 libenjoy_enumerate(ctx); // get list with available joysticks. structs are // 获得joystick可用的列表 // typedef struct libenjoy_joy_info_list { // uint32_t count; // libenjoy_joy_info **list; // } libenjoy_joy_info_list; // // typedef struct libenjoy_joy_info { // char *name; // uint32_t id; // char opened; // } libenjoy_joy_info; // // id is not linear (eg. you should not use vector or array), // and if you disconnect joystick and then plug it in again, // it should have the same ID info = libenjoy_get_info_list(ctx); if(info->count != 0) // just get the first joystick { libenjoy_joystick *joy; printf("Opening joystick %s...", info->list[0]->name); joy = libenjoy_open_joystick(ctx, info->list[0]->id);//获得第一个游戏杆的信息 if(joy) { int counter = 0; libenjoy_event ev; printf("Success!\n"); printf("Axes: %d btns: %d\n", libenjoy_get_axes_num(joy),libenjoy_get_buttons_num(joy)); while(1) { // Value data are not stored in library. if you want to use // them, you have to store them // That's right, only polling available // 调用libenjoy_poll函数监听joystick按键事件 while(libenjoy_poll(ctx, &ev)) { switch(ev.type) { case LIBENJOY_EV_AXIS: printf("%u: axis %d val %d\n", ev.joy_id, ev.part_id, ev.data); break; case LIBENJOY_EV_BUTTON: printf("%u: button %d val %d\n", ev.joy_id, ev.part_id, ev.data); break; case LIBENJOY_EV_CONNECTED: printf("%u: status changed: %d\n", ev.joy_id, ev.data); break; } } #ifdef __linux usleep(50000); #else Sleep(50); #endif counter += 50; // 如果joystick被拔出了,则每隔1秒调用一次libenjoy_enumerate函数 // 来监控joystick的连接状态 if(counter >= 1000) { libenjoy_enumerate(ctx); counter = 0; } } // Joystick is really closed in libenjoy_poll or libenjoy_close, // because closing it while libenjoy_poll is in process in another thread // could cause crash. Be sure to call libenjoy_poll(ctx, NULL); (yes, // you can use NULL as event) if you will not poll nor libenjoy_close // anytime soon. // 关闭joystick库 libenjoy_close_joystick(joy); } else printf("Failed!\n"); } else printf("No joystick available\n"); // Frees memory allocated by that joystick list. Do not forget it! // 清除内存 libenjoy_free_info_list(info); // deallocates all memory used by lib. Do not forget this! // libenjoy_poll must not be called during or after this call // 关闭libenjoy库,在关闭之后,就不可以再调用libenjoy_poll函数了 libenjoy_close(ctx); return 0; } 总结

本文介绍了joystick游戏杆编程的基本概念,并给出了几种读取joystick游戏杆输入的方法。这几种方法种,我最青睐的还是第四种使用joystick接口库。虽然使用Windows平台微软提供的库进行joystick编程也很方便,但是我在使用时还是遇到了许多兼容性问题。使用joystick接口库则是拿来了一个造好并且调试好的轮子,直接使用很方便。 为了更加方便大家使用,在此将libenjoy库编译成为了静态库和动态库:libenjoy动态链接库(win32vc6.0)。Linux版的暂时没有需求,所以就没有做,有需要的可以自己来。

引用:

维基百科词条:JoyStickWindows下对游戏杆编程JoyStick编程学习笔记在C++ Builder中使用游戏操纵杆DirectlnputXInputSDL-mirror/SDLTasssadar/libenjoy

资源:

libenjoy_master源码和测试工程libenjoy动态链接库(win32vc6.0)


【本文地址】


今日新闻


推荐新闻


CopyRight 2018-2019 办公设备维修网 版权所有 豫ICP备15022753号-3