then raise SDLException.Create(SDL_GetError); flags := IMG_INIT_PNG; result := IMG_Init( flags ); if ( ( result and flags ) <> flags ) then raise SDLImageException.Create( IMG_GetError ); LoadTextures; CreateGameObjects;end;Agora podemos abrir um joystick para leitura.Por questao de seguranca, vamos sempre checar se ha um joystick disponivel antes de tentar utiliza-lo e se nao houver mais (um controle pode ser desconectado no meio do jogo, por exemplo) fechamos seu manipulador. Faremos isto em uma nova rotina que incluiremos no game loop.Crie uma nova variavel privada em TGame, chame-a de fJoystick e defina seu tipo como PSDL_Joystick, um ponteiro para um SDL_Joystick e implemente o codigo abaixo.procedure TGame.CheckDevices;var numJoysticks: SInt32;begin numJoysticks:= SDL_NumJoysticks; if (numJoysticks > 0) then begin if (fJoystick = nil) then begin fJoystick:= SDL_JoystickOpen(0); exit; end; end else if fJoystick <> nil then begin SDL_JoystickClose(fJoystick); fJoystick := nil; exit; end;end;(...)procedure TGame.Run;var deltaTime : real; thisTime, lastTime : UInt32;begin deltaTime := 0.0; thisTime := 0; lastTime := 0; fRunning := true; while fRunning do begin thisTime := SDL_GetTicks; deltaTime := real((thisTime - lastTime) / MSecsPerSec); lastTime := thisTime; CheckDevices; //atualizamos o status do joystick no comeco de cada iteracao HandleEvents; Update( deltaTime ); Render; SDL_Delay(1); end;end;Com isto, e seguro plugar ou remover um joystick durante a partida. O jogo sempre sabera inicializar e liberar os recursos necessarios em cada uma das situacoes.O SDL notifica os eventos associados aos joysticks de maneira identica ao que faz com os eventos de teclado. Para cada evento ocorrido no dispositivo, a biblioteca adiciona uma mensagem na pilha e nos podemos captura-las facilmente dentro de nosso TGame.HandleEvents. Observe os identificadores no padrao SDL_JOY* no case principal da funcao.procedure TGame.HandleEvents;var event : TSDL_Event;begin while SDL_PollEvent( @event ) = 1 do begin case event.type_ of SDL_QUITEV : fRunning := false; SDL_KEYDOWN : case event.key.keysym.sym of SDLK_ESCAPE: fRunning := false; SDLK_LEFT, SDLK_A : fPlayer.Input[Ord(TPlayerInput.Left)] := true; SDLK_RIGHT, SDLK_D : fPlayer.Input[Ord(TPlayerInput.Right)]:= true; SDLK_SPACE : fPlayer.Input[Ord(TPlayerInput.Shot)] := true; end; SDL_KEYUP : case event.key.keysym.sym of SDLK_LEFT, SDLK_A : fPlayer.Input[Ord(TPlayerInput.Left)] := false; SDLK_RIGHT, SDLK_D : fPlayer.Input[Ord(TPlayerInput.Right)]:= false; SDLK_SPACE : fPlayer.Input[Ord(TPlayerInput.Shot)] := false; end; SDL_JOYAXISMOTION : case event.jaxis.axis of //X axis motion 0 : begin fPlayer.Input[Ord(TPlayerInput.Left)] := false; fPlayer.Input[Ord(TPlayerInput.Right)] := false; if event.jaxis.value > 0 then fPlayer.Input[Ord(TPlayerInput.Right)] := true else if event.jaxis.value < 0 then fPlayer.Input[Ord(TPlayerInput.Left)] := true end; end; SDL_JOYBUTTONUP : case event.jbutton.button of 0, 1, 2, 3 : begin fPlayer.Input[Ord(TPlayerInput.Shot)] := false; end; end; SDL_JOYBUTTONDOWN : case event.jbutton.button of 0, 1, 2, 3 : begin fPlayer.Input[Ord(TPlayerInput.Shot)] := true; end; end; end; end;end;Bingo! Plugue o joystick e vera que pode controlar a nave com os controles direcionais e atirar utilizando os botoes.O eventos de navegacao direcional horizontal sao reportados como um movimento no eixo X utilizando a cosnstante SDL_JOYAXISMOTION. Se o valor lido for maior que 0, significa que houve um pressionamento na seta para a direita, se for menor que 0, a seta esquerda do joystick foi pressionada.A mesma logica e utilizada para reportar o pressionamento (SDL_JOYBUTTONUP) e liberacao (SDL_JOYBUTTONDOWN) dos botoes. Como existem inumeros modelos de controladores de jogo, cada um com um numero de diferente de botoes disponiveis, capturamos os eventos dos 4