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.