1 de junho de 2020

Iniciando e usando os controles no SGDK

Neste post vou explicar como fazer o Mega Drive reconhecer os botões pressionados no controle. A estrutura do código permanece a mesma ao código anterior, só vamos fazer algumas adições.



Vamos ao código:


#include <genesis.h>
static void meuJoy();

int main(){
VDP_drawText("Botoes pressionados:", 1,1);
    while(1){
        meuJoy();
        VDP_waitVSync();
}
return (0);
}

void meuJoy(){
u16 botao = JOY_readJoypad(JOY_1);

if (botao == BUTTON_RIGHT){
    VDP_drawText ("Voce apertou o botao RIGHT:",1,2);
} else if (botao == BUTTON_LEFT) {
    VDP_drawText ("Você apertou o botao LEFT:",1,2);
} else if (botao == BUTTON_UP) {
    VDP_drawText ("Você apertou o botao UP:",1,2);    
} else if (botao == BUTTON_DOWN){
    VDP_drawText ("Você apertou o botao DOWN:",1,2);
} else if (botao == BUTTON_START) {
    VDP_drawText ("Você apertou o botao START:",1,2);
} else if (botao == BUTTON_A) {
    VDP_drawText ("Você apertou o botao A:",1,2);
} else if (botao == BUTTON_B) {
    VDP_drawText ("Você apertou o botao B:",1,2);
} else if (botao == BUTTON_C) {
    VDP_drawText ("Você apertou o botao C:",1,2);
} 
}
Vamos analisar o código gerado pelo Visual Studio:
#include <genesis.h>
Esta linha de cmando é "obrigatório" em qualquer programa criado para o Mega Drive. É responsável por importar todas as bibliotecas contendo funções e constantes para poupar bastante trabalho.
int main()
{
...
...
...  
return (0);
}

Esta é a função principal. Não vou entrar em detalhes, mas todo código C precisa fazer parte de alguma função, portanto é obrigatório em qualquer código. O código ficará entre os "{ }". Já o return(0) indica que a função retornará um valor (no caso 0) que não vai ter serventia nenhuma. 
VDP_drawText("Botoes pressionados:", 1,1);
Esta é uma chamada de função que foi importada pelo #include_ <genesis.h>_. Neste caso é responsável por usar o processador de vídeo VDP do Mega Drive para escrever na tela. A estrutura deste comando é: VDP_drawText que é a chamada da função e mais 3 argumentos que ficarão entre (parênteses). O primeiro argumento é uma "string", ou seja, o que vai ser escrito (Botoes pressionados). O segundo é a posição da tela no eixo x (1) e o terceiro no eixo y (1). Lembrando que a tela no Mega é divido em quadrados (tiles) de 8x8 pixels, portanto esses valores não são em pixels.
while(1)
{
...
...
}
A partir daqui o programa teoricamente já funcionaria, porém é preciso fazer com que o código não termine. Pois chegando em return(0) o código acabaria e o seu "homebrew" travaria. Para isso é necessário colocar uma estrutura de repetição para que o código nunca acabe e o comando while() faz isso. Tudo o que está entre "{}" será executado em loop para sempre (a não ser que faça alguma condição para sair do loop, mas que não é o caso).
VDP_waitVSync();
E finalmente essa também é uma chamada de função igual o VDP_drawText. Porém não entramos com nenhum argumento. Sua função é esperar uma atualização de tela CRT, que é o momento que o feixe de elétrons da "TV" sai do canto inferior direito e recomeça no canto superior esquerdo. Esta é uma função necessária nos códigos para que não ocorra "flickering" entre uma atualização de tela e outra. É comum colocá-la no final do código, porém a medida que o código for ficando mais complexo, vai precisar gerenciar melhor esta função ao longo do código.

Dica: Na pasta "/doc/html" de onde está descompactado o SGDK, podemos pesquisar todas as funções da biblioteca. É útil para se familiarizar com as funções e seus argumentos necessários.

Agora vamos nos concentrar nos comandos relacionados aos cotroles:
static void meuJoy();
Este comando é puro da linguagem C... não faz parte da biblioteca do SGDK. Aqui estou dizendo pro programa que vai ter uma função chamada "meuJoy" no código (pode ser qualquer nome), ou seja, estou definindo uma função estática que vou chamá-la mais tarde. 
Não é obrigatório definir uma função. Poderia colocar todo o código dentro da função "main", mas esta é uma boa prática de programação, separar as funções para só ir chamando mais tarde, para não precisar redigitá-las.
meuJoy();
Aqui estou, da fato, chamando minha função "meuJoy". Notem que ela está dentro da estrutura de repetição "while(1) {...}". Isso porque precisamos que o hardware leia o tempo inteiro o controle, caso contrário vai ler apenas uma vez (isso se der tempo). Como havia escrito, esta estrutura de repetição infinita "while(1) {...}" é obrigatório para que o código não finalize e "trave" o jogo.
void meuJoy(){
...
}
Esta é a própria função. Tudo o que está dentro do "{ }" vai ser executado toda vez que o código "meuJoy();" é lido.
u16 botao = JOY_readJoypad(JOY_1);
Aqui estou dizendo pro programa que é para atribuir o valor do botão pressionado no controle 1 (função "JOY_readJoypad(JOY_1);" lê o que você aperta no controle) à uma variável chamada "botao". O "u16" é para dizer pro programa que este é um valor de 16bits. Esta variável vai ser utilizada para ler o valor que tem nela.
if (botao == BUTTON_RIGHT){
...
}
Esta é uma estrutura chamada condicional, ou seja, que só vai ser executada o que está entre "{ }" se certa condição for verdadeira. A condição está entre parêntese "(botao == BUTTON_RIGHT)". Resumindo: se (valor da variável "botao" é igual ao valor do botao "up") execute o que está entre "{ }", se não pode pular.
VDP_drawText("Voce apertou o botao RIGHT:",1,2);
Este comando já havia explicado. Vai escrever na tela o que está entre " " , neste caso, na posição X=1 e Y=2.

O comando "else if" (também estrutura condicional) faz a mesma coisa que o "if" e no código está fazendo a mesma coisa que o botão RIGHT, mas para os outros botões. Então se for o botão "LEFT" que foi pressionado, o programa simplesmente pula toda a estrutura do "RIGHT" e assim por diante com os outros botões.

Assim que o código da função "void meuJoy()" acabar "}" (quando chega no último colchete), o código vai voltar para o próximo comando depois do "meuJoy();" (dentro do "while") e em seguida vai executar o "VDP_waitVSync();", para logo retornar pro "meuJoy();". Notem que esses dois comandos estão dentro dos colchetes "{ }" do while, portanto, eles vão ser repetidos infinitamente.

Obs.: Neste código não tem a Alis. Foi só um gostinho para o próximo post.

O próximo tutorial vou tentar explicar e mostrar como jogar tiles e sprites na tela. 

Um comentário: