|
MC102 |
| 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.