SDL e programação de jogos - detecção de colisão - parte 3
Caso vc não tenha visto a parte 2, aqui o link:
SDL-e-programacao-de-jogos-parte-2
É um dos algoritmos mais fáceis de aprender e também um dos mais fáceis de entender!
Veja abaixo como ele funciona:
Vc pode colocar tudo numa única expressão lógica ou pode colocar em 4 if. Detalhe: é mais fácil verificar por NÃO colisão do que por colisão!
Fica a seu critério definir o código de colisão. Neste tutorial, vamos usar função para ficar mais genérico e mais desafiador.
Para o próximo código, vamos precisar do algoritmo acima como uma função que chamaremos ela de boundingBox, que recebe dois ponteiros constantes do tipo SDL_Rect (rectA e rectB) e retorna 1 se eles estão colidindo ou retorna 0 em caso de não colisão
E eu digo meu caro que um jogo é apenas um conjunto organizado de diversos algoritmos! Ou seja, o jogo é preparado de um jeito que cada algoritmo trabalha praticamente independente dos outros e a soma de odos os trabalhos resultado no que vc vê na tela como jogo
Veja abaixo um código de exemplo: (implemente a função de boundingBox com o algoritmo ali de cima!)
Veja o exemplo completo aqui: colisao_boundingbox.c
No próximo tutorial, veremos como separar um retângulo de dentro um do outro e também como melhorar o código da movimentação do player.
Exercícios:
SDL-e-programacao-de-jogos-parte-2
Introdução
Pra quem não sabe, todo jogo usa algoritmos de detecção de colisão e separação de objetos. Esse é um assunto bem amplo (e complexo!) mas neste post vc aprenderá o básico:- vc vai aprender a como detectar colisão entre dois retângulos
- vc vai aprender a como separar um retângulo de dentro um do outro
Algoritmo básico: bounding boxes!
O algoritmo de detectar se dois retãngulos estão colidindo é o bounding boxes!É um dos algoritmos mais fáceis de aprender e também um dos mais fáceis de entender!
Veja abaixo como ele funciona:
- pegue um retângulo e chame-o de rectA
- pegue outro retângulo e chame-o de rectB
- se a posição da lateral direita do rectA é MAIOR ou igual a posição da lateral ESQUERDA de rectB, então, continue para passo 4, senão, não é colisão
- se a posição da lateral esquerda do rectA é menor ou igual a posição da lateral DIREITA de rectB, então, continue para passo 5, senão, não é colisão
- se a posição da lateral de cima do rectA é menor ou igual a posição da lateral DE BAIXO de rectB, então, continue para passo 6, senão, não é colisão
- se a posição da lateral de baixo do rectA é MAIOR ou igual a posição da lateral DE CIMA de rectB, então, continue para passo 7, senão, não é colisão
- se chegou até aqui, então, é colisão de rectA com rectB!
Vc pode colocar tudo numa única expressão lógica ou pode colocar em 4 if. Detalhe: é mais fácil verificar por NÃO colisão do que por colisão!
Fica a seu critério definir o código de colisão. Neste tutorial, vamos usar função para ficar mais genérico e mais desafiador.
Para o próximo código, vamos precisar do algoritmo acima como uma função que chamaremos ela de boundingBox, que recebe dois ponteiros constantes do tipo SDL_Rect (rectA e rectB) e retorna 1 se eles estão colidindo ou retorna 0 em caso de não colisão
Exemplo de uso: detectando colisão!
Quando vc vê um retângulo numa janela do SDL vc pode pensar: mas como diabos algo assim se transforma num jogo complexo?E eu digo meu caro que um jogo é apenas um conjunto organizado de diversos algoritmos! Ou seja, o jogo é preparado de um jeito que cada algoritmo trabalha praticamente independente dos outros e a soma de odos os trabalhos resultado no que vc vê na tela como jogo
Veja abaixo um código de exemplo: (implemente a função de boundingBox com o algoritmo ali de cima!)
// código de exemplo de como detectar colisão
// compile com gcc -o colisao_boundingbox colisao_boundingbox.c -lSDL2
//código de colisão entre dois retangulos na tela
//neste exemplo tem um rect amarelo que é controlado pelas setas do teclado e um rect cinza que fica parado.
//quando os dois se encostar pelo boundingBox então o rect do player vai de amarelo e fica vermelho.
//quando não se encostar, o rect do player volta ficar amarelo
#include <SDL2/SDL.h>
#include <stdio.h>
int boundingBox(const SDL_Rect *a, const SDL_Rect * b) {
return (
//implemente aqui a lógica de detecção de colisão
);
}
int main() {
SDL_Init(SDL_INIT_VIDEO);
//100 posição horizontal em pixels dentro do seu monitor do canto esquerdo superior para direita
//150 posição vertical em pixels dentro do seu monitot do canto esquerdo superior pra baixo
//640 é a largura da janela em pixel
//480 é a altura da janela em pixel
SDL_Window * janela = SDL_CreateWindow("loops e jogos", 100,150,640,480, SDL_WINDOW_OPENGL);
SDL_Renderer * renderer = SDL_CreateRenderer(janela, -1, SDL_RENDERER_ACCELERATED);
SDL_Event evento;
SDL_Rect player;
player.x = 220;
player.y = 240;
player.w = 32;
player.h = 64;
//cria o sólido
//ele é apenas um retângulo simples
SDL_Rect solido;
solido.x = 320;
solido.y = 200;
solido.w = 32;
solido.h = 128;
int fim = 0;
//loop principal
while (!fim) {
//loop de eventos
//novo loop de eventos
while (SDL_PollEvent(&evento)) {
//verifica se clicou em fechar
if (evento.type == SDL_QUIT)
fim = 1;
//verifica se a tecla pra baixo foi apertada
if (evento.type == SDL_KEYDOWN) {
if (evento.key.keysym.sym == SDLK_DOWN) {
//move o player pra baixo +5 pixels
player.y = player.y + 5;
}
//verifica se a tecla apertada é a seta direita
else if (evento.key.keysym.sym == SDLK_RIGHT) {
//move o player +5 pixels pra direta
player.x = player.x + 5;
}
//se é a tecla seta esquerda
else if (evento.key.keysym.sym == SDLK_LEFT) {
//mova pra esquerda, como que faz?
//se somar +5 ao player.x é mover pra direita, então diminiuir -5 em player.x é mover pra esquerda!
//R:
player.x = player.x - 5;
}
else if (evento.key.keysym.sym == SDLK_UP) {
//mmova pra cima, como que faz?
//se mover pra baixo é somar +5 ao player.y, então, mover pra cima é diminuir -5 no player.y!
//R:
player.y = player.y - 5;
}
}
}
//código de update
//faz mover, faz pular, etc
//verifica se o player e o sólido estão colidindo
//observe que NÃO é separado o player do sólido, mas apenas verifica se estão se tocando! (ui que gostoso se tocar!)
//se playerColidiuComSolido é 1, e tnão estão colidindo, se é 0 não estão.
int playerColidiuComSolido = boundingBox(&player, &solido);
//código de desenho na tela
//aqui é onde o usuário vê o resultado na tela
//limpa a tela com a cor preta
//toda a tela é desenhado de preto
SDL_SetRenderDrawColor(renderer, 0,0,0,255);
SDL_RenderClear(renderer);
//desenha o SÓLIDO na tela com a cor cinza!
SDL_SetRenderDrawColor(renderer, 128,128,128,255);
SDL_RenderFillRect(renderer, &solido);
//verifica se NÃO colidiu o player e o sólido
if (playerColidiuComSolido == 0) {
//Se NÃO colidiu
//desenha o player na tela com a cor amarela!
SDL_SetRenderDrawColor(renderer, 255,255,0,255);
}
else {
//Se colidiu
//desenha o player na tela com a cor vermelho!
SDL_SetRenderDrawColor(renderer, 255,0,0,255);
}
SDL_RenderFillRect(renderer, &player);
//tem que chamar essa função pra mostrar tudo na janela
SDL_RenderPresent(renderer);
//NOTA: tem que esperar um pouco antes de ir pra próxima iteração
SDL_Delay(16);
}
//por fim libera memória
SDL_DestroyRenderer(renderer);
SDL_DestroyWindow(janela);
SDL_Quit();
return 0;
}
No exemplo acima, vc deve implementar a função boundingBox() para detectar se os dois retângulos estão colidindo.Veja o exemplo completo aqui: colisao_boundingbox.c
No próximo tutorial, veremos como separar um retângulo de dentro um do outro e também como melhorar o código da movimentação do player.
Exercícios:
- Experimente detectar colisão do mouse com um retângulo na tela. O mouse nada mais é que um ponto (x, y) sem as dimensões (w, h). Vc pode criar outra função chamada pointBox() para detectar se o mouse está dentro ou fora de algum retângulo. Se está dentro de um dos retângulos, então, mudar a cor do retênculo, se está fora, coloque a cor normal do retângulo. NOTA: veja ali em baixo um exemplo de código para pegar as coordenadas do mouse.
- Experimente colocar a posição (x, y) do player pra ser a posição (mouseX, mouseY) no código do exercício 1 e veja se continua detectando colisão. Quando colocar o player na posição (mouseX, mouseY) ele vai acompanhar o movimento do mouse dentro da janela e vc pode verifica se continua mudando de cor o player.
- Experimente fazer o sólido ficar movendo de um lado a outro na horizontal, basta criar uma variável chamada solidoVelX com valor +5, dai no loop principal fazer solido += solidoVelX, depois verificar se a posição solido.x é maior que 640 (largura da janela), se for, vc coloca solidoVelX = -5 (pra mover pra esquerda), se não se solido.x for menor que zero, então, vc coloca o solidoVelX com valor igual a +5
//declare mouseX e mouseY fora do loop principal e inicialize com valor 0
// no loop de eventos
while (SDL_PollEvent(&evento)) {
//resto do código dos eventos
...
//esse if será executado se o evento colocado pelo SDL_PollEvent() for do tipo mouse motion
if (evento.type == SDL_MOUSEMOTION) {
mouseX = evento.motion.x;
mouseY = evento.motion.y;
}
}
//resto do código
//aqui vc pode verificar com sua própria pointBox() se o ponto (mouseX, mouseY)...
//...está dentro do player e depois verificar se está dentro do solido

Comentários
Postar um comentário