Manipulando Joysticks

Inicialização

O primeiro passo quando se usa um joystick em um programa SDL é iniciar o sub-sistema de Joystick do SDL. Isto é feito passando o sinalizador (flag) SDL_INIT_JOYSTICK para SDL_Init. O sinalizador (flag) de joystick será geralmente usado em conjunto com outros sinalizadores (flags) (como o sinalizador de vídeo) porque o joystick é normalmente usado para controlar alguma coisa

Exemplo 3-1. Inicializando SDL com suporte para o Joystick

    if ( ! SDL_Init( SDL_INIT_VIDEO | SDL_INIT_JOYSTICK ) )
    {
        fprintf(stderr, "Não foi possível iniciar SDL: %s\n", SDL_GetError());
        exit(1);
    }

Isto irá provocar a inicialização do SDL com ambos os sub-sistemas, de Vídeo e de Joystick, ativados.

Examinando

Se chegamos até este ponto, então podemos seguramente assumir que a biblioteca SDL foi iniciada, e que o sub-sistema de Joystick está ativo. Nós agora podemos chamar alguma função de vídeo e/ou som para seguir em frente, antes de precisarmos do joystick. Eventualmente teremos de nos certificarmos que há realmente um joystick para ser usado. É bom sempre fazer a verificação, mesmo que se saiba que um joystick estará presente no sistema, porque assim poderemos detectar caso haja algum mal contato na conexão. A função usada para procurar por joysticks é a SDL_NumJoysticks.

Esta função simplesmente retorna o número de joysticks disponíveis no sistema. Se retornar pelo menos um, então estamos no caminho certo. O próximo passo é determinar qual dos joysticks o usuário quer utilizar. Se o número de joysticks disponíveis for apenas um, então é seguro supor que este um é o que o usuário quer utilizar. SDL tem uma função para pegar o nome dado aos joysticks pelo sistema operacional, e essa função é SDL_JoystickName. O joystick é especificado por um índice onde 0 é o primeiro joystick e o último joystick é o número retornado pela função SDL_NumJoysticks - No exemplo 3-2 cria-se uma lista com todos os joysticks disponíveis.

Exemplo 3-2. Examinando o número de joysticks disponíveis

   printf("%i joysticks foram encontrados.\n\n", SDL_NumJoysticks() );
    printf("Os nomes dos joysticks são:\n");
                
    for( i=0; i < SDL_NumJoysticks(); i++ ) 
    {
        printf("    %s\n", SDL_JoystickName(i));
    }

Abrindo um Joystick e Recebendo os Eventos do Joystick

A arquitetura de condução de eventos em SDL faz com que trabalhar com joysticks seja simples. Joysticks podem acionar 4 tipos de eventos diferentes:

SDL_JoyAxisEvent Ocorre quando um eixo é movido. SDL_JoyBallEvent Ocorre quando a posição da esfera de localização (TrackBall) do joystick é alterada. SDL_JoyHatEvent Ocorre quando é alterada uma posição do controle de topo do Joystick. SDL_JoyButtonEvent Ocorre quando um botão é pressionado ou solto.

Eventos são recebidos de todos os joysticks abertos. A primeira coisa que deve ser feita para recebermos eventos de joysticks é chamar a função SDL_JoystickEventState com o sinalizador SDL_ENABLE. Em seguida deve-se abrir o joystick do qual você deseja receber eventos. Isto é feito com a função SDL_JoystickOpen. Para o exemplo 3-3 nós estamos interessados apenas em eventos do primeiro joystick do sistema. Para receber eventos dele devemos fazer isso:

Exemplo 3-3. Abrindo um Joystick

    SDL_Joystick *joystick;

    SDL_JoystickEventState(SDL_ENABLE);
    joystick = SDL_JoystickOpen(0);

Se desejarmos receber eventos de outro joystick, devemos então abri-los com chamadas para a função SDL_JoystickOpen do mesmo modo que abrimos o joystick 0, com a diferença que devemos guardar a estrutura SDL_Joystick que retorna, em um ponteiro diferente. Nós só precisamos do ponteiro do joystick quando estamos trabalhando com o joystick ou quando estamos fechando o joystick.

Até este ponto todo o código que temos é usado apenas para iniciar o joystick para lermos valores em tempo real. Tudo que é necessário agora é um evento em repetição (Loop), que é algo que todos os programas SDL devem ter para receber os eventos de desistência do sistema. Devemos agora adicionar código para verificar o evento de repetição para ao menos algum dos eventos mencionados acima. Vamos imaginar que nosso evento de repetição seja parecido com esse:

    SDL_Event event;
    /* Outro código de inicialização vai aqui */   

    /* Inicie a repetição principal do jogo aqui */
    while(SDL_PollEvent(&event))
    {  
        switch(event.type)
        {  
            case SDL_KEYDOWN:
            /* Coloque as partes do teclado aqui */                             
            break;

            case SDL_QUIT:
            /* Coloque quaisquer sinalizadores necessários para */
            /* terminar a repetição principal do jogo aqui */
            break;
        }
    }

    /* Fim da repetição aqui */

Para lidar com os eventos de joystick nós meramente adicionamos casos para ele, e primeiramente vamos lidar com a adição de códigos dos eixos. Verificação de eixos pode se tornar problemática porque muitos dos eventos recebidos do joystick são espúrios (lixo). Eixos de joystick têm a tendência de variar um pouco da posição designada. Para compensar isso você deve ajustar o limite de mudanças, e ignorar os eventos que não excederem um valor mínimo. Geralmente 10% é um bom valor de limiar. Isto soa muito mais complicado do que é. Aqui está o código que lida com eventos de eixos:

Exemplo 3-4. Eventos de Eixos de Joystick

    case SDL_JOYAXISMOTION:  /* Lida com Movimentação de Joystick */
    if ( ( event.jaxis.value < -3200 ) || (event.jaxis.value > 3200 ) ) 
    {
      /* Código vai aqui */
    }
    break;

Outra dica com eventos de eixos é que os movimentos ‘para cima e para baixo’ e ‘ esquerda e direita’ são dois conjuntos de eixos diferentes. Os eixos mais importantes são o eixo 0 (esquerda-direita) e o eixo 1 (cima-baixo). Para trabalhar com eles separadamente no código, nós fazemos o seguinte:

Exemplo 3-5. Mais Eventos de Eixos do Joystick

    case SDL_JOYAXISMOTION:  /* Lida com Movimentação de Joystick */
    if ( ( event.jaxis.value < -3200 ) || (event.jaxis.value > 3200 ) ) 
    {
        if( event.jaxis.axis == 0) 
        {
            /* Código de movimento de esquerda-direita vai aqui */
        }

        if( event.jaxis.axis == 1) 
        {
            /* Código de movimento de cima-baixo vai aqui */
        }
    }
    break;

Idealmente o código aqui deve usar event.jaxis.value para escalonar alguma coisa. Por exemplo, vamos imaginar que você está usando o joystick para controlar o movimento de uma espaçonave. Se o usuário estiver usando um joystick analógico e empurrar o cabo só um pouquinho, ele espera mover menos que se ele empurrasse muito. É preferível criar seu código para essa situação porque faz com que a experiência dos usuários de controles analógicos seja melhor, e mantém do mesmo modo para os usuários de controles digitais.

Se seu joystick tem algum eixo adicional então ele possivelmente é usado para outro cabo ou outro dispositivo, e estes eixos retornam valores também, só que com outros valores de event.jaxis.axis

Trabalhar com botões é simples se comparado com a checagem de eixos.

Exemplo 3-6. Eventos de Botão de Joystick

    case SDL_JOYBUTTONDOWN:  /* Lida com os Apertos de Botão do Joystick */
    if ( event.jbutton.button == 0 ) 
    {
        /* Código vai aqui */
    }
    break;

Checagem de botões é mais simples que checagem de eixos porque um botão pode apenas ser pressionado ou não pressionado. O evento SDL_JOYBUTTONDOWN é acionado quando um botão é apertado, e o evento SDL_JOYBUTTONUP é disparado quando um botão é solto. Nós temos também que saber qual botão foi pressionado, e isso é feito lendo o campo event.jbutton.button.

Finalmente, quando terminamos de usar o joystick, devemos fechá-lo chamando a função SDL_JoystickClose. Para fechar um determinado joystick aberto devemos fazer isto no final do programa:

    SDL_JoystickClose(joystick);

Funções Avançadas de Joystick

Isto resolve o problema dos controles que você pode encontrar por ai, mas existem ainda algumas outras coisas que SDL suporta. Controles de Esferas (Joyballs) são o próximo na nossa lista. Eles são similares aos eixos, mas com algumas poucas diferenças. Controle de Esfera guarda mudanças de posição diferentemente das armazenadas nos eventos de eixos. Além disso, um evento de esfera de localização (trackball) contém as mudanças de ambos os eixos, X e Y. Para esse caso é como segue:

Exemplo 3-7. Eventos de Esfera de Joystick

    case SDL_JOYBALLMOTION:  /* Manipula o movimento de Esfera */
    if( event.jball.ball == 0 )
    {
      /* Manipulando esfera */
    }
    break;

O código acima verifica a primeira esfera no joystick. A mudança de posição será armazenada em event.jball.xrel e event.jball.yrel.

Finalmente temos o evento de topo. O controle no topo do joystick apenas informa a direção em que é empurrado. Verificamos a posição deste controle com as funções:

SDL_HAT_CENTERED

SDL_HAT_UP

SDL_HAT_RIGHT

SDL_HAT_DOWN

SDL_HAT_LEFT

Também existem algumas combinações pré-definidas das acima:

SDL_HAT_RIGHTUP

SDL_HAT_RIGHTDOWN

SDL_HAT_LEFTUP

SDL_HAT_LEFTDOWN

Na manipulação de eventos do controle de topo de joysticks temos algo parecido com isso:

Exemplo 3-8. Eventos de Controle de Topo do Joystick

    case SDL_JOYHATMOTION:  /* Manipula o movimento do controle de topo */
    if ( event.jhat.hat | SDL_HAT_UP )
    {
        /* Faça a parte do movimento 'Para Cima' aqui */
    }

    if ( event.jhat.hat | SDL_HAT_LEFT )
    {
        /* Faça a parte do movimento 'Para Esquerda' aqui */
    }

    if ( event.jhat.hat | SDL_HAT_RIGHTDOWN )
    {
        /* Faça a parte dos movimentos 'Direita e Para Baixo' juntas, aqui */
    }
    break;

Em adição aos exames de número de joysticks no sistema e seus nomes, existem funções para examinar as capacidades dos joysticks conectados:

SDL_JoystickNumAxes Retorna o número de eixos do joystick

SDL_JoystickNumButtons Retorna o número de botões do joystick

SDL_JoystickNumBalls Retorna o número de esferas do joystick

SDL_JoystickNumHats Retorna o número de controles de topo no joystick

Para usar estas funções só temos que passar pela estrutura que obtivemos quando abrimos o joystick. Por exemplo:

Exemplo 3-9. Examinando as Características dos Joysticks

    int number_of_buttons;
    SDL_Joystick *joystick;

    joystick = SDL_JoystickOpen(0);
    number_of_buttons = SDL_JoystickNumButtons(joystick);

Este código deverá obter o número de botões do primeiro joystick do sistema.

SDLDoc-ptBR/Tratando_Joysticks (last edited 2008-04-17 08:18:40 by localhost)