variacao de tempo ( fSpeed * deltaTime ). Se um tiro deve ser disparado, um evento e chamado, delegando a responsabilidade para qualquer um que implementa-lo.Agora, podemos alterar TGame.HandleEvents para informar fPlayer o estado dos inputs.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; 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)] := true end; end;end;Antes de compilar, lembre-se declarar fPlayer dentro de TGame e de realizar as devidas inicializacoes e finalizacoes.O que fizemos aqui foi capturar o pressionamento (SDL_KEYDOWN) e liberacao (SDL_KEYUP) das teclas que nos interessam e atualizar os flags de input do jogador para que quando a funcao TPlayer.Update for chamada, ela saiba se deve mover o jogador ou criar um novo tiro.Execute o game e veja como agora e possivel mover o jogador. Altere a variavel fSpeed ate ficar satisfeito com o resultado. O valor da constante DEFAULT_COOLDOWN controla a frequencia com que o jogador pode atirar.Perceba que a logica de criacao do disparo do jogador nao foi criada. Ao inves disto, delegamos esta responsabilidade ao evento OnShotTriggered. A razao por tras desta escolha, e que tanto o jogador quando os inimigos podem efetuar disparos e, para manter o codigo organizado, vamos implementar a logica de desenho e atualizacao dos projeteis em um unico lugar. Uma classe unica que mantera todos os projeteis do jogo, a TShotList.TShotDirection = ( Up, Down);TShot = class ( TGameObject )private fDirection : TShotDirection; fSpeed : real; fVisible : boolean; fSprite : TSprite;public constructor Create(const aRenderer: PSDL_Renderer); override; destructor Destroy; override; procedure Draw; override; procedure Update(const deltaTime : real); override; property Sprite : TSprite read fSprite write fSprite; property Direction : TShotDirection read fDirection write fDirection; property Speed : real read fSpeed write fSpeed; property Visible : boolean read fVisible write fVisible;end;TShotList = classstrict privateconst MAX_SHOTS = 64;var fShots : array[0..MAX_SHOTS-1] of TShot; function GetItems(index: integer): TShot;public constructor Create(const aRenderer: PSDL_Renderer; aTexture: TTexture); destructor Destroy; override; procedure Update(const deltaTime : real); procedure Draw; function NextIndexAvailable: integer; property Items[index: integer]: TShot read GetItems; default;end;Definimos a classe TShot para representar um disparo. Cada disparo pode seguir, em linha reta, para cima ou para baixo (TShotDirection) a uma velocidade constante (fSpeed) e, sabe desenhar e atualizar a si mesma. Veja sua implementacao.{ TShot }constructor TShot.Create(const aRenderer: PSDL_Renderer);begin inherited Create(aRenderer); fSpeed := 300.0; fDirection := TShotDirection.Up; fVisible := true; fSprite := TSprite.Create;end;destructor TShot.Destroy;begin fSprite.Free; inherited Destroy;end;procedure TShot.Draw;var source, destination : TSDL_Rect;begin if ( fSprite.Texture.Data <> nil ) and fVisible then begin source.x := 0; source.y := 0; source.w := 6; source.h := 12; destination.x := Round(self.Position.X); destination.y := Round(self.Position.Y); destination.w := 6; destination.h := 12; SDL_RenderCopy( fRenderer, fSprite.Texture.Data, @source, @destination) ; end;end;procedure TShot.Update(const deltaTime: real);begin if fVisible then begin case fDirection of TShotDirection.Up : Position.Y := Position.Y - (fSpeed * deltaTime ); TShotDirection.Down : Position.Y := Position.Y + (fSpeed * deltaTime ); end;