MC102
Algoritmos e Programação de Computadores
Parte VIII



Norton Trevisan Roman




ANIMAÇÃO BÁSICA

O que o programa abaixo faz?

    BEGIN
      FOR i:=1 to 20 do write('*');
      writeln
    END.
        

Escreve 20 '*' certo? E como você vê a saída?

    ********************
        

Como o computador escreveu?

    *
    **
    ***
    ...
    ********************
        

E por que você não viu isso? Porque foi muito rápido! Agora considere o programa:

    FOR c:=1 TO 20 DO 
    BEGIN
      write('*');
      atrasa
    END;
    writeln;
        

se "atrasa" for suficientemente longo, então veremos a animação, que corresponde a uma barra de * que cresce da esquerda para a direita.

Como fazemos o atraso? Uma maneira horrível pode ser:

    PROCEDURE atrasa;
    VAR a,b,c : integer {contadores}
    BEGIN
      FOR a:=1 TO 1000 DO
        FOR b:=1 to 10000 DO
          FOR c:=1 TO 10000 DO {nada};
    END;
        

Isso vai ficar contando até 10¹². É um atraso.

Mas tem que haver um meio mais inteligente de gerar esse atraso. E tem! Em pascal existe o comando delay(t), que gera um atraso de t milissegundos. Para que delay funcione, não esqueça de incluir "USES crt;" logo abaixo da cláusula "PROGRAM". Então nosso programa pode ser:

    FOR c:=1 TO 20 DO
    BEGIN
      write('*');
      delay(500)
    END;
        

Mas isso ainda é limitado, não? Afinal, a tela não é só uma linha. Ela tem altura e largura, e poderíamos querer por um '*' em algum lugar pré-definido dela. Como faríamos então?

Antes de mais nada, temos que considerar a tela como uma grande matriz de n linhas por m colunas. Um grande quadriculado. Então a tela é:

0 1 2 ... m
0
1
2
...
n

onde n e m dependem do tamanho do monitor. Note que o (0,0) é no canto superior esquerdo.

Como fazemos então para por um '*' na posição (2,3) -> linha 3, coluna 2? Usando gotoxy:

    BEGIN
      gotoxy(2,3);
      write('*')
    END.
        

Assim, gotoxy posiciona o cursor na coordenada (x,y) = (2,3) e write escreve la´um '*'. Fácil não? Novamente, não esqueça de incluir "USES crt;".

Agora, como fazermos para fazer com que um '*' ande das coordenadas (2,2) até (20,2), ou seja, que ande 18 posições na linha 2? Um algoritmo para isso seria:

    desenho um * na posição pos
    espero
    para pos de 2 a 20 faça:
      apago o * em pos
      desenho um * em pos+1
      espero
        

E como apago o '*'? Simples, desenho um espaço em branco em cima dele. Ou seja, pinto na mesma cor da tela. Então o programa é:

    gotoxy(2,2);
    write('*');
    delay(500);
    FOR x := 2 TO 19 DO {19 porque a última linha irá escrever no 20}
    BEGIN
      gotoxy(x,2);
      write(' ');
      gotoxy(x+1,2);
      write('*');
      delay(500)
    END; 
        

Você vai ver o '*' passar de x:=2 a 20. Peraí. 20? Então por que no FOR tem um 19? Porque o último write será posto em x+1 e, se x for 19, esse último '*' irá em x = 20.

Agora, para finalisar esse pequeno desvio que fizemos, vamos derrubar um ovo. Vamos desenhar algo que, ainda que vagamente, lembre um ovo e fazê-lo cair 20 posições a partir de uma posição inicial constante.

Que algoritmo usamos? o mesmo:

    desenho o ovo
    espero
    para y = yinicial até yinicial + 20
      apago o ovo
      desenho o ovo em y+1
      espero
        

E como vamos desenhar o ovo? Bom, com o que sabemos até agora podemos criar um procedimento para desenhar o ovo e um para apaga. E como saberemos onde desenhar? É só fazer com que os procedimento leiam a posição inicial do ovo em variáveis globais. Lembre-se: há um modo melhor, mais inteligente e mais seguro de fazer isso, mas só veremos mais tarde. Então vamos lá:

    PROGRAM queda;
    USES crt;

    CONST xin = 10; {o x inicial}
          yin = 2;  {o y inicial}
    VAR x,y : integer; {coordenadas}
          c : integer; {contador do for}

    PROCEDURE desenha_ovo;
    BEGIN
      gotoxy(x+1,y);
      write('*');
      gotoxy(x,y+1);
      write('* *');
      gotoxy(x,y+2);
      write('* *');
      gotoxy(x+1,y+3);
      write('*')
    END;

    PROCEDURE apaga_ovo;
    BEGIN
      gotoxy(x+1,y);
      write(' ');
      gotoxy(x,y+1);
      write('   ');
      gotoxy(x,y+2);
      write('   ');
      gotoxy(x+1,y+3);
      write(' ')
    END;

    BEGIN
      x := xin; {inicializo a coordenada}
      y := yin; {inicializo a coordenada}
      desenha_ovo;
      delay(500);
      FOR c := yin TO (yin+20) DO
      BEGIN
        apaga_ovo;
        y := y+1;  {coordenada onde desenho o próximo ovo, x é o mesmo}
        desenha_ovo;
        delay(500)
      END
    END.
        

O que "desenha_ovo" faz? Desenha um ovo na posição x,y (veja abaixo):

x x+1 x+2
y *
y+1 * *
y+2 * *
y+3 *

E "apaga_ovo"? Desenha o mesmo ovo, só que com espaços em vez de *. O corpo do programa faz, então, a animação.

Obs: Notou a falta de ";" no último write dos procedimentos, no delay do FOR e no END do FOR? Isso funciona porque antes de um END o ";" não é necessário. Tudo funciona se você colocar, mas não é necessário.

Pronto. Estamos derrubando o ovo. Mas note uma coisa: a velocidade de queda é constante. O tempo entre cada desenhar do ovo é constante, ou seja, se o ovo cai 20 posições, o fará em tempo 20 × t (tempo do atraso), a uma velocidade de 1 pos/t. Mas, e se quisermos incluir uma aceleração? Basta variarmos o atraso a um passo constante. Por exemplo:

Passo Atraso
1 0.5
2 0.4
3 0.3
4 0.2

O programa leva cada vez menos tempo para percorrer a mesma distância de um passo, ou seja, a velocidade está aumentando. Como a redução do tempo se dá em um passo constante, a velocidade aumenta em um passo constante também, ou seja, a aceleração é constante.

Então, se quisermos incluir uma gravidade em nossa queda, teríamos que fazer algo assim:

 desenha_ovo;
 delay(60 * g); {600 para g = 10}

 FOR c := yin TO (yin+20) DO
 BEGIN
   apaga_ovo;
   y := y+1;  {coordenada onde desenho o próximo ovo, x é o mesmo}
   desenha_ovo;
   delay((60 - c) * g) {reduz o tempo de g em g}
 END
        

Obs: Lembre-se de que delay aceita somente valores inteiros positivos.





‹— Parte VIIPágina da disciplinaParte IX —›