A primeira regra de qualquer jogo é a colisão. É claro que isso só inclui 99,99% dos jogos. return (pixelcolor == surface->format->colorkey); int SDL_CollideBoundingBox(SDL_Rect a, SDL_Rect b){ int SDL_CollideBoundingCircle(int x1, int y1, int r1, int x2, int y2, int r2, int offset){ bool Play::mov(int movX,int movY,Mapa *mapa){ bool Play::mov2(int movX,int movY,Mapa *mapa){ int SDL_CollideBoundingBox(SDL_Rect a, SDL_Rect b){
Como será o sistema de colisão em seu jogo é um fator determinante pra conclusão do projeto.
Como sempre tenho a SDL sempre a mão e para resolver este problema vou apresentar a SDL_Collide.
» Post Completo...*** SDL_Collide ***
Esta não é mais uma biblioteca de dependência para seu código, na verdade eu a considero como uma biblioteca de referência. Digo isso porque SDL_Collide possui apenas 240 linhas de código (totalmente comentadas) e estudando a lógica das funções (apenas 6) você é capaz de otimizar as suas.
int SDL_CollideTransparentPixel(SDL_Surface *surface, int u, int v);
Esta Função serve apenas para testar se um pixel[u][v] é ou não transparente.
É uma função que acessa um pixel (meio complicado de explicar) e no final compara com o colorkey da imagem.
int SDL_CollidePixel(SDL_Surface *as, int ax, int ay, SDL_Surface *bs, int bx, int by, int skip = 4);
Esta função faz um teste de colisão em pixel precisão. É muito lenta.
Por exemplo: SDL_CollidePixel("verde_claro",0,0,"verde_escuro",4,2,2);
Como é mostrado acima, o exemplo faria teste de colisão nos pixels de intercessão entre as imagens. O parâmetro skip (2) indica quantos pixels saltar (1 faz teste completo).
O exemplo retornou verdadeiro. Branco é nossa cor de transparência e a colisão foi detectada apenas uma vez.
int SDL_CollideBoundingBox(SDL_Surface *sa, int ax, int ay, SDL_Surface *sb, int bx, int by);
e
int SDL_CollideBoundingBox(SDL_Rect a, SDL_Rect b);
São responsáveis pela colisão entre retângulos e são muito rápidas.
if(b.x + b.w < a.x) //- b.direita < a.esquerda
return 0;
if(b.x > a.x + a.w) //- b.esquerda > a.direita
return 0;
if(b.y + b.h < a.y) //- b.baixo < a.cima
return 0;
if(b.y > a.y + a.h) //- b.cima > a.baixo
return 0;
return 1; //- retângulos se colidem
}
Repare que a colisão só existe quando todos os testes falham. O algoritmo procura por algum lado que possa eliminar a colisão totalmente.
int SDL_CollideBoundingCircle(int x1, int y1, int r1, int x2, int y2, int r2, int offset);
Faz a comparação de colisão entre circulos. x e y são coordenadas do centro. use offset como 0 (deve ser alguma medida de precisão).
int xdiff = x2 - x1; //- diferença no eixo x
int ydiff = y2 - y1; //- diferença no eixo y
/* Distância entre os centros dos círculos ao quadrado */
int dcentre_sq = (ydiff*ydiff) + (xdiff*xdiff);
/* Calcula a soma dos raios ao quadrado */
int r_sum_sq = r1 + r2;
r_sum_sq *= r_sum_sq; //- melhor que (r1+r2)*(r1+r2)
return (dcentre_sq - r_sum_sq <= (offset*offset));
}
Esta função está bem otimizada, tanto é que, para calcular a distância não foi utilizada a raiz quadrada.
A distância não é realmente necessária, ela serve apenas como comparativo. Como o cálculo da raiz quadrada não é uma operação trivial, é preferível comparar todas as somas (raios e dx dy) em potência de 2.
int SDL_CollideBoundingCircle(SDL_Surface *a, int x1, int y1, SDL_Surface *b, int x2, int y2, int offset);
É uma variação da função anterior onde o raio do circulo é calculado por aproximação (r1 = (a.w+a.h) / 4).
Download: SDL_Collide (o código fonte já vem com a versão )
*** O exemplo ***
Aproveitando o código anterior, criei um jogo de labirinto com itens (quase um Pac-Man) para que ficasse bem claro como pode ser feita a implementação de um jogo com colisões.
Para que ficasse funcional acabei complicando o código. Por isso vou explicar algumas das funções que realmente importam.
Não é sempre que se pode mover em todas as direções que pede o jogador, e é isso que a função mov() irá tratar:
if( !mov2(movX,movY,mapa) ){ //- teste de movimento em x e y
if( !mov2(movX,0,mapa) ){ //- teste de movimento em x
if( !mov2(0,movY,mapa) ) //- teste de movimento em y
return 0;
}
}
pegaItem(mapa);
return 1;
}
SDL_Rect aux = {box.x+movX,box.y+movY,box.w,box.h}, ret;
int x,y,i,j,colisao;
char t; //- tile
x = aux.x/W; //- coordenada x no mapa (aproximada)
y = aux.y/H; //- coordenada y no mapa (aproximada)
//- loop nos tiles vizinhos
for(j=-1;j<2;j++){ //- -1,0,1
for(i=-1;i<2;i++){ //- -1,0,1
try{
t = mapa->tile(x+i,y+j);
}catch(...){ //- fora da grade
continue;
}
mapa->getRect(x+i,y+j,ret);
colisao = SDL_CollideBoundingBox(aux,ret);
if(colisao && (t==1 || t>3) ){ //- colisao com paredes
//printf("colisao> %d,%d x %d,%d\n",aux.x,aux.y,ret.x,ret.y);
return 0;
}
}
}
box.x += movX;
box.y += movY;
return 1;
}
if(b.x + b.w <= a.x) return 0;
if(b.x >= a.x + a.w) return 0;
if(b.y + b.h <= a.y) return 0;
if(b.y >= a.y + a.h) return 0;
return 1;
}
Fazer colisão usando o retângulo da própria imagem pode não ser uma boa. Meu personagem tem 32x32 e seu retêngulo de colisão apenas 20x20.
A movimentação não ficou muito boa. A explicação para isso é que não tratamos as colisões da melhor forma, pois sempre que há uma colisão não se faz absolutamente nada para corrigir.
Então é só ! Analise o código fonte para entender os detalhes.
Download: » código fonte
*** SinucaOS ***
Não tem como a gente falar de colisão de círculos sem lembrar de um jogo de sinuca.
Acredite, fazer um jogo de sinuca é realmente difícil. A física de um jogo de sinuca exige muito mais do que se pode ver. A tacada inicial, por exemplo, é uma explosão de colisões e isto fragiliza a implementação.
SinicaOS é um grupo que está desenvolvendo um jogo de sinuca open source em C e Allegro. Por enquanto, o foco principal é ter um simulador de física funcional.
A imagem acima(animação gif) mostra duas bolas grudadas no terceiro quadro. Isto mostra que não são poucos os problemas enfrentados.
Pode ser um bug do jogo, mas o grande causador deste problema é a quantidade de bolas, a proximidade entre elas e a alta precisão exigida. A maioria dos bons jogos de sinuca sobrem deste mesmo mal.
*** Link's ***
Download: » código fonte
» SDL - Site oficial
» SDL_Collide - Site do projeto
---
Feliz Natal !!!
.:: Menu Rápido ::.
Linux | C/C++ | Downloads | SDL | [×]A melhor maneira de se descobrir uma lib gratuita é nos repositórios do Ubuntu: $apt-cache search lib <palavra_chave> dev
Ou pelo devpaks.org, mas o repositório tem me ajudado mais !!!
- Script's GIMP - Python-Fu !!!
- Dicas Web
- Vídeo Compiz Fusion (Desktop 3D)
- Compilando com gcc e Makefile
- Que tal mudar para Ubuntu ?!
- SDL - A Biblioteca dos Jogos 2D
- Analisador léxico de arquivos script
- Simpatizando com a Libxml2
- AsciiGen - Tabela ASCII em C
- Conexão com API C do MySQL
- Compilando com gcc e Makefile
- DR Tetris 0.3 - Tetris no estilo tradicional !
- DR Quebra-Cabeça disponível para download !!!
- Freeggs - Liberdade aos ovos \o/
Se você quer aprender a programar jogos... SDL !!!
- Carregando mapas 2D no formato TMX
- Controle de tempo e Frame Rate
- SDL em Processamento de Imagens
- SDL_Surface - Introdução detalhada
- Imprimindo texto com SDL_Ttf
- SDL_Collide - Colisão 2D para jogos
- Tocando música e sons com SDL_mixer
- Gerando e carregando mapas 2D em jogos
- SDL - A Biblioteca dos Jogos 2D
sábado, 22 de dezembro de 2007
SDL_Collide - Colisão 2D para jogos
A primeira regra de qualquer jogo é a colisão. É claro que isso só inclui 99,99% dos jogos.
Como será o sistema de colisão em seu jogo é um fator determinante pra conclusão do projeto.
Como sempre tenho a SDL sempre a mão e para resolver este problema vou apresentar a SDL_Collide.
» Post Completo...
Postado por Diogo_RBG 6 comentários
quarta-feira, 12 de dezembro de 2007
1.000 Visitantes \o/
Agradeço a força de todos vocês ! Pois hoje a marca de 1.000 visitantes foi atingida !!!
Foram apenas 14 motivos para visitarem meu blog e são mais de 1.000 motivos para que eu continue com meu trabalho feito em horas vagas !!!
É com grande satisfação que apresento:
Postado por Diogo_RBG 3 comentários
Tópicos: off-topic
Tocando música e sons com SDL_Mixer
SDL é uma biblioteca básica, mas possui muitas bibliotecas de apoio. Uma delas é a SDL_Mixer. #include <SDL/SDL_mixer.h> void init(){ void carregar(){ Mix_PlayMusic( musica, -1 ); Mix_PlayChannel( -1, bomba, 0 );
De acordo com alguns tutoriais que andei vendo por aí, a forma mais fácil de tocar música e efeitos sonoros em seu jogo feito em SDL é com SDL_Mixer.
Além de suportar mais formatos (wav, mp3, ogg, mid(Timidity instalado), ...) você não tem que se preocupar com a função callback que é utilizada na SDL.
Siga este passo a passo de como deixar o seu jogo mais divertido !!!
» Post Completo...*** Instalando ***
Certifique-se que a lib SDL já esteja instalada. (Caso não esteja)
No Windows baixe o binário (SDL_mixer-devel-1.2.8-VC8.zip), o pacote (SDL_mixer-1.2.6-2mol.DevPak) ou use o repositório do Dev-Cpp.
No Linux baixe o binário (SDL_mixer-devel-1.2.8-1.i386.rpm), o código para compilar (SDL_mixer-1.2.8.tar.gz) ou use o repositório do Debian/Ubuntu (sudo apt-get install libsdl-mixer1.2-dev).
Para compilar é preciso, além de incluir a biblioteca SDL_mixer.h, linkar a lib ao seu projeto (-lSDL_mixer). exemplo: gcc -o mix mix.c `sdl-config --cflags --libs` -lSDL_mixer
Caso esteja com problemas consulte: » Setting up SDL Extension Libraries
*** Programando com SDL_mixer ***
Aqui temos os tipos que armazenam a musica e o efeito sonoro:
Mix_Music *musica = NULL; //- música de fundo
Mix_Chunk *bomba = NULL; //- efeito sonoro mixável.
Mix_Chunk *tiro = NULL;
SDL_Init(SDL_INIT_VIDEO | SDL_INIT_AUDIO);
atexit(SDL_Quit);
screen = SDL_SetVideoMode( W, H, 32, SDL_SWSURFACE);
Mix_OpenAudio( 22050, MIX_DEFAULT_FORMAT, 2, 1024 ); //- inicializa SDL_Mixer
atexit(Mix_CloseAudio);
}
musica = Mix_LoadMUS("007JamesBond.mid");
bomba = Mix_LoadWAV("bomba.ogg");
tiro = Mix_LoadWAV("tiro.wav");
}
Mix_PlayChannel( -1, tiro, 0 );
*** O Exemplo ***
Este é o exemplo que criei para testar a SDL_Mixer:
Não chega a ser um teclado, mas a intenção foi boa ! Ainda não sei como melhorar, mas estarei estudando.
EDIT (23/12/2007): Mudei o buffer de 4096 para 1024. Isso acelerou a mixagem das notas musicais ao som de fundo.
Download: » código fonte
*** Onde Encontar ?! ***
Onde encontrar músicas e efeitos sonoros para meus jogos ?!
» Arcade Accurate (incluíndo o Pacman)
» Sunncity (mid's)
» Midiworld (mid's)
» Simply The Best
» Galbadia
» Find Sound (ou Google msm !)
No eMule uma busca por "midis" ajuda bastante:
Mas de 500 Midis Heavy Metal.rar [hash]
[Midi] Classical Piano Midis...zip [hash]
40000.mids.Nacional.e.Internacionais...rar [hash]
Uma maneira de aproveitar melhor tudo isso é saber manipular programas de audio.
Pra Linux temos:
» Audacity (sudo apt-get install audacity) - Para editar audio.
» Rosegarden (sudo apt-get install rosegarden) - Editor de arquivos midi e de partituras.
» Timidity (sudo apt-get install timidity) - Sequenciador midi. Sem ele não tem como ouvir midi no Linux. dica: $ timidity 007.mid -Ov 007.ogg - Salva saída no formato ogg.
*** Link's ***
Download: » código fonte
» SDL
» SDL_Mixer - Página do projeto
» Playing Sounds - Tutorial Lazy Foo
» OSG/SDL Tutorial 17 - Audio with SDL_Mixer
» SDL_Mixer Tutorial
» Utilizando áudio com SDL_mixer
---
Essa semana foi dura ! Aprendi muita coisa de uma vez !!!
Postado por Diogo_RBG 4 comentários
quinta-feira, 6 de dezembro de 2007
Gerando e carregando mapas 2D em jogos
É comum utilizar mapas em jogos, pois facilita nas colisões, nos tilesets... em tudo ! //--- Função que gera o arquivo mapa.txt ---// # Informações # void Mapa::analisar(char *buf, int n){
No último post falei sobre SDL e no penúltimo sobre analisadores. Este irá combinar tudo isso e mais um pouco.
Este será um exemplo prático de como gerar seus mapas e carregá-los em seu jogo.
» Post Completo...*** O Gerador ***
Quem nasceu primeiro, o ovo ou a galinha ?! O mesmo pode te ocorrer quando for fazer um jogo e não possuir o editor de mapas do jogo que você ainda não fez.
Uma maneira rápida de criar um mapa é construindo um gerador "quase" genérico que pode ler os dados de um arquivo.bmp e converter em seus tilesets. Mas como é isso ?!
Abra o Paint ou o KolourPaint e crie uma imagem de 20x20. Dê um zoom de 800% ou mais e habilite a grade (Ctrl+G). Este é o editor que não vai te deixar na mão !
Depois de alguns cliques faço algo do tipo:
O gerador entra agora. Ele deverá converter cada pixel em um tile do seu jogo.
Se você for mais ousado pode fazer ele te gerar todos os detalhes de acabamentos.
No geral o código fica assim:
void gerar(){
FILE *file = fopen("arquivo.txt","wb");
...
for(j=0;j>img->h;j++){
for(i=0;i>img->w;i++){
if(i!=0)
fprintf(file," ");
fprintf(file,"%02X",getTile( getPix(img,i,j) ));
}
fprintf(file,"\n");
}
...
}
//--- Função de conversão da cor em tile ---//
int getTile(Uint32 cor){
switch(cor){
case 0x000000:
return 1;
case 0xffffff:
return 0;
}
return 0;
}
*** O Analisador ***
O gerador não resolve tudo. Sempre irá existir um detalhe a mais. E mapas gerados são muito enquadrados.
Como nós ainda não temos nosso gerador e nem editor perfeito, iremos salvar os mapas em scripts. Isso facilita, pois você poderá fazer pequenos retoques à mão.
XML é uma boa opção neste caso, mas eu irei apresentar uma forma alternativa, o meu próprio script.
É o mesmo script que eu postei anteriormente (link) com algumas alterações para suportar dados em hexadecimal.
O arquivo script tem este formato:
tiles = "tiles.bmp"
tile_w = 20
tile_h = 20
mapa_w = 20
mapa_h = 20
[tiles[
0F 05 05 05 ...
07 02 00 00 ...
...
0D 04 04 04 ...
]]
*** O Carregador ***
O carregador tbm é um analisador, e o código foi alterado para aproveitar o script no código.
static string var,val; //- strings redimensionáveis
...
switch(est){
...
case VAR: //- trata variáveis
if( let(c) || num(c) || c=='_')
var += c;
...
case VAL: //- trata valores
...
else if(c=='\n' || c=='\r'){
est = ZERO;
setVar(var,val);
}
...
}
...
}
void Mapa::setVar(const string var, const string val){
if(var.empty() || val.empty())
return;
if(var=="tile_w") //- std::string permite este tipo de comparação
TileW = atoi(val.c_str());
else if(var=="tile_h")
TileH = atoi(val.c_str());
...
}
É muito parecido com o Pacman e dá até vontade de jogar, mas não se engane !
Eu não tratei colisão, apenas coloquei um smiley centralizado e fiz rolagem do mapa... o jogo é você quem deve fazer !
*** Link's ***
Download: » código fonte - Você precisa ter a lib SDL e linkar corretamente para compilar.
» Tutorial Tiling (por Lazy Foo) - Uma segunda referência
» SDL - A Biblioteca dos Jogos 2D
» Analisador léxico de arquivos script
Postado por Diogo_RBG 7 comentários