Olá! Já faz um tempo que postei pela última vez, pois acabaram as aulas de monitoria. =)
Hoje vou escrever sobre (adivinhe!) Cinemática básica, isto é, como modelar matematicamente as posições dos objetos em movimento, iniciando o uso do blog com a finalidade original, que era passar um pouco sobre animações. Se quiser simplesmente ver o código (em python), clique aqui.
Relembrando
No colegial, os professores de física passam as equações de “Movimento Retilíneo Uniforme” e “Movimento Retilíneo Uniformemente Variado” – MRU e MRUV, respectivamente. O MRU é um caso particular do MRUV, onde a aceleração vale 0. Assim, deixo aqui apenas a do MRUV, que é mais genérica:

MRUV - Movimento Retilíneo Uniformemente Variado
A notação está em forma vetorial, para informar que as variáveis possuem módulo, direção e sentido. Para problemas de balística, o eixo X geralmente não possui aceleração e o eixo Y é afetado pela aceleração da gravidade. As equações do eixo X e Y, geralmente, são tratadas separadamente, para facilitar a resolução. Supondo uma velocidade inicial de lançamento de um objeto com componentes não-nulas tanto para o eixo x quando para o eixo y, e considerando uma aceleração da gravidade (geralmente negativa, pois a gravidade atrai para baixo e o eixo y cresce para cima), é possível notar uma trajetória parabólica para o objeto lançado. Essa equação fornece a posição a cada instante, considerando-se as condições ideais (sem atrito, sem resistência do ar, apenas a gravidade atuando etc) num tempo contínuo.
Em computação, contudo, o tempo não é contínuo, mas isso não chega a ser um problema na maioria dos casos: aproximando-se o suficiente do real é o bastante para que nossos olhos não notem a diferença.
Um modo equacionar o MRUV em computação é dada abaixo (trecho de código em python) , considerando-se que o tempo, na verdade, é o número do “frame” desde o início da simulação. Dessa forma, t = 1 significa o 1o. frame, t = 2 o segundo e assim por diante.
## Antes de iniciar:
self.xs0 = self.posx
self.ys0 = self.posy
self.xv0 = v0 * math.cos(ang)
self.yv0 = -v0 * math.sin(ang) # o eixo y aumenta pra baixo; queremos que suba!
self.xa = 0 # sem aceleracoes no eixo x
self.ya = grav # gravidade (para baixo!)
## A cada iteracao/frame
self.posx = self.xs0 + self.xv0 * self.tempo + (self.xa * self.tempo * self.tempo / 2.0)
self.posy = self.ys0 + self.yv0 * self.tempo + (self.ya * self.tempo * self.tempo / 2.0)
self.tempo += 1
self seria o objeto a ser tratado; seus componentes indicam posição inicial x e y, velocidades iniciais x e y, acelerações x e y. self.posx e self.posy são as posições “naquele instante”, no frame número self.tempo .
Significado
Bom, mas o que significam a velocidade e aceleração? Elas são taxas de variação. A velocidade é a variação (derivada com relação ao tempo!) da posiçao e a aceleração a variação da velocidade. Elas dizem o quanto uma variável vai variar em um segundo. Então, por exemplo, uma velocidade de 3 para a direita significa que, daqui um segundo, a posição do objeto aumentou de 3 unidades para a direita (eixo x, geralmente). Da mesmforma, a aceleração diz quanto a velocidade varia em um segundo ou uma unidade de tempo (no caso aqui, um frame). Seguindo essa linha, é possível modelar esse movimento de modo iterativo, da seguinte forma:

Cinemática iterativa para computação
Isso deve ser feito a cada frame da simulação, preferencialmente nessa ordem. A legenda: acel = aceleração; vel = velocidade, pos = posição e equação é uma equação que controla a aceleração. Como estamos exemplificando com MRUV, a aceleração deve ser constante. Assim, é possível modelar, digamos, uma partícula que sofre ação da gravidade, como:
# preparacao, valores iniciais
self.posx, self.posy = x, y # posicao inicial
self.velx = v0 * math.cos(ang) # velocidade inicial
self.vely = -v0 * math.sin(ang)
self.acelx = 0 # aceleracoes; 0 em x
self.acely = grav
# A cada frame:
self.velx += self.acelx
self.vely += self.acely
self.posx += self.velx
self.posy += self.vely
Dessa forma, se a aceleração se mantiver sempre constante, haverá um MUV (movimento uniformemente variado, não mais necessariamente “retilíneo”). Essa forma gera uma trajetória parabólica bem próxima da obtida com a equação do tempo, mas sem precisar calcular um quadrado e uma divisão a cada frame, apenas somas. =)
Vantagens
Como se sabe, no mundo real (e nas simulações… e jogos!), a aceleração não será constante por muito tempo. É possível que ela varie, devido a vários fatores, “naturais” ou não (o jogador/usuário poderia alterar a aceleração dos objetos). Exemplos de “causas naturais” que modificariam a aceleração:

Exemplos de equações de aceleração
sendo g a aceleração da gravidade, b um coeficiente de resistência do ar (deve ter outro nome…), v_vento a velocidade do vento e mi o coeficiente de atrito dinâmico.
Dessas, apenas a de gravidade é um movimento uniformemente variado, já que mantém a aceleração constante. As demais (e existem muitas outras por aí!) não são uniformemente variados, são apenas variados. (… o que nos deixa com um Movimento Variado?).
Nesses casos, a aceleração teria um valor “setado”/”recalculado” a cada frame, fornecendo resultados interessantes. Mais ainda, todas essas equações podem ser simplesmente somadas, combinando seus efeitos, por serem equações lineares, oferecendo efeitos mais realistas.
Em código:
# resistência do ar, apenas (a cada frame)
self.acelx = -0.01 * self.velx # a res. do ar eh uma forca proporcional a velocidade
self.acely = -0.01 * self.vely # e atua em sentido contrario a ela
# vento, apenas (a cada frame)
self.acelx = -0.01 * (self.velx - self.ventox) # mas, na verdade, depende da velocidade relativa
self.acely = -0.01 * (self.vely - self.ventoy) # do objeto com relacao ao ar, que pode estar se movendo
Um outro caso interessante é utilizar as teclas pressionadas. Por exemplo, se as teclas A e D movem um bonequinho para a esquerda e direita, respectivamente, elas poderiam acelerar o boneco, dando-lhe uma inércia: ele não fica com velocidade máxima de uma vez assim que o usuário pressiona o botão. Uma equação típica para isso, utilizando pygame, é:
events = pygame.event.get() # para atualizar o estado de tudo
teclas = pygame.key.get_pressed() # para determinar o estado de cada tecla
self.acelx = (teclas[K_d] - teclas[K_a]) * aceleracao - 0.1*self.velx # para acelerar o objeto no eixo x
self.acely = (teclas[K_s] - teclas[K_w]) * aceleracao - 0.1*self.vely # para acelerar o objeto no eixo y
# depois, somar a aceleracao na velocidade e a velocidade na posicao
É importante ter o “limitador” dele, essa “resistência de ar“, para que o objeto não acelere infinitamente. Essa resistência de ar limita a velocidade, fazendo o objeto tender a uma determinada velocidade: a chamada velocidade terminal. Se, por algum motivo, o objeto estiver acima dessa velocidade terminal, a resistência do ar fará com que a velocidade reduza até a terminal. Caso deseje-se calcular a velocidade terminal:

Fórmula para Velocidade Terminal
Mas, por que isso é uma vantagem? Bom, tente fazer uma equação como a do primeiro caso (dependente do tempo) que modele esses efeitos. =P Boa sorte! Além disso, modelar de forma que um efeito possa ser “ligado ou desligado” a qualquer hora (como quando um botão for pressionado pelo usuário) torna-se bastante complexo com a equação do tempo, mas praticamente não muda o outro método.
Finalizo deixando um código em python para ilustrar a diferença desses vários efeitos nas trajetórias balísticas.
Códigos: Cinemática Balística (Python)