para criar e distribuir corretamente os inimigos em suas posicoes iniciais na tela.procedure TGame.CreateGameObjects;var i : integer; enemy : TEnemy;begin for i:= 0 to 119 do begin case i of 00..39 : begin enemy := TEnemyC.Create( fRenderer ); enemy.Sprite.Texture.Assign( fTextures[ integer(TSpriteKind.EnemyC) ] ); enemy.Sprite.InitFrames(1, 2); end; 40..79 : begin enemy := TEnemyB.Create( fRenderer ); enemy.Sprite.Texture.Assign( fTextures[ integer(TSpriteKind.EnemyB) ] ); enemy.Sprite.InitFrames(1, 2); end; 80..119 : begin enemy := TEnemyA.Create( fRenderer ); enemy.Sprite.Texture.Assign( fTextures[ integer(TSpriteKind.EnemyA) ] ); enemy.Sprite.InitFrames(1, 2); end; end; enemy.Position.X := DEBUG_CELL_SIZE + ( i mod 20 ) * DEBUG_CELL_SIZE ; enemy.Position.Y := 2* DEBUG_CELL_SIZE + ( i div 20 ) * DEBUG_CELL_SIZE ; fEnemies.Add( enemy ); end; fPlayer := TPlayer.Create( fRenderer ); fPlayer.Sprite.Texture.Assign( fTextures[ integer(TSpriteKind.Player)] ); fPlayer.Sprite.InitFrames(1,1); fPlayer.OnShotTriggered:= @doPlayer_OnShot; fPlayer.Position.X := trunc( SCREEN_HALF_WIDTH - ( fPlayer.Sprite.Texture.W / 2 )); fPlayer.Position.Y := (DEBUG_CELL_SIZE * 18) - fPlayer.Sprite.CurrentFrame.Rect.h; fShots := TShotList.Create(true);end;Vamos tambem diferenciar um inimigo do outro para que eles tenham pontos de vida diferentes. { TEnemyA } TEnemyA = class( TEnemy ) protected procedure InitFields; override; end; { TEnemyB } TEnemyB = class( TEnemy ) protected procedure InitFields; override; end; { TEnemyC } TEnemyC = class( TEnemy ) protected procedure InitFields; override; end; { TEnemyD } TEnemyD = class( TEnemy ) protected procedure InitFields; override; end;(...){ TEnemyC }procedure TEnemyC.InitFields;begin inherited InitFields; fHP:= 3;end;{ TEnemyB }procedure TEnemyB.InitFields;begin inherited InitFields; fHP:= 2;end;{ TEnemyA }procedure TEnemyA.InitFields;begin inherited InitFields; fHP := 1;end;{ TEnemyD }procedure TEnemyD.InitFields;begin inherited InitFields; fHP:= 4;end;Restringindo os movimentosVamos aproveitar que estamos com essas formulas frescas na cabeca e restringir os movimentos do jogador para que ele nao saia da secao inferior do layout. Altere TPlayer.Update conforme o codigo a seguir.procedure TPlayer.Update(const deltaTime: real);begin if fInput[Ord(TPlayerInput.Left)] then begin Position.X:= Position.X - ( fSpeed * deltaTime ); if Position.X < DEBUG_CELL_SIZE then Position.X:= DEBUG_CELL_SIZE; end; if fInput[Ord(TPlayerInput.Right)] then begin Position.X:= Position.X + ( fSpeed * deltaTime ); if Position.X > ((DEBUG_CELL_SIZE * 24) - Self.Sprite.CurrentFrame.Rect.w) then Position.X:= ((DEBUG_CELL_SIZE * 24) - Self.Sprite.CurrentFrame.Rect.w); end; if fCooldownCounter > 0 then Dec(fCooldownCounter, trunc(deltaTime * MSecsPerSec)); if ( (fInput[Ord(TPlayerInput.Shot)]) and ( fCooldownCounter <= 0) ) then begin if Assigned(fOnShotTriggered) then fOnShotTriggered(self); fCooldownCounter := fCooldown; fInput[Ord(TPlayerInput.Shot)] := false; end;end;Quanto aos inimigos, vamos deixa-los parados em seus lugares por enquanto, pois isto ira facilitar muito as coisas no decorrer do proximo topico onde iremos tratar as colisoes entre os objetos. Voltaremos a movimentacao dos inimigos em outro momento.Tratamento de ColisoesInimigos e seus retangulos de colisaoUma das etapas mais delicadas no loop de um game e a checagem de colisao. Neste passo, devemos iterar por todos os objetos visiveis, checar se eles "tocam" um ao outro e tomar alguma decisao quando isto ocorrer. Se um tiro tocar um inimigo, por exemplo, ele deve sofrer um dano e o tiro sera destruido.Deteccao de colisoes e um assunto extenso, mas para nosso game so ha um tipo de colisao possivel, a colisao entre retangulos que, na pratica se reduz a verificar se ha alguma interseccao ente dois deles. A SDL, novamente, possui uma funcao para nos ajudar. Confira a documentacao de SDL_HasIntersection e veja como tudo o que ela precisa e de dois retangulos.