= deslocamento total em x, deltaY = deslocamento total em Y Grafico da maquina de estadosCom as regras da maquina de estados que rege o movimento dos inimigos bem entendidas, podemos pensar em sua implementacao. Se voce tiver um pensamento mais visual, a imagem ao lado, que mostra graficamente o fluxo da maquina correspondente aos dados desta tabela, pode ajudar a visualizar melhor o seu funcionamento.A tabela de estados em si, pode ser mapeada para um tipo enumerado e cada inimigo sabera duas informacoes sobre seu movimento: o estado atual e o estado anterior que iremos armazenar em duas variaveis privadas fOldMoveDirection e fMoveDirection.O metodo update de TEnemy.Update sera responsavel por implementar as regras da maquina e fazer a mudanca dos estados quando necessario //Estados TEnemyMoveDirection = ( None, //A Right, //B Down, //C Left //D );(...)procedure TEnemy.Update(const deltaTime : real);const OFFSET_X = 3 * DEBUG_CELL_SIZE; OFFSET_Y = DEBUG_CELL_SIZE div 2;var currTicks : UInt32; deltaX : real; limitX : real; deltaY : real; limitY : real; procedure CalcXParams( aDirection : TEnemyMoveDirection ); inline; begin deltaX := Abs(Position.X - fMovementOrigin.X); case aDirection of TEnemyMoveDirection.Right : limitX := fMovementOrigin.X + OFFSET_X; TEnemyMoveDirection.Left : limitX := fMovementOrigin.X - OFFSET_X; end; end; procedure CalcYParams; inline; begin deltaY := Abs(Position.Y - fMovementOrigin.Y); limitY := fMovementOrigin.Y + OFFSET_Y; end; procedure ChangeDirection( aDirection : TEnemyMoveDirection ); inline; begin fOldMoveDirection := fMoveDirection; fMoveDirection:= aDirection; end;begin if Assigned( Sprite ) then Sprite.Update(deltaTime); if ( fMoveDirection <> TEnemyMoveDirection.None ) then begin case fMoveDirection of TEnemyMoveDirection.Left : begin CalcXParams( TEnemyMoveDirection.Left ); Position.X -= fSpeed * deltaTime; if ( Position.X < limitX ) then Position.X := limitX; if ( deltaX = OFFSET_X ) then begin fMovementOrigin := Position; ChangeDirection( TEnemyMoveDirection.Down ); end; end; TEnemyMoveDirection.Right : begin CalcXParams( TEnemyMoveDirection.Right ); Position.X += fSpeed * deltaTime; if ( Position.X > limitX ) then Position.X := limitX; if ( deltaX = OFFSET_X ) then begin fMovementOrigin := Position; ChangeDirection( TEnemyMoveDirection.Down ); end; end; TEnemyMoveDirection.Down : begin CalcYParams; Position.Y += fSpeed * deltaTime; if ( Position.Y > limitY ) then Position.Y := limitY; if ( deltaY = OFFSET_Y ) then begin fMovementOrigin := Position; if ( fOldMoveDirection = TEnemyMoveDirection.Left ) then ChangeDirection( TEnemyMoveDirection.Right ) else ChangeDirection( TEnemyMoveDirection.Left ); end; end; end; end;end; Depois de realizar as alteracoes os inimigos estarao se movimentado de acordo com o valor de fMoveDirection, e as transicoes da maquina de estados estarao sendo computadas em TEnemy.Update.Otimo. Os inimigos estao se movendo, vamos, agora, faze-los atirar.Tiros e ColisoesLambra-se de como fazemos o jogador atirar? Haviam algumas limitacoes que impusemos de proposito para que o game fluisse bem. Definimos um intervalo entre os tiros e delegamos a criacao do tiro em si a quem implementasse o evento OnShot. Faremos a mesma coisa com os inimigos, mas com duas diferencas importantes.O jogador atira em resposta a um evento do teclado ou do gamepad. Os inimigos atirarao em responsa a um teste de probabilidade que sera realizado a cada 2500ms.O jogador pode atirar a qualquer momento. Um inimigo so pode atirar se nao houver outros inimigos em sua linha de tiro, caso contrario, eles matariam uns aos