JoyStick游戏杆编程实践
概述
最近突然对如何编程读取游戏手柄输入比较感兴趣。所以上网找了找相关的资料,发现没有什么简单明了的教程,所以在此将收集到跟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<stdio.h>
#include<stdlib.h>
#include<conio.h>#include<Windows.h>//添加joystick操作api的支持库
#include<MMSystem.h>
#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/SDL
- Tasssadar/libenjoy
SDL全称是Simple DirectMedia Layer,是一个很全面的跨平台媒体/游戏开发库,但是我没精力折腾这些,所以转向了libenjoy。这是一个简单的JoyStick操作接口库,使用C语言实现,可以与任何C/C++应用程序一起使用,而且是跨平台的,可以说非常方便。在此给出libenjoy工程中的测试例程和libenjoy库的源代码与测试工程:
//测试例程
#include <stdio.h>
#ifdef __linux#include <unistd.h>
#else#include <windows.h>
#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 librarylibenjoy_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 IDinfo = 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 __linuxusleep(50000);
#elseSleep(50);
#endifcounter += 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);}elseprintf("Failed!\n");}elseprintf("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版的暂时没有需求,所以就没有做,有需要的可以自己来。
引用:
- 维基百科词条:JoyStick
- Windows下对游戏杆编程
- JoyStick编程学习笔记
- 在C++ Builder中使用游戏操纵杆
- Directlnput
- XInput
- SDL-mirror/SDL
- Tasssadar/libenjoy
资源:
- libenjoy_master源码和测试工程
- libenjoy动态链接库(win32vc6.0)
JoyStick游戏杆编程实践相关推荐
- 游戏杆编程心得二:如何判断按钮的有效按下
作者:朱金灿 来源:http://blog.csdn.net/clever101 在游戏杆编程中通过一般需要获取按钮状态来执行特定事件,比如实现按下按钮1一次,变量num递增100,但在调试系统时往往 ...
- Windows下对游戏杆编程
我现在所知道的获取游戏杆输入的方法有4种,第4种才是我要说的正题. 1.用DDK通过USB接口直接访问游戏杆 2.通过汇编访问游戏杆 据说在NT下不能这么用了 3.用Direct Input 也许会很 ...
- Cocos2d-x 类COC手游与RTS(即时战略)游戏的编程实践总结
本文乃Siliphen原创,转载请注明出处:http://blog.csdn.net/stevenkylelee 概述 先来看一段视频.这个视频很短.4分钟.是我的一个技术demo演示视频. http ...
- 3D游戏编程实践——打飞碟(Hit UFO)游戏运动与物理兼容版
这次编程实践是在上一次实践的基础上,增加了物理运动,做到了运动学和物理运动会的兼容.而原来的代码只实现了运动学部分. 首先需要实现物理运动部分的Action类和ActionManager类. 相比起运 ...
- Python游戏编程实践2:魔塔
Python游戏编程实践2:魔塔 前言 运行 前言 在逗游游戏盒上玩了一个名叫<魔塔>的游戏,感觉颇有心得体会."与其临渊羡鱼,不如退而结网",使用Python语言编写 ...
- Python游戏编程实践3:魔法洞穴2
Python游戏编程实践3:魔法洞穴2 前言 运行 前言 之前在TapTap上玩了一个名叫<魔法洞穴2>的小游戏,感觉很有意思,就使用Python语言编写了一个类似的命令行小游戏,为了简单 ...
- 3D游戏编程实践——Priests and Devils
编程实践--Priests and Devils github链接:https://github.com/ctlchild/SYSU-unity3d-learning/tree/master/hw2 ...
- 3D游戏编程实践——Priests and Devils(动作分离版)
编程实践--Priests and Devils 动作分离版 Priests and Devils is a puzzle game in which you will help the Priest ...
- Python游戏编程实践1:鲁蒂亚的世界
Python游戏编程实践1:鲁蒂亚的世界 前言 运行 前言 在逗游游戏盒上玩了一个名叫<鲁蒂亚的世界>的小游戏,感觉颇有心得体会."与其临渊羡鱼,不如退而结网",使用P ...
最新文章
- NLP被英语统治?打破成见,英语不应是「自然语言」同义词
- 基于经验的SOA成功原则
- 监控工具—Prometheus—监控Java程序
- 设计模式(命令模式)
- 失血多少会贫血_阿胶糕治贫血两大好处,治疗贫血两大方法要掌握
- 软件测试--cookie学习
- 免费的开源软件那么“香”,为何他们宁愿花钱去买软件?
- 白糖详细 制造工艺、等级划分、国家标准号和注意事项
- iOS如何完成蓝牙打印机功能
- 《架构师修炼之道》读书笔记之五:换位思考
- HTML 字体图标的引入
- 记一次npm install 报RequestError: connect ETIMEDOUT 20.205.243.166:443和RequestError: socket hang up
- IT路要如何走?——老程序员的10个忠告
- RTSP拉流h265(hevc)+AAC关键节点详解!史上最全RTSP+hevc 交互全记录!
- 机器学习基础---pr曲线的绘制
- 《海外华人写兰州国际书法展》亮相美国丹佛
- 11.30 - 每日一题 - 408
- 《计算机科学》投稿心得
- C#语言生成PDF文件函数总结
- PowerMILL Robot 2017 机器人编程视频教程