Survive — Organizando o código

survive-3_atom

Relembrando daqueles dois exemplos da parte anterior, quando o “cartridge.asm” foi transformado no “hello.asm” e o número de linhas do programa mais que dobrou passando de 20 para 41 linhas. Até aí tudo bem, programas de computador tendem a aumentar de tamanho conforme as funcionalidades são acrescidas mas programas em assembly são  praticamente instruções sequenciadas e isto cresce bem rápido.

Assim, como também acontece em qualquer linguagem de programação, quanto maior é o programa, mais difícil é mantê-lo organizado. Daí vem a pergunta: Isto é importante?

CLARO QUE É! Quando escrevi a versão para MSX do Flappy Bird usei algumas regras que pareciam (muito) boas na teoria mas justamente a prática cuidou de avacalhá-las, ou seja, hora de rever alguns conceitos. 🙂

Antes de seguir adiante, duas coisas:

  1. A mudança no título das publicações é para ajudar a identificar melhor o conteúdo;
  2. A partir deste ponto prometo publicações um pouco mais curtas e
  3. Não! Não discutirei sobre o quanto ld a,0x10 é mais bonito que LD A,$10, o foco será praticidade e não estética.  🙂

Quanto cresce?

Exemplificando para fixar melhor, digamos que eu queira acrescentar uma segunda mensagem de texto ao “hello.asm”, algo simples e que em qualquer linguagem de programação seria “só colocar um print“, correto? Então, vou “só colocar um print” para ver como fica:

O “só colocar um print” significou acrescentar 4 linhas:

...
            ld hl,haveANiceDay
            call print
...
haveANiceDay:
            db "Have a nice day! ^_^",0
...

Claro, “só seriam mais 4 linhas” se já tivesse deixado o trecho de impressão de strings em uma rotina específica mas como não o fiz, lembrando justamente o “não repita você mesmo“, tive de fazê-lo! 🙂

Rotinas em arquivos

Quando comecei o Survive fui aproveitando diversas rotinas já prontas, copiando, colando e adaptando dentro de “survive.asm”. Quando me dei conta mal havia iniciado, faltava bastante coisa e já ultrapassara a marca das 1.000 linhas de código. Então resolvi colocar cada rotina, ou conjunto funcional de rotinas, em arquivos separados e aproveitei para torná-las mais independentes do programa principal usando rótulos próprios e outras coisas. No final a diretiva include cuida de unificar os segmentos.

Para o montador assembler é indiferente trabalhar com um arquivo de 1.000 linhas ou com 10 arquivos concatenados de 100 linhas cada. O mesmo pode-se dizer do Git, tanto faz para a ferramenta monitorar alterações em um  único grande arquivo ou em diversos arquivos. Mas para um uso efetivo dela é bem melhor que o código esteja separado em pequenos arquivos.

Pois é, o Git não estava elencado originalmente na caixa de ferramentas mas ele faz parte daquilo que é “essencial”, assim como é o caso do GNU Make. 🙂

Nomes dos rótulos

Não vou entrar em detalhes, basta observar este trecho do código do Flappy Bird para ver como era o uso dos rótulos:

            ...
GPLMENSA0:  inc de
            ld a,(de)
            cp 1
            jr z,GPLMENSA2
            cp 0
            jr z,GPLMENSA1
            call WRTVRM
            inc hl
            jr GPLMENSA0
            ...

Se eu me perguntava sobre o que se fazia em GPLMENSA1 e GPLMENSA2, imagine quem nunca viu antes o código?

Então, novas regras:

  • As rotinas da BIOS e variáveis de ambiente continuam iguais — é assim que elas são conhecidas e não é de bom grado alterá-las;
  • Os rótulos das minhas rotinas, sub-rotinas e também das “variáveis” passam a ser grafadas em lowerCamelCase (tal qual em JavaScript);
  • Nada de criar rótulos sequenciais, usar nomes que detalhem melhor o que ele é e
  • Após definir um rótulo, pular uma linha, exceto nos equ, pois o Pasmo dá erro na montagem.

Como resultado o mesmo trecho de código fica assim:

            ...
gplMensaPrint:
            inc de
            ld a,(de)
            cp 1
            jr z,gplMensaWait
            cp 0
            jr z,gplMensaNewLine
            call WRTVRM
            inc hl
            jr gplMensaPrint
            ...

Bem mais legível e até dá para ter uma ideia aproximada sobre o que gplMensaWait e gplMensaNewLine devem fazer. 🙂

Usando ‘proc’ e ‘endp’

Uma coisa que aprendi — vi usando, não sabia o que era, pesquisei e gostei da ideia — foi fazer a marcação de início e fim de rotinas com as diretivas proc e endp. Sua função é de delimitação de um bloco de código, como fazem as chaves na linguagem C:

waitASec:
            proc
            | ld a,(JIFFY)
            | cp b
            | ret nc
            | jr waitASec
            endp

Só mais trabalho? Nem tanto, ao delimitar um bloco de instruções eu ganho a possibilidade de utilizar um escopo local para os rótulos lá dentro:

meuNumero:  equ 0x8000
            ...
minhaRotina:
            proc
            local meuNumero
            ...
meuNumero:  equ 0xffff
            ...
            endp

O valor utilizado é o que está dentro do bloco de código e não o que está do lado de fora, algo como este cara aqui em Javascript:

var meuNumero=32768;
function minhaRotina(){
    var meuNumero=65535;
    ...
}

Algo muito útil, ainda mais com a ideia de reaproveitar código.

E na prática?

survive-3_code-refactoring

Resolvi aproveitar todas as “novas regras” aplicando-as diretamente no código do Flappy Bird e o resultado foi a quarta revisão do jogo (ou 1.D se preferir) — no final acabou não sendo só um code refactoring pois aproveitei para corrigir alguns defeitos e também acrescentar novos recursos.

As alterações ainda não foram disponibilizadas no repositório do jogo no GitHub, falta uma revisão em todos os comentários (pois ainda apontam para os rótulos antigos) mas será em breve. Aí incluo também novas versões dos executáveis nas versões em cartucho e também binário (para carregar com BLOAD).

Fim da terceira parte

Assim fecho (eu acho) todas as definições teóricas do Survive, aliás muita coisa daqui pode ser aplicada para o desenvolvimento de jogos de jogos em outras plataformas ou em outras linguagens de programação.

Agora é hora de efetivamente começar a escrever um jogo! 😀

Anúncios

7 comentários sobre “Survive — Organizando o código

  1. Pingback: Atualização do Flappy Bird | giovannireisnunes

  2. No sjasmplus dá para fazer print em uma linha:

    print macro str
    ld hl,1f
    call print
    jr 2f
    1: db str, 0
    2:
    endm

    Aí é só usar
    print “hello”

    Curtir

    • Pois é, eu estudei um pouco o SJASMPLUS e dente as coisas que não me agradaram está a sintaxe escolhida para os rótulos dinâmicos. Poxa, “1f”, “2f” etc são o tipo de coisa que pode gerar alguma confusão. Aliás é possível fazer o mesmo no PASMO:

      macro print,str
      	proc
      	local p1,p2
      	ld hl,p1
      	call print_string
      	jr p2
      	p1: db str,0
      	p2:
      	endp
      	endm
      

      Curtir

      • Acho meio feio também, a idéia é que só faz sentido usar se o jump estiver bem perto da definição, de modo que os dois caibam visualmente na tela. Mas como ele é opensource dá para estender se precisar.

        Curtir

Deixe um comentário

Preencha os seus dados abaixo ou clique em um ícone para log in:

Logotipo do WordPress.com

Você está comentando utilizando sua conta WordPress.com. Sair / Alterar )

Imagem do Twitter

Você está comentando utilizando sua conta Twitter. Sair / Alterar )

Foto do Facebook

Você está comentando utilizando sua conta Facebook. Sair / Alterar )

Foto do Google+

Você está comentando utilizando sua conta Google+. Sair / Alterar )

Conectando a %s