Vetores e Trigonometria
Links Relacionados: Matemática e Física para Jogos, Jogos Digitais
Descrição
Na Computação Gráfica, e consequentemente nos Games que se utiliza desse recurso para a apresentação e interação visual, são utilizadas algumas grandezas como direção e força do vento, gravidade, direção que um personagem está olhando, etc. Essa é descrita como uma grandeza vetorial.
Essas direções e intensidades são representadas por vetores. Estes possuem informações referentes a distância, sentido e tamanho, geralmente representados graficamente por setas.
Características dos Vetores
- Tamanho: é a intensidade. É também chamado de magnitude;
- Direção: indica a inclinação do vetor no espaço;
- Sentido: mostra para onde o vetor está apontando;
Observação: vetores não possuem como propriedade a posição.
Vetores representam deslocamentos com sinal em cada eixo.
- Em 2 dimensões têm-se um valor para x e y.
- Em 3 dimensões, têm-se x, y e z.
- Em 4 dimensões, têm-se x, y, z e w.
Graficamente, representamos vetores como uma flecha. A posição da flecha não importa, desde que sua direção, tamanho e sentido sejam mantidos.
Representação na Programação
No C++ ou no Java, esses valores virariam variáveis float:
1class Vector2D {
2public:
3 float x;
4 float y;
5
6 Vector2D() : x (0.0f), y (0.0f) {}
7 Vector2D(float _x, float _y) : x(_x), y(_y) {}
8};
Tamanho
Para encontrarmos o tamanho, utilizamos a fórmula definida na última aula. Transcrevendo-a em C++, temos:
1#include <math.h>
2
3float Vector2D::size() {
4 return sqrt((x * x) + (y * y));
5}
Soma de Vetores
Também podemos utilizar operações de soma de vetores. Por exemplo:
Com o código em C++:
1Vector2D Vector2D::operator +(const Vector2D& other) const {
2 return Vector2D(x + other.x, y + other.y);
3}
4
5Vector2D& Vector2D::operator +=(const Vector2D& other) {
6 x += other.x;
7 y += other.y;
8 return *this;
9}
Um exemplo prático pode se ver na figura a seguir. Se quisermos representar a trajetória da bola, podemos somar o vetor gravidade ao vetor da trajetória. É possível também adicionar vetores como vento, por exemplo.
Vetores também podem ser multiplicados por valores. Para tal, o código em C++ efetua essa operação:
Vector2D Vector2D::operator *(float scalar) const {
return Vector2D(x * scalar, y * scalar);
}
Vector2D& Vector2D::operator *=(float scalar) {
x *= scalar;
y *= scalar;
return *this;
}
Normalização
Para normalizar um vetor, ou seja, impor um tamanho a ele, utilizamos a operação de normalização. Isso reduz o tamanho do vetor para 1 (um). Este vetor norm alizado pode então ser multiplicado por um escalar para obtermos tamanho desejado. Para normalizar um vetor, basta dividirmos x e y pelo tamanho do vetor:
1Vector2D& Vector2D::normalize() {
2 return (*this /= size());
3}
Vetores e Ângulos
Se quisermos que o nosso atacante chute uma bola baseado no ângulo e na força, podemos criar um vetor com essas informações.
Se for dado um chute de ângulo 50 graus e a uma força 10, poderíamos chamar a função a baixo. Lembrando que em C/C++ o ângulo é em radianos (1 grau = PI/180 radianos).
1Vector2D Vector2D::bySizeAndAngle(float size, float angle) {
2 return Vector2D(cos(size) * size, sin(size) * size);
3}
Da mesma forma, podemos retornar qual o ângulo de um vetor por meio do arco-tangente de x e y:
1float Vector2D::angle() const {
2 return atan2f(y, x);
3}
Para facilitar, podemos fazer funções de conversão de radianos para graus e graus para radianos:
1#define PI 3.1416
2
3float grad2radians(float grad) {
4 return (grad / 180) * PI;
5}
6
7float radians2grad(float radians) {
8 return (radians * 180) / PI;
9}
Também podemos rotacionar um vetor, utilizando a operação de rotação vista na última aula. Contudo, nesse caso estamos trabalhando apenas com vetores, em que a posição não importa. Então estamos sempre tendo como base o eixo (0, 0) do vetor, não necessitando das operações de translação.
1Vector2D& Vector2D::rotate(float angle) {
2 // Executa as operações de sin e cos apenas uma vez,
3 // economizando processamento.
4 float s = sin(angle);
5 float c = cos(angle);
6 float newX = (x * c) - (y * s);
7 float newY = (x * s) + (y * c);
8 x = newX;
9 y = newY;
10 return *this;
11}
Ângulo entre dois vetores
Para encontrar o ângulo entre dois vetores, é utilizado o produto escalar, onde A ⋅ B é o produto escalar entre os pontos A e B:
ou
Assim, podemos dizer que:
Onde |A| e |B| são respectivamente os tamanhos de A e B e α o ângulo que queremos calcular. Agora, note como o cálculo seria simplificado se A e B fossem vetores de tamanho 1:
ou, simplesmente:
Evitar o cálculo do tamanho reduz muito processamento, por isso é bom usar vetores normalizados para representar direções. No C++, o método para o cálculo do produto escalar fica assim:
1float Vector2D::dot(const Vector2D& other) const {
2 return (x * other.x) + (y * other.y);
3}
E o do ângulo entre os dois vetores unitários, assim:
1float Vector2D::angleBetween(const Vector2D& other) const {
2 float dp = dot(other);
3
4 if (dp >= 1.0) {
5 dp = 1.0f;
6 } else if(dp <= -1.0) {
7 dp = -1.0f;
8 }
9 float angPi = (float) acos(dp);
10 return dot(other) > 0 ? -angPi : angPi;
11}
Exercícios
1. Implemente o header (.h) e o arquivo fonte (.cpp) do vetor 2D para utilizá-lo no resto dos exercícios.
2. Faça um programa com as seguintes características:
- Clique na tela para definir o primeiro ponto (Ponto A)
- Clique na tela para definir o segundo ponto (Ponto B)
- Desenhe uma linha entre o Ponto A e o Ponto B
- Informe na tela, em elementos tipo texto:
- a distância entre os pontos
- o ângulo do Ponto A para o Ponto B
- A cada novo clique, o Ponto B se tornará o Ponto A e o Ponto B será o novo local onde foi dado o clique. Redesenhe a linha entre A e B e refaça os cálculos e apresente-os na tela.
3. Faça um programa com as seguintes características:
- Desenhe do lado esquerdo da tela e abaixo um pequeno canhão.
- A movimentação do mouse para cima e para baixo altera o ângulo de tiro.
- A movimentação do mouse para a esquerda e direita altera a força do tiro.
- O clique do mouse efetua um disparo (represente o disparo com um ponto grande ou com uma imagem)
- Quando a bala do canhão cair, calcule a distância entre o canhão e a bala.
- Considere a gravidade como 9.8 m/s.
- Mostre na tela as informações de:
- Ângulo do tiro
- Força do tiro
- Distância percorrida pela bala do canhão.
4. No programa anterior, acrescente vento. Para isso:
- Crie um vetor de direção e velocidade do vento. Como estamos em um espaço bidimensional, considere apenas contra o canhão ou a favor do tiro do canhão (direita para esquerda ou esquerda para direita).
- Altere a velocidade do vento por meio das setas direcionais ( <- e -> ).
- Acrescente a informação da direção do vento e força.