Saída da 1ª animação em modo texto. Bem vindo à Matrix! :) |
E por que alguém faria isto em pleno ano de 2014 com tantas opções e tantas tecnologias capazes de renderizar imagens super realistas em hardwares comuns e baratos? - eu até posso ouvir você perguntando.
Pelo prazer e pelo desafio, ora bolas! Sinceramente, precisa de mais que isto?
Então vamos começar nos familiarizando com o console dentro do Windows. Segundo a documentação da Microsoft
Consoles gerenciam inputs e outpus (I/O) para aplicações em modo caractere (aplicações que não providenciam sua própria interface gráfica).
Então, como primeira e mais importante restrição, temos a impossibilidade de acessar qualquer tipo de modo gráfico. Nossa tela é capaz de exibir 25 linhas de 80 caracteres em possui uma paleta de 16 cores.
Um... caracteres coloridos na tela? Que tal simular um efeito "matrix" pra começar nossa exploração?
Vamos lá.
Crie uma nova aplicação console em seu ambiente (Delphi ou Lazarus), salve-a com o nome de matrix e você vai ter um código parecido com este :
program matrix; {$APPTYPE CONSOLE} uses SysUtils; begin try { TODO -oUser -cConsole Main : Insert code here } except on E: Exception do Writeln(E.ClassName, ': ', E.Message); end; end.
Apague todo o código entre o
begin
e o end
e substitua SysUtils
na clásula uses
pela unit Windows
(vamos utilizar somente a API do windows neste primeiro programa). Feito isto, escreva o código conforme a listagem abaixo, execute e veja o efeito funcionando.program matrix; {$APPTYPE CONSOLE} uses windows; const SCREEN_W = 80; //largura da tela SCREEN_H = 25; //altura da tela var stdOut : THANDLE; //handler da janela do console position : COORD; //posição em que vamos imprimir o caracter (x, y) attribute: Word; //atributos de saída de texto no console begin randomize; stdOut := GetStdHandle(STD_OUTPUT_HANDLE); while hi(GetKeyState(VK_ESCAPE)) = 0 do begin position.X:= short(random(SCREEN_W-1)); position.Y:= short(random(SCREEN_H-1)); if (Random(10) mod 2 = 0) then attribute:= FOREGROUND_GREEN else attribute:= 10; SetConsoleTextAttribute(stdOut, attribute); SetConsoleCursorPosition(stdOut, position); if (Random(10) mod 2 = 0) then write('0') else write('1'); end; end.
Ok, há espaços para várias melhorias, mas é um bom ponto de partida. Vamos entender o código.
O algoritmo aqui é o mais básico possível, simplesmente vamos imprimir zeros e uns em dois tons de verde em posições aleatórias na tela em um loop que só termina quando pressionamos a tecla
ESC
.Começamos definindo as constantes que representam os limites da tela (
SCREEN_H
e SCREEN_W
) e as variáveis que serão necessárias para as chamadas da API
que utilizaremos. Depois inicializamos o gerador de números pseudo-aleatórios chamando a função randomize
e terminamos nossas inicializações recuperando o handler de saída da nossa janela com a função GetStdHandle
.Em seguida, iniciamos nosso loop verificando, através da função
GetKeyState
, se a tecla ESC
não foi pressionada e, a cada iteração escolhemos uma posição aleatória (linhas 17 e 18), um tom de verde entre as duas opções que temos na paleta (linhas 19 até 22), preparamos o terminal com as opções escolhidas (linhas 23 e 24) usando as funções SetConsoleTextAttribute
e SetConsoleCursorPosition
e, finalmente, escrevemos 0 ou 1 na tela.Seguindo os links para a documentação das funções da API do windows, o código deve ser bem fácil de acompanhar para quem possui um conhecimento básico na linguagem. Talvez a única parte que mereça um comentário adicional é a função
hi
usada no teste do loop. Esta função serve para verificar o valor do byte mais significativo do valor inteiro retornado por GetKeyState
.Sempre que estivermos interagindo com a API do windows e com boa parte das APIs escritas em C, vamos utilizar operações de manipulação de bits. Aqui você encontra um texto explicando o que é o bit mais significativo de um valor e aqui está documentação da função
hi
no free pascal. A leitura vale muito à pena.Enfim, código compilado rodando e totalmente compreendido, vamos ao próximo post onde iremos realizar algumas melhorias no efeito.