Quando iniciamos com o uso de vetores, muitas vezes, não temos a intuição imediata de que operação vetorial utilizar para atingir determinado resultado. Por isso, elaborei esse pequeno guia, com algumas das operações mais comuns.
Esse texto pressupõe que você já entende o que são vetores e para que servem. Se não é esse seu caso, leia nosso artigo introdutório sobre vetores.
Parte 1: Velocidades e direções
Problema 1.1: Representação de Agentes 2D
Problema: Representar corretamente a posição e direção de um veículo, em ambientes 2D.
Use um vetor para posição (Position);
Use um vetor unitário para direção e um float com a velocidade (Direction) ou
Use um vetor não unitário que representa ambos, direção e velocidade (Velocity).
Se o ator puder girar a cabeça, use um vetor unitário para indicar a direção para qual ele olha (Facing).
public Vector2 Position { get; set;}
private Vector2 Velocity {get; set;}
return Velocity.Length();
return Vector2.Normalize(Velocity);
Problema 1.2: Posições relativas entre A e B sem considerar o giro de A
Problema: Muitas vezes gostaríamos de desenhar um objeto B, em uma posição relativa a um objeto A, considerando apenas a posição de A. Por exemplo, considere um game de nave, onde um escudo gire em torno da nave a uma velocidade fixa. Outro exemplo seria um game horizontal scroller, onde quiséssemos um escudo na parte frontal da nave.
Solução: Dado um vetor A.pos contendo a posição do centro do agente A. E um vetor representando o deslocamento relativo entre o centro de A até a posição desejada de B (offset), a posição final de B será dada pela a soma dos dois vetores.
finalPos = B.offset + A.pos;
Problema 1.3: Posições relativas de A e B considerando o giro de A
Problema: Muitas vezes precisamos desenhar um objeto A em relação a outro objeto B, considerando a posição e a rotação de A. Um exemplo dessa situação seria posicionar um canhão rotatório num tanque de guerra.
Criar um vetor com a posição relativa a partir do centro de A, desconsiderando a rotação;
Usar a matriz de transformação de A sobre esse vetor, antes de soma-lo a A.
finalPos = A.pos + Vector2.Transform(a.Transform, B. relativePos);
Problema 1.4: Descobrir a direção que um agente A deve seguir para ir de encontro ao agente B / Descobrir a distância entre dois agentes
Problema: Temos dois agentes na tela, e queremos descobrir a direção entre os agentes A e B e/ou a distância entre eles.
Solução: Subtraia a posição do destino da posição da origem. O vetor resultante representa a trajetória entre eles. Seu comprimento representa a distância entre os dois agentes e sua direção representa o lado que um agente deve seguir para colidir com outro.
Vector2 path = (A.Position – B.Position);
float distance = path.Length();
Vector2 directionToB = Vector2.Normalize(path);
No XNA a distância entre dois vetores pode ser calculada diretamente através da função Vector2.Distance.
Problema 1.5: Forçar um vetor a ter um determinado tamanho
Problema: Muitas vezes obtemos um vetor de direção, e gostaríamos de forçá-lo a ter um tamanho determinado, como por exemplo, a velocidade atual do nosso agente.
Solução: Normalize o vetor e multiplique pelo tamanho desejado.
Vector2 A.Velocity = Vector2.Normalize(path) * A.Speed;
Problema 1.6: Criar um vetor com determinada direção e tamanho
Problema: Inicializar um vetor contendo uma direção e tamanho especificados. Isto poderia ser usado para, por exemplo, definir a direção e força do tiro de um canhão.
Solução: O vetor é criado através da fórmula V = (cos(a)*t, sen(a)*t), onde a é o ângulo e t o tamanho desejado.
Vector2 NewBySizeAngle(float size, float angle) {
(float)Math.Cos(angle)*size,
(float)Math.Sin(angle)*size);
Problema 1.7: Descobrir se um agente está à frente ou atrás de outro (2D)
Problema: Muitas vezes precisamos descobrir se um agente B está na parte à frente ou atrás do agente A. Observe que, quando os objetos giram, o conceito de "frente" e "trás" depende da direção do observador (A).
Calcule o vetor de trajetória subtraindo a posição de B da posição de A;
Retire o produto escalar do vetor de direção de A, com a trajetória normalizada até B. Essa operação equivale ao cosseno entre A e a trajetória de B.
Se o resultado for maior que zero B estará à frente de A. Se for menor que zero, B estará atrás de A. E se for igual a zero, B estará na lateral exata de A.
Vector2 pathNormal = (B.Position – A.Position);
pathNormal.Normalize();
bool isInFront = Vector2.Dot(A.Direction, pathNormal) > 0;
Problema 1.8: Calcular se um agente está no campo de visão de outro (2D)
Problema: Descobrir se o agente A pode ver o agente B.
Solução: Armazenar duas constantes contendo:
O cosseno do ângulo de visão desejado;
A distância máxima da visão.
Retire o produto escalar do vetor de direção de A, com a trajetória normalizada até B. Ou seja, o cosseno entre A e a trajetória de B.
Se a constante a) for maior que o resultado obtido, o agente B estará fora do campo de visão, portanto, não estará visível;
Caso contrário, teste se distância máxima da visão é menor do que o tamanho do vetor da trajetória.
Otimização: Esse processo pode se tornar mais rápido se as distâncias estiverem ao quadrado.
public bool canSee(Agent other)
const float VISION_RADIANS = Math.cos(Math.ToRadians(45));
const float VISION_DISTSQR = 50*50; //in pixels
Vector2 path = (B.Position – A.Position);
return VISION_RADIANS <= Vector2.Dot(A.Direction, Vector2.Normalize(path)) &&
VISION_DISTSQR <= path.LengthSquared();
Problema 1.9: Deslocamento lateral em 2D
Problema: Achar o vetor de deslocamento lateral de um agente em 2D. Nesse caso, queremos calcular o vetor perpendicular à direção.
Solução: O vetor perpendicular, em 2D, é facilmente calculado da seguinte forma:
a) Inverte-se o valor de x e y;
b) Nega-se o valor de x para girar à esquerda, ou o valor de y para girar à direita.
Vector2 perp = Vector2(A.Y, -A.X);
Problema 1.10: Deslocamento lateral em 3D (Strafe)
Problema: Achar o vetor de deslocamento lateral de um agente em 3D. Neste caso, precisamos do vetor de direção do agente, e do vetor up, que aponta para cima. O vetor de strafe é definido como o produto vetorial entre a direção e o vetor up normalizado.
Vector3 strafe = Vector3.Cross(A.Direction, A.Up);
Problema 2.1: Deslocar um agente numa velocidade constante
Solução: Multiplique o vetor de direção, unitário, pela velocidade desejada, e pelo tempo transcorrido em segundos (secs).
float secs = (float)gameTime.ElapsedGameTime.TotalSeconds
A.Position += A.Direction * speed * secs;
Note que direction * speed é o vetor Velocity, portanto, caso você tenha implementado o modelo descrito no Problema 1.1, bastaria fazer:
A.Position += A.Velocity * secs;
Veja o Problema 2.2 para um modelo físico levando em consideração a aceleração.
Problema 2.2: Movimentação Newtoniana simples
Problema: Em muitos games, é necessário uma forma simples que lembre a movimentação newtoniana no vácuo.
Solução: A forma abaixo considera a movimentação Newtoniana clássica no vácuo e um sistema de forças, que serão aplicadas ao corpo a cada game loop. A solução é leve o suficiente para ser usada em sistemas de partículas, e dá um bom resultado visual. Entretanto, para Steering Behaviors, considere o modelo proposto por Reynolds.
Você necessitará:
Um vetor considerando a direção em que o corpo está se movendo (Velocity). Na física, esse vetor também pode representar a energia de movimento acumulada, portanto, é comum que seja chamado de momentum.
A massa do veículo (mass);
Um vetor representando a posição do corpo (Position).
Uma função, que calcula a soma de todas as forças sendo aplicadas no corpo naquele Game Loop (calculateForces).
Um vetor representando a aceleração da gravidade (gravity);
O tempo transcorrido entre essa chamada de função e a última em segundos (secs);
O cálculo da posição é dado pela fórmula:
Pf = P0 + m * t + a * t² / 2
E a atualização do momento, que deve ocorrer a seguir, é dada por:
m = a * t;
Pf = Posição final
P0 = Posição atual
m = Vetor de momento linear
a = Vetor aceleração
double secs = (float)GameTime.ElapsedGameTime.TotalSeconds;
Vector2D acceleration = CalculateForces() / mass;
Vector2D accelSecs = acceleration * secs;
position += (momentum + accelSecs/2) * secs;
momentum += accelSecs;
Problema 2.3: Atração gravitacional simples
Problema: Calcular o vetor de força que representa a atração gravitacional entre dois agentes.
Calcular o vetor de trajetória entre o objeto sendo atraído (B) e o objeto que atrai (A);
Calcular a intensidade da força gravitacional, através da fórmula:
Fg = Força da gravidade resultante
G = Constante gravitacional universal. Na física real, equivale a 6,67428*10-11 m3/kg1s2. Em games, esse valor pode ser calibrado pelo game designer, para representar o quanto de "atratividade" ele gostaria para o planeta.
m1 e m2: As massas dos agentes A e B, respectivamente
d2: Distância ao quadrado entre o centro de massa dos dois corpos.
Multiplicar o resultado pela trajetória normalizada.
public Vector3 calculateGravityForce(Planet a, Ship b) {
Vector3 path = b.Position – a.Position;
float intensity = (a.g * a.mass * b.mass) / path.LengthSquared();
path *= intensity;
Problema 2.4: Reflexo, colisão elástica e colisão inelástica
Problema: Calcular o vetor resultante da colisão elástica de um objeto contra a superfície. Essa Fórmula também pode ser aplicada para o reflexo da luz contra um espelho perfeitamente plano.
Solução: Para o cálculo será necessário:
n: O vetor normal perpendicular à superfície. Esse vetor aponta para o local de onde o objeto vem;
I: O vetor de incidência (geralmente a Velocity do agente);
O cálculo é demonstrado pela figura:
Exemplo (reflexo e colisão elástica):
public Vector2 reflex(Vector2 incident, Vector2 normal) {
return incident – 2*normal.dot(Incident)*normal;
No caso do XNA, a função Vector2.Reflex realiza essa operação.
Variação: Para colisão inelástica, substituir o valor 2 por (1+C) onde C é o coeficiente de restituição (um número de 0 até 1, indicando o percentual de força que é restituído).
Exemplo (colisão inelástica):
public Vector2 reflex(Vector2 incident, Vector2 normal, float restituion=1) {
return incident – (1+restitution)*normal.dot(Incident)*normal;
Problema 2.4: Descobrir o vetor normal a partir dos vértices de uma face
Problema: Calcular automaticamente a normal de uma face, baseado na posição de seus vértices.
Dados os três vértices, v1, v2 e v3, obter os vetores dos lados através da subtração de v3-v1 e v2-v1;
Obter o vetor perpendicular a face é obtido obtendo-se o produto vetorial entre os dois vetores resultantes.
Normalize o resultado.
O gráfico abaixo demonstra o cálculo:
public Vector3 CalculateNormal(Vector3 v1, Vector3 v2, Vector3 v3) {
Vector3 normal = Vector3.Cross(v2 – v1, v3 – v1);
Nesse guia, procurei reunir as situações mais comuns para as primeiras aplicações envolvendo vetores. Logicamente, existem muitas outras situações em que os vetores seriam aplicáveis, especialmente se você decidir se aprofundar em computação gráfica ou física. Entretanto, se você ainda não usa essa fantástica ferramenta matemática, espero que o texto torne seu caminho muito mais fácil a partir de agora.
Se você gostou desse artigo e gostaria de se aprofundar mais ainda, confira também nosso material sobre matrizes e transformações (parte1 e parte 2).
Em caso de dúvidas poste uma mensagem ou entre em contato!
28/07/2012 02:53:43 |189.62.151.xxx| Vitor Almeida da Silva - Muito útil.
Realmente muito útil Vinícius, vai ajudar bastante gente.
28/07/2012 08:47:51 | Vinícius Godoy de Mendonça - Obrigado
06/08/2012 23:42:00 |177.68.202.xxx| Matheus
Esse site é o melhor site dev nacional, por favor continuem assim!
PS: Vocês precisam de algum tipo de ajuda finaceira (ex: para pagar o server)? Eu gostaria de contribuir!
07/08/2012 14:09:31 | Vinícius Godoy de Mendonça
Doações são sempre bem-vindas. Se quiser doar, mande um e-mail para o contato@pontov.com.br e te passamos as contas para o depósito.
07/08/2012 15:41:18 |177.32.36.xxx| Pigmeu
Coloca um botão do paypal pra galera doar, Vinícius!
07/08/2012 13:52:55 |177.83.86.xxx| Lucas - Sensacional!
Muito obrigado por esse artigo, vai me ajudar demais com a minha engine .
07/08/2012 14:09:42 | Vinícius Godoy de Mendonça
21/08/2012 10:10:03 |200.213.117.xxx| Victor Hugo Viana Santos
Qual matemática uso para programar shaders(GLSL)?
E um pequena sugestão, vocês poderiam abordar o tema mais tarde.
21/08/2012 12:02:04 | Vinícius Godoy de Mendonça
Está nos meus planos fazer uma série sobre o pipeline programável em opengl. Por enquanto, você pode ler os artigos de shaders do Thiago Pastor na sessão de XNA. Ele explica a matemática envolvida no modelo de iluminação de Phong.
21/08/2012 12:32:07 | Bruno Crivelari Sanches
Só um detalhe: a matemática usada em shaders é 80% vetores, que você encontra vários artigos aqui no PontoV e o resto matrizes e matemática básica (sendo que matrizes você também encontra aqui)
Os conceitos envolvidos depende do que você pretende fazer, mas os artigos de Shaders na sessão de XNA já cobrm todos os conceitos básicos de iluminação e alguns avançados, como Deferred Lighting. É só adaptar para a sintaxe do GLSL.
26/11/2012 20:50:25 |177.82.224.xxx| Renan - Seno para Radianos
Muito bom o post , só tenho uma pergunta , que nao tem nada a ver com o post , voce poderia me responder se é possivel eu converter um valor de seno em radianos , por exemplo tenho o seno 0,7071067 (45º)
em radianos ?
26/11/2012 22:54:54 |200.192.114.xxx| ViniGodoy - Seno para radiano
Sim, nas classes que acompanhar o primeiro artigo de vetores existe o método toRadians. É possível fazer essa conversão com a classe MathUtil do C# ou com a classe Math do Java também.
16/12/2013 14:10:52 |186.229.90.xxx| Carlos Magno - Conselho
16/12/2013 15:39:06 |189.123.217.xxx| ViniGodoy
É indispensável, especialmente em jogos 3D.
Pelo menos, o conceito de vetores e matrizes de transformação é. Você não precisa decorar como as operações são realizadas, mas deve saber exatamente o que fazem.
Por exemplo, você não precisa saber montar de cabeça uma matriz de rotação, nem saber escrever o algoritmo que calcula a inversa. Mas é importante saber o que essas operações fazem e quando usa-las.
As engines mais modernas usam fortemente o conceito de transformações. Você vai achar objetos de transformação Java (AffineTransform), em IOS (Transform), em Cocos2D, etc... Vai achar esses conceitos também em engines de física como a Box2D (a classe b2vec, por exemplo, representa um vetor).
Em 3D, então, nem se fala. Se for usar uma engine 3D, por mais básica que seja, terá que ter um bom conhecimento de matemática.
16/12/2013 17:30:28 |186.229.90.xxx| Carlos Magno
Bom, irei, antes de qualquer coisa, ler os livros Álgebra, Geometria 2D e Física da série Use a Cabeça(Por ter uma leitura descontraída e te colocar em uma perspectiva diferente), posteriormente desenvolver joguinhos sem quaisquer engines ou frameworks para ai então me considerar preparado? para o desenvolvimento "sério" de jogos em 2D.