第25课 - 控制杆


更新时间:2014年2月14日


这里我们将学习从控制杆/游戏手柄获取输入。这个程序的基础是运动那一课,只是这次控制杆将取代键盘来移动点。
//将要使用到的控制杆
SDL_Joystick *stick = NULL;
控制杆在SDL中有自己的数据类型,即SDL_Joystick。

在这个程序中,我们把控制杆声明为全局变量。
//点
class Dot
{
    private:
    //点的坐标
    int x, y;
    
    //点的速度
    int xVel, yVel;
    
    public:
    //初始化
    Dot();
    
    //处理控制杆
    void handle_input();
    
    //移动点
    void move();
    
    //显示点
    void show();
};
就像你看到的那样,Dot类和以前的基本保持一样。唯一的改变是我们处理输入的方式。
bool init()
{
    //初始化所有SDL的子系统
    if( SDL_Init( SDL_INIT_EVERYTHING ) == -1 )
    {
        return false;    
    }
    
    //设置屏幕
    screen = SDL_SetVideoMode( SCREEN_WIDTH, SCREEN_HEIGHT, SCREEN_BPP, SDL_SWSURFACE );
    
    //如果设置屏幕时出现错误
    if( screen == NULL )
    {
        return false;    
    }
    
    //检查是否有控制杆
    if( SDL_NumJoysticks() < 1 )
    {
        return false;    
    }
    
    //打开控制杆
    stick = SDL_JoystickOpen( 0 );
    
    //如果打开控制杆出现问题
    if( stick == NULL )
    {
        return false;
    }
    
    //设置窗口标题
    SDL_WM_SetCaption( "Move the Dot", NULL );
    
    //如果所有初始化都成功
    return true;
}
使用键盘和控制杆作为输入的一个关键区别是控制杆必须要执行初始化。

在初始化函数中我们使用SDL_NumJoysticks()来检查插入了多少个控制杆。如果至少一个控制杆被插入,我们就用函数SDL_JoystickOpen()打开第一个可用的控制杆。第一个可用的控制杆是控制杆0,,因为在编程中我们总是从0开始计数。当打开控制杆出现问题,SDL_JoystickOpen()会返回NULL。
void clean_up()
{
    //释放表面
    SDL_FreeSurface( dot );
    
    //关闭控制杆
    SDL_JoystickClose( stick );
    
    //退出SDL
    SDL_Quit();
}
在清理函数中,我们必须调用SDL_JoystickClose()来关闭被打开的控制杆。
void Dot::handle_input()
{
    //如果一个轴上发生变化
    if( event.type == SDL_JOYAXISMOTION )
    {
        //如果控制杆0发生变化
        if( event.jaxis.which == 0 )
        {
            //如果X轴变化
            if( event.jaxis.axis == 0 )
            {
                //如果X轴处在中间位置
                if( ( event.jaxis.value > -8000 ) && ( event.jaxis.value < 8000 ) )
                {
                    xVel = 0;
                }
                //如果不是
                else
                {
                    //调整速度
                    if( event.jaxis.value < 0 )
                    {
                        xVel = -DOT_WIDTH / 2;
                    }
                    else
                    {
                        xVel = DOT_WIDTH / 2;
                    }
                }    
            }
当控制杆移动时,一个SDL_JOYAXISMOTION事件会发生。

首先我们检查移动的控制杆是控制杆0,。在这个程序中,这是无关紧要的,因为被初始化的控制杆只有控制杆0,但是在实际游戏中,你可能将需要检查多个控制杆。

然后我们检查它移动的是哪个轴。在大多数现代控制杆上,X轴是0,Y轴是1。

接着我们检查X轴的值是否在-8000到8000范围内。如果是的,X轴是处于中间位置的,点将保持静止。

你可能在想"为神马如此大的一个范围被认为是处于中间位置?"原因是控制杆的轴的范围是-32768到32767。你可以将控制杆放在0的位置,然后你朝它打一个喷嚏,它可能就会变成200 。

如果控制杆不在中间位置范围内,我们就设置相应的X方向的速度。
            //如果Y轴发生变化
            else if( event.jaxis.axis == 1 )
            {
                //如果Y轴在中间位置
                if( ( event.jaxis.value > -8000 ) && ( event.jaxis.value < 8000 ) )
                {
                    yVel = 0;
                }
                //如果不是
                else
                {
                    //调整速度
                    if( event.jaxis.value < 0 )
                    {
                        yVel = -DOT_HEIGHT / 2;
                    }
                    else
                    {
                        yVel = DOT_HEIGHT / 2;
                    }
                }
            }
        }
    }
}
然后Y轴的处理和之前的一样。

处理控制杆时,SDL_JoyAxisEvent是最难处理的事件。处理其他的事件,比如SDL_JoyBallEvent, SDL_JoyHatEvent, 和 SDL_JoyButtonEvent,应该是容易想出来的,只要你快速浏览一下SDL的API文档。

本课所用的多媒体文件和源代码可从此处下载

下一课:可缩放窗口和窗口事件