Vetores e Trigonometria

De Aulas

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.

Vetores.png

Características dos Vetores

Vetores representacao.png
  • 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:

Vetores soma.png

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 chute.png

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.