SDL e programação de jogos - forças e movimento genérico em jogos de plataforma - parte 5.1

Olá pessoa, let's arrochar o dedo no teclado, vulgo codar?

Na aula passa que vc pode conferir aqui: SDL e programação de jogos - movimentação e separação de colisão

Vamos pegar o último código que vc pode baixar aqui: Move e separa parte 2

Sigam-me os fodas, porque deles é que é o mundo real!

Teoria sobre o novo código

Vc viu que no último código a gente usou os valores para adicionar ou subtrair 5 pixels, porém, meu amigo, neste novo tutorial, vamos dar um senhor upgrade geral!

Aqui no caso, vamos ter uma base de uma engine 2d de física. É muito código e pode ser que vc se perda um pouco, mas não se preocupe, vc pode se encontrar novamente virando a esquina mais próxima.

Mas primeiro, vamos a teoria básica sobre: FìSICA em jogos! Muahaha

Teoria: usando física básica em jogos

É isso ai meu caro, nesta parte vamos precisar do conhecimento de física clássica, aquela do senhor Newton.

Será com ela que vamos fazer um código genérico suficiente para poder ser usado com QUALQUER objeto que desejamos ter!

Aplicando forças

Em nosso código atual, a gente adicionou 5 no eixo X pra mover pra direita, subtraiu 5 em X pra mover pra esquerda, etc. Mas veja bem:

Observe que o adicionar ou subtrair 5 em cada eixo na verdade podemos generalizar ele. No caso, podemos usar uma variável com um valor constante no lugar do 5 e ai então a gente só faz somar ou subtrair no eixo desejado.

Isso é bem fácil né? Basicamente mover significa apenas ou somar um valor a posição ou subtrair um valor a posição, seja em X ou em Y.

Veja um exemplo disso em ação:

//velocidade constante
int velocidadeX = 5;
//código acima vai antes de entrar no loop principal

//código de mover DENTRO do loop principal
//mover no eixo X (horizontal)
//se é pra mover pra direita
if (setaDireita == 1) {
  //faz mover pra direita
  player.x = player.x + velocidadeX;
}
//senão se setaDireita == 0, não faz nada
//se é pra mover pra esquerda
if (setaEsquerda == 1) {
  //faz mover pra esquerda
  player.x = player.x - velocidadeX;
}
Veja que eu mudei onde antes tinha o valor 5 para apenas ter a variável velocidadeX.

No caso, velocidadeX é o mesmo que uma variável de força, sabe por quê? Porque ela se refere ao valor que realmente vai o player mover!

Agora, veja como fica o código acima ainda melhor: NOTA: modifique o código do Move e separa parte 2 para ver o que acontece.


//velocidade constante
int velocidadeX = 0;
//código acima vai antes de entrar no loop principal

//código de mover DENTRO do loop principal
//mover no eixo X (horizontal)
//se é pra mover pra direita
if (setaDireita == 1) {
  //faz mover pra direita
  velocidadeX = velocidadeX + 5;
}
//senão se setaDireita == 0, não faz nada
//se é pra mover pra esquerda
if (setaEsquerda == 1) {
  //faz mover pra esquerda
  velocidadeX = velocidadeX - 5;
}
//agora realmente move o player em X
player.x = player.x + velocidadeX;
Deu pra ver a diferença?

Enquanto somar diretamente +5 ou -5 faz o player mover de forma "dura" (ui!) fazer o código acima faz com que o player passe a "deslizar" no eixo X.

O nome disso se chama momentum, que basicamente é a velocidade que continua com certo valor até que se aplique força no sentido contrário.

Ou seja, é a lei do senhor Newton que diz: um corpo, permanece em movimento enquanto lhe é aplicado alguma força! E se nenhuma força é aplicado, ele fica parado! Morô meu camarada?

Então, o que fizemos ao somar +5 ou -5 a velocidadeX na verdade foi apenas aplicar uma força num sentido (pra direita com +5 e pra esquerda com -5) e ai fez com que nosso player deliza-se um pouco e depois seguisse na direção desejada.

Ou seja, podemos dizer que nosso player é na verdade um objeto móvel! Ou um objeto dinâmico! Enquanto que o retângulo de nome "solido" é um objeto estático, ou seja, que não se move e apenas colide!

Se correr o bicho pega, se colidir o bicho para

Do que foi exposto acima, vc tem que entender o seguinte: força NÃO muda de uma vez o valor da velocidade! E toda vez que colidir, vc deve modificar a velocidade pra parecer mais "realistico".

Por exemplo, ali nas linhas 131 e 170 do Move e separa parte 2 vc tem um processamento de colisão. Porém meu caro e querido, ainda não está muito adequado, sabe por quê? Porque o player continua acelerando enquanto está encostado no sólido! Tente vc mesmo, faça o player e o solido colidirem em X e ai tente segurar o botão mover o player em direção ao solido, vc vai ver que vai chegar uma hora em que o player atravessa o solido, isso é completamente normal (OBS: tem que modificar o código como falei antes ali em cima)

Isso ocorre porque a velocidade X aumenta tanto que chega um momento em que o player vai tá movendo numa velocidade maior do que a metade da largura do solido. Ou seja, nosso algoritmo de colisão e processamento tem uma baita limitação que é chamada de Tunelamento.

Existem técnicas para resolver o tunelamento mas isso é muito avançado pra este tutorial, talvez veremmos mais sobre ele em ocasião oportuna. Mas para evitar isso, por hora, vamos adicionar uma velocidade máxima permitida para mover, veja o código abaixo:

//modifique o código
//velocidade constante
int velocidadeX = 0;
int velocidadeMaxX = 20;
//código acima vai antes de entrar no loop principal

//código de mover DENTRO do loop principal
//mover no eixo X (horizontal)
//se é pra mover pra direita
if (setaDireita == 1) {
  //faz mover pra direita
  velocidadeX = velocidadeX + 5;
}
//senão se setaDireita == 0, não faz nada
//se é pra mover pra esquerda
if (setaEsquerda == 1) {
  //faz mover pra esquerda
  velocidadeX = velocidadeX - 5;
}

//limita a velocidade pra evitar tunelamento
//se estamos indo pra esquerda além da velocidade máxima negativa
if (velocidadeX < -velocidadeMaxX) {
  //então, limite a velocidade pra esquerda
  velocidadeX = -velocidadeMaxX;
}
//se estamos indo pra DIREITA além da velocidade máxima positiva
else if (velocidadeX > velocidadeMaxX) {
  //então, limite a velocidade pra direita
  velocidadeX = velocidadeMaxX;
}

//agora realmente move o player em X
player.x = player.x + velocidadeX;
Ou seja, agora estamos limitando o quanto consegue mover no máximo em X! Vc pode fazer o mesmo com o eixo Y, fica ai como exercício!

Veja que a velocidade máxima pra esquerda é na verdade um valor negativo menor que a velocidade máxima em valor negativo, ou menor que -velocidadeMaxX.

Vc também precisa parar o player quando ele colidir com o solido, pra fazer isso, basta colocar DENTRO do if do "if (boundingBox(&player, &solido))" de cada eixo, uma atribuição para 0 em cada velocidade.

Se colidir em X com o sólido então faz velocidadeX = 0. Se colidir em Y com o sólido, então, faz velocidadeY = 0. Ou seja, faz o player parar de mover em cada eixo que colidir com o solido.

Exercícios:
  1. Faça a modificação do código do move_e_separa_2.c e adicione o código acima para X e também outro para Y. Precisa de outra velocidadeY e velocidadeMaxY. Não esqueça de limitar o movimento!
  2. Faça a modificação para parar de mover o player quando colidir tanto em X quanto em Y
  3. Experimente tentar atravessar o player no exercício 2, veja se consegue agora fazer o tunelamento.
Como o artigo tá grande, é melhor eu dividir em mais partes. Na próxima parte vc verá aplicação de forças ao player.

Comentários

Postagens mais visitadas deste blog

SDL e programação de jogos parte 1

SDL e programação de jogos - detecção de colisão - parte 3

SDL e programação de jogos parte 2