segunda-feira, 22 de fevereiro de 2010

Tile Builder

OBS: Antes o nome dessa bagunça aqui era "Tile Master". Agora é "Tile Builder" (porque eu desenvolvi outro programa - muito melhor - chamado Tile Master)

Tile Builder
é um minúsculo programa que eu desenvolvi, que implementa uma "tile engine". Leia a seguir para saber mais. E clique no link abaixo para fazer o download dos arquivos (compactados num arquivo .zip de 12KB):

Nota da versão 1.1 - Corrigi o bug do Screen::erase_tile() e adicionei a classe Entity. Veja o arquivo leia-me.txt

Clique aqui para baixar Tile Builder 1.1 (23/02/2010)
Clique aqui para baixar Tile Builder 1.0 (22/02/2010)

ATENÇÃO: Tile Master utiliza a biblioteca Allegro para gerar os gráficos! Caso você ainda não tenha Allegro instalado, dê uma olhada na minha postagem sobre como baixar e instalar Allegro no ambiente Dev-C++ no Windows:

http://fernando-aires.blogspot.com/2010/02/allegro-uma-biblioteca-em-c-para.html


O que é Tile Master?

Tile Master é uma espécie de "tile engine", que pode ser usada para desenvolver jogos com gráficos baseados em blocos (tiles) no estilo do NES (Nintendo Entertainment System), ou como se conhece no Brasil, o Nintendinho 8-bit dos anos 80. Todo o programa foi escrito em C++ e usa a biblioteca Allegro como base. Tudo foi compilado no ambiente Dev-C++ com MinGW no Windows.


Como usar?

Todo o código da classe Screen está bem comentado, e deve ser tudo auto-explicativo, mas eu vou dar uma explicação bem breve aqui:

1. Arquivo screen.h
Esse arquivo contém a declaração (ou definição se você preferir) da classe Screen. Essa classe é a única responsável por gerenciar a tela, com as cores do NES, e criar/manipular os blocos gráficos (os tiles).

2. Arquivo screen.cpp
Esse arquivo contém a implementação da classe Screen.

3. Arquivo main.cpp
Esse arquivo só existe para você testar a classe Screen. Ele já contém um pequeno main() com a criação de um objeto Screen e a chamada do método test(), que simplesmete mostra o tipo de coisa que Tile Master faz (coisa bem simples).

4. Arquivo NES_palette.png
Esse arquivo de imagem mostra a paleta de cores do NES. Como eu implementei a paleta de cores do Tile Master pra ter as cores praticamente idênticas às cores do NES, cada entrada da paleta do Tile Master corresponde à entrada da paleta do NES. Então use essa tabela para obter o código hexadecimal da cor desejada. Um detalhe: a entrada da paleta que contém a cor preta "oficial" do NES é a entrada 0x3f. Existe mais de uma entrada na paleta com uma cor "preta", mas essa é a oficial (eu não usaria a entrada 0x0d, pois essa cor é "mais do que preta"). Inclusive, eu usei um #define BLACK com o valor 0x3f justamente por isso.


O passo-a-passo mais básico

Pra ser bem breve, basta você criar uma instância da classe Screen. Ao fazer isso, automaticamente a tela será inicializada, com a paleta de cores do NES. Para criar um bloco gráfico (um tile), você precisa declarar e inicializar um array de char sem sinal (unsigned char), do tamanho de TILE_SIZE (que é definido como 64). Exemplificando, é assim que você declara um bloco:

unsigned char meu_bloco[TILE_SIZE] =
{
0, 0, 0, 0, 0, 0, 0, 0,
0, 0, 0, 0, 0, 0, 0, 0,
0, 0, 0, 0, 0, 0, 0, 0,
0, 0, 0, 0, 0, 0, 0, 0,
0, 0, 0, 0, 0, 0, 0, 0,
0, 0, 0, 0, 0, 0, 0, 0,
0, 0, 0, 0, 0, 0, 0, 0,
0, 0, 0, 0, 0, 0, 0, 0
};

Repare que cada 0 desses é um pixel que será plotado na tela. Trocando o número 0 por outro número (entre 0 e 3) você define o CÓDIGO de cor daquele pixel. Os pixeis com o código 0 terão a cor definida em tile_color0, os pixeis com o código 1 terão a cor definida em tile_color1, e assim por diante. Cada bloco pode ter até no máximo 4 cores (0, 1, 2 e 3). Se houver um código inválido no bloco (menor que 0 ou maior que 3), o pixel será transparente.

Para definir as cores do bloco antes de desenhá-lo na tela, use o método set_tile_colors(int cor0, int cor1, int cor2, int cor3), passando como argumento os índices da paleta de cor desejados. Para saber os índices da paleta que contém as cores que você deseja, olhe o arquivo NES_palette.png que vem junto com o pacote. Se você preferir pode procurar na Internet, digite no Google a frase "NES palette" que com certeza você vai encontrar. Então basta passar o código hexadecimal do índice da paleta por esse método para configurar as cores. Pra facilitar, aí embaixo está a paleta de cores do NES com os códigos hexadecimal para cada entrada da paleta:




Depois de chamar esse método para configurar as cores do bloco, chame o método draw_tile(unsigned char bloco[], int x, int y) para desenhar o bloco na tela com as cores especificadas. Como argumento passe o nome do array contendo os dados do bloco, e as coordenadas x e y da tela. Repare que as coordenadas da tela são ajustadas automaticamente para que seja possível "encaixar" os blocos um do lado do outro!

Basicamente é isso. Implementei uns métodos legais como invert_tile_colors() para inverter as cores dos blocos, randomize_tile_colors() para escolher as cores dos blocos aleatoriamente e fill(unsigned char bloco[]) para preencher a tela inteira com o mesmo bloco. E você pode criar outros métodos se quizer.

Se puder mande a sua versão pra eu ver depois :P


Os métodos da classe Screen

A seguir eu apresento a interface pública da classe Screen:

void cls()
Apaga a tela deixando o fundo da cor preta.

void cls(int indice_da_paleta)
Apaga a tela deixando o fundo da cor especificada pelo indice da paleta.

int color(int indice_da_paleta)
Retorna a cor que está no indice da paleta especificado

void set_tile_colors(int cor0, int cor1, int cor2, int cor3)
Define as quatro cores usadas para desenhar os próximos blocos gráficos:

cor0 = define o índice da paleta de cores em tile_color0;
cor1 = define o índice da paleta de cores em tile_color1;
cor2 = define o índice da paleta de cores em tile_color2;
cor3 = define o índice da paleta de cores em tile_color3;

void randomize_tile_colors()
Define aleatoriamente as quatro cores usadas para desenhar os próximos blocos gráficos.

void invert_tile_colors()
Inverte as cores usadas para desenhar os próximos blocos gráficos. Isso significa cor0=cor1, cor1=cor2, cor2=cor3 e cor3=cor0 (é um troca-troca)

void randomize_tile_data(unsigned char bloco[])
Define aleatoriamente os dados do bloco passado como argumento. Na prática isso serve mais é pra testar as funções da biblioteca.

void draw_tile(unsigned char bloco[], int x, int y)
Desenha o bloco gráfico passado como argumento nas coordenadas especificadas. O bloco será desenhado de acordo com os dados contidos no array bloco[]. Dependendo do valor (de 0 a 3) que estiver nos índices do array, esse método vai plotar um pixel da cor correspondente. Se o método encontrar um valor fora do intervalo válido (menor que 0 ou maior que 3) ele vai plotar um pixel transparente, isto é, da mesma cor que o fundo da tela. Então, ao escanear os valores nos índices do array bloco[], o método interpreta assim:

0 = plota um pixel da cor definida em tile_color0;
1 = plota um pixel da cor definida em tile_color1;
2 = plota um pixel da cor definida em tile_color2;
3 = plota um pixel da cor definida em tile_color3;
4 (ou qualquer outro número maior) = plota um pixel tranparente (da mesma cor do fundo da tela).

Para definir os valores de tile_color0, tile_color1, tile_color2 e tile_color3, basta invocar o método set_tile_colors(int color0, int color1, int color2, int color3) e passar como argumento os respectivos índices da paleta de cores desejados.

Defina um bloco SEMPRE assim:

unsigned char nome_do_bloco[TILE_SIZE] =
{
0, 0, 0, 0, 0, 0, 0, 0,
0, 0, 0, 0, 0, 0, 0, 0,
0, 0, 0, 0, 0, 0, 0, 0,
0, 0, 0, 0, 0, 0, 0, 0,
0, 0, 0, 0, 0, 0, 0, 0,
0, 0, 0, 0, 0, 0, 0, 0,
0, 0, 0, 0, 0, 0, 0, 0,
0, 0, 0, 0, 0, 0, 0, 0
};

E claro, substitua os 0 pelo código de cor desejado (de 0 a 3, ou outro número para representar os pixeis tranparentes). E não esqueça de definir as cores do bloco antes de desenhá-lo! Se você definir as cores dos blocos com set_tile_colors() isso afetará TODOS os blocos desenhados DEPOIS de chamar esse método, ou seja, os blocos desenhados ANTES não serão afetados.

void draw_tile_ex(unsigned char bloco[], int x, int y,
int cor0, int cor1, int cor2, int cor3)
É uma combinação dos métodos set_tile_colors() e draw_tile().

void erase_tile(int x, int y)
Apaga o bloco que foi desenhado nas coordenadas especificadas. O que esse método faz é criar um outro bloco "zerado" da mesma cor do fundo da tela, e colocar no lugar indicado. É como substituir um bloco colorido por um bloco invisível :P

void fill(unsigned char bloco[])
Preenche a tela inteira com o bloco gráfico especificado.

void fill_ex(unsigned char bloco[], int cor0, int cor1, int cor2, int cor3)
É uma combinação dos métodos set_tile_colors() e fill().

void fill_rect(unsigned char bloco[], int x, int y, int largura, int altura)
Desenha um retângulo nas coordenadas e dimensões especificadas, usando o bloco gráfico especificado como "recheio".

void test()
Executa um teste bem simples para ver o Tile Master funcionando.


Contato

Se você tem dúvidas, sugestões ou críticas, me envie um e-mail:

romeno19@gmail.com