Tutoriais

Programar Jogo na Linguagem C

Esse tutorial é indicado para iniciantes.

O tutorial mostra passo-a-passo como desenvolver um joguinho simples.



O foco do tutorial é escrita de código, mas além disso também é necessário instalar um compilador.

Download do Compilador

Esse arquivo contém o compilador.

Compilador é um software que recebe código-fonte e transforma em arquivo executável.

Baixe o compilador e extraia a pasta 'Tutorial' para a área de trabalho.

Começando a Escrever

Para ver como compilar abra o bloco de notas e digite:
hello world
Salve o arquivo na pasta 'Tutorial'

Clique em "Arquivo -> Salvar Como"

Dê o nome "jogo.c" para o arquivo.

No campo "Tipo" selecione a opção "Todos os Arquivos"



Com isso a gente já criou o arquivo que vai conter o código-fonte que o compilador vai transformar em executável.

Mas por enquanto o conteúdo do arquivo ainda não é código-fonte.

A linguagem C tem umas regras que esse tutorial vai explicar.

Conhecendo o Compilador

Para começar vamos tentar compilar esse arquivo:

Com as teclas de atalho 'windows + r' o windows abre uma janelinha para receber um comando:



Digite "cmd" e aperte "enter".

Isso abre a tela do prompt/ms-dos

Digite "cd Desktop"

Isso significa "change directory para a área de trabalho"

Depois digite "cd Tutorial"



O compilador está dentro da pasta 'tcc' mas não vamos andar até lá porque o código-fonte está na pasta 'Tutorial'.

O comando para usar o compilador fica:
tcc\tcc jogo.c

Código em Linguagem C

Quando esse comando é executado o compilador exibe uma 'mensagem de erro' na janelinha do ms-dos.
Porque esse código é inválido.



Vamos editar o arquivo 'jogo.c' para que o compilador gere um arquivo executável.

Digite:
#include<stdio.h>
int main(){
	printf("hello world");
	return 0;
}
e salve.

Nessas cinco linhas tem um código-fonte que o compilador entende.

Se mandar para o compilador (com o comando 'tcc\tcc jogo.c') ele deve gerar um arquivo executável.
Se ele exibir alguma 'mensagem de erro' pode ser erro de digitação ou o ms-dos não está no diretório 'Tutorial'

Essa linha do 'include' desbloqueia a função 'printf' (que serve para exibir uma mensagem na tela)

Essa linha do main() indica para o compilador que aí começa o código.

A linha 'printf' envia essa string para a tela.

Arquivo Executável

Com o comando 'tcc\tcc jogo.c' um arquivo chamado jogo.exe deve ser gerado.

Esse arquivo pode ser executado com duplo-clique do mouse mas por enquanto vamos utilizar o ms-dos para executá-lo.

Digite 'jogo.exe'

Se tudo está certo, uma mensagem "hello world" deve ser exibida no prompt !

Isso significa que o comando 'printf' funcionou
o 'include' funcionou
a 'função main' funcionou
o compilador funcionou
e o executável funcionou.

Agora vamos editar esse código-fonte para começar a programar o joguinho.

Tiny C Compiler & dos-like

Os arquivos dentro da pasta 'dos-like' são uma extensão do compilador 'tcc'

tcc é 'tiny C compiler'

O conteúdo da pasta 'dos-like' são uns arquivos que servem para que o desenvolvedor gere softwares baseado em 'ms-dos'.
É tipo uma homenagem à época do início da popularização da computação.

A iniciativa 'dos-like' é interessante para nós porque serve para mostrar como era programar computadores nessa época.

À partir daqui esse tutorial não vai mais usar o comando printf

Modo Gráfico

O jogo utilizará o modo gráfico do ms-dos para desenhar os elementos na tela

A linha do 'include stdio' pode ser apagada

Vamos usar o comando include para vincular o código da iniciativa dos-like
#include "dos-like/dos.h"
A linha do 'printf' deve ser apagada.

No seu lugar vai a linha que coloca a tela no modo grafico do ms-dos:
	setvideomode(videomode_320x200);
Dentro de um loop (que é encerrado quando o user pressiona 'Esc') vão os comandos que desenham na tela

O comando que escolhe a cor cinza claro para desenhar o background do jogo:
		setcolor(15);
Uma variável chamada background amazena 8 números correspondentes a 4 coordenadas (x,y) do background
(20,30)=canto superior esquerdo
(300,30)=canto superior direito
(300,100)=canto inferior direito
(20,100)=canto inferior esquerdo
		int background[8]={20,30,300,30,300,100,20,100};
O comando fillpoly preenche na tela o retângulo descrito nessas 4 coordenadas.
		fillpoly(background,4);
A função waitvbl é parte importante da biblioteca dos-like

O código do arquivo jogo.c fica:
#include "dos-like/dos.h"
int main(){
	setvideomode(videomode_320x200);
	while(!keystate(KEY_ESCAPE)){
		setcolor(15);
		int background[8]={20,30,300,30,300,100,20,100};
		fillpoly(background,4);
		waitvbl();
	}
	return 0;
}
Para compilar (gerar o arquivo executável) o comando mudou para:
tcc\tcc jogo.c dos-like\dos.c
(porque é preciso vincular o 'dos-like' no executável)

Verifique se o prompt exibe alguma 'mensagem de erro'.
Se tudo ocorreu bem o arquivo jogo.exe foi gerado novamente e ele agora exibe uma tela assim:

Desenhando o Obstáculo

Ainda dentro do loop vamos criar uma variável obs1 que vai armazenar 6 números.

São as coordenadas dos vértices de um triângulo.

O obstáculo irá se mover pela tela, mas por enquanto ele fica fixo em uma posição.
		setcolor(12);
		int obs1[6]={292,98,296,88,300,98};
		fillpoly(obs1,3);
Quando gera novamente o arquivo (e executa ele), a tela deve ficar assim:



Verifique se não tem erro na hora de gerar o .exe pois pode acontecer de não gerar um novo arquivo e você rodar uma versão (do exe) sem as alterações

Fazendo o obstáculo se mover

A gente cria uma variável obstaculo1 com a posição do obstáculo.

Daí a gente incrementa o valor dessa variável de tempos em tempos (milissegundos)

E desenha novamente o background e o obstáculo (na posição atualizada)
#include "dos-like/dos.h"
int main(){
	int obstaculo1=0;
	setvideomode(videomode_320x200);
	while(!keystate(KEY_ESCAPE)){
		setcolor(15);
		int background[8]={20,30,300,30,300,100,20,100};
		fillpoly(background,4);
		setcolor(12);
		obstaculo1=(obstaculo1+3)%274;
		int obs1[6]={292-obstaculo1,98,296-obstaculo1,88,300-obstaculo1,98};
		if(obstaculo1>0)fillpoly(obs1,3);
		sleep(20);
		waitvbl();
	}
	return 0;
}
A função sleep serve para 'esperar passar' 20 milissegundos (e depois continuar...)

Desenhando o Joe

		setcolor(2);
		int cabeca[8]={52,80,56,80,56,83,52,83};
		fillpoly(cabeca,4);
		int bracos[8]={48,84,60,84,60,86,48,86};
		fillpoly(bracos,4);
		int tronco[8]={53,86,56,86,56,91,53,91};
		fillpoly(tronco,4);
		int pernadir[8]={52,91,54,91,54,98,52,98};
		fillpoly(pernadir,4);
		int pernaesq[8]={55,91,57,91,57,98,55,98};
		fillpoly(pernaesq,4);

Fazendo o Joe Pular

Assim como para alterar a posição do obstáculo basta alterar uma variável...
com o Joe também será assim.

A variável altura indicará onde o Joe será desenhado.

As variáveis cabeça,braços,tronco e pernas terão valores baseados na altura.
	int altura=0;
		int cabeca[8]={52,80-altura,56,80-altura,56,83-altura,52,83-altura};
		fillpoly(cabeca,4);
		int bracos[8]={48,84-altura,60,84-altura,60,86-altura,48,86-altura};
		fillpoly(bracos,4);
		int tronco[8]={53,86-altura,56,86-altura,56,91-altura,53,91-altura};
		fillpoly(tronco,4);
		int pernadir[8]={52,91-altura,54,91-altura,54,98-altura,52,98-altura};
		fillpoly(pernadir,4);
		int pernaesq[8]={55,91-altura,57,91-altura,57,98-altura,55,98-altura};
		fillpoly(pernaesq,4);
Para tratar o pulo serão necessárias 5 condições:
  • se o joe está no chão e começa o pulo
  • se o joe está subindo
  • se o joe está descendo
  • o momento que ele para de subir
  • o momento que ele para de descer
  • 		if(altura==0&&keystate(KEY_UP))altura=5;
    		if(altura%4==1)altura+=4;
    		if(altura%4==3)altura-=4;
    		if(altura>28)altura=31;
    		if(altura<2)altura=0;

    Acabamento

    Na versão final está implementada a detecção da colisão e um 'restart da fase':
    #include "dos-like/dos.h"
    int obstaculo1,obstaculo2,obstaculo3,altura,gameover;
    void init(){
    	obstaculo1=-250;
    	obstaculo2=-250;
    	obstaculo3=-250;
    	altura=0;
    	gameover=0;
    }
    int main(){
    	setvideomode(videomode_320x200);
    	init();
    	while(!keystate(KEY_ESCAPE)){
    		if(gameover!=0){
    			if(keystate(KEY_UP))init();
    		}else{
    			if(altura==0&&keystate(KEY_UP))altura=5;
    			if(altura%4==1)altura+=4;
    			if(altura%4==3)altura-=4;
    			if(altura>28)altura=31;
    			if(altura<2)altura=0;
    			setcolor(15);
    			int background[8]={20,30,300,30,300,100,20,100};
    			fillpoly(background,4);
    			setcolor(2);
    			int cabeca[8]={52,80-altura,56,80-altura,56,83-altura,52,83-altura};
    			fillpoly(cabeca,4);
    			int bracos[8]={48,84-altura,60,84-altura,60,86-altura,48,86-altura};
    			fillpoly(bracos,4);
    			int tronco[8]={53,86-altura,56,86-altura,56,91-altura,53,91-altura};
    			fillpoly(tronco,4);
    			int pernadir[8]={52,91-altura,54,91-altura,54,98-altura,52,98-altura};
    			fillpoly(pernadir,4);
    			int pernaesq[8]={55,91-altura,57,91-altura,57,98-altura,55,98-altura};
    			fillpoly(pernaesq,4);
    			setcolor(12);
    			obstaculo1=(obstaculo1+3)%274;
    			obstaculo2=(obstaculo2+4)%274;
    			obstaculo3=(obstaculo3+5)%274;
    			int obs1[6]={292-obstaculo1,98,296-obstaculo1,88,300-obstaculo1,98};
    			int obs2[6]={292-obstaculo2,98,296-obstaculo2,88,300-obstaculo2,98};
    			int obs3[6]={292-obstaculo3,98,296-obstaculo3,88,300-obstaculo3,98};
    			if(obstaculo1>0)fillpoly(obs1,3);
    			if(obstaculo2>0)fillpoly(obs2,3);
    			if(obstaculo3>0)fillpoly(obs3,3);
    			if(obstaculo1>232&&obstaculo1<242&&altura<9)gameover=1;
    			if(obstaculo2>232&&obstaculo2<242&&altura<9)gameover=1;
    			if(obstaculo3>232&&obstaculo3<242&&altura<9)gameover=1;
    			sleep(20);
    			waitvbl();
    		}
    	}
    	return 0;
    }