Conectar-se
Quem está conectado
9 usuários online :: Nenhum usuário registrado, Nenhum Invisível e 9 Visitantes

Nenhum

Ver toda a lista


Compartilhe
Ir em baixo
avatar
Ranking : Nota D
Notas recebidas : D - C - D - C
Data de inscrição : 14/05/2009
Número de Mensagens : 713
Insígnias de JAM :

Insignia 1x 0 Insignia 2x 0 Insignia 3x 0
Reputação : 7

Prêmios
   : 0
   : 0
   : 1
Ver perfil do usuário

Utilizando vetores nos movimentos

em Dom 10 Jun 2018, 21:28
Título: Utilizando vetores nos movimentos
Versão do GM: a partir do 6
Dificuldade: Fácil
Link para download da Engine

Vetores

Mas o que realmente são vetores? Bem, não é um conceito difícil. Você pode pensar em um vetor como uma seta. Algumas grandezas só precisam de um número para ser descritas, como a massa, a altura ou o seu nível de satisfação com este post, em uma escala qualquer. São as grandezas escalares. Mas outras grandezas precisam de uma intensidade (módulo, magnitude ou norma), uma direção e um sentido, por exemplo, a velocidade, aceleração ou uma força. São as grandezas vetoriais.

No Game Maker (GM) um ponto qualquer da Room pode ser definido como o par ordenado A(x, y). Se você tomar um outro ponto, digamos, B(x', y'), existe um vetor AB cuja norma é a distância entre A e B, a direção é a mesma da reta suporte desse segmento e o sentido é "de A para B". Note que A e B são pontos genéricos. Um vetor, falando de uma forma mais formal, é o conjunto de todos os segmentos de mesma norma, mesma direção e mesmo sentido. Se A(0, 5), B(0, 10), C(20, 30) e D(20, 35), então AB e CD representam o mesmíssimo vetor, porque a norma, a direção e o sentido de AB e CD são os mesmos (respectivamente, 5, perpendicular ao eixo X e de baixo para cima). Você também pode encontrar as coordenadas de um vetor fazendo a diferença entre a extremidade e a origem. P. ex.: AB = B - A = (0, 10) - (0, 5) = (0, 5) e CD = D - C = (20, 35) - (20, 30) = (0, 5). Notou como AB e CD representam o mesmo vetor?

Você pode somar vetores simplesmente somando suas coordenadas. P. ex.: considere os vetores v (2, 5) e u(4, 8). Então v + u = (2 + 4, 5 + 8) = (6, 13). Não existe subtração entre vetores. Mas a notação v - u é utilizada para somar v com o oposto do vetor u, que tem a mesma norma e direção, mas o sentido contrário. O procedimento é análogo. (Note que se AB = v e BC = u, então AB + BC = AC).

Existem muitas outras operações interessantes envolvendo vetores, mas essa noção já basta para o que irei apresentar aqui.

Entendi. E daí?

Na física, em especial, na Mecânica clássica, os vetores são fundamentais no estudo do movimento. Isso porque eles não definem dois pontos, mas um conjunto de pontos que variam com o tempo. Isso quer dizer que se tivermos um objeto, digamos, uma bola, e aplicarmos um vetor horizontal, da esquerda para a direita, com intensidade 5, então a cada instante (step) sua posição irá variar 5 pixels, criando um movimento lateral. Se adicionarmos um segundo vetor perpendicular ao primeiro com intensidade inicial igual a 10, de baixo para cima, os vetores irão se somar e o resultado será um movimento em linha reta 5 pixels para a esquerda e 10 pixels para cima a cada instante. Adicionando ainda um terceiro vetor de intensidade .5, também vertical, mas de cima para baixo, a resultante será um vetor oblíquo que descreve um movimento de salto com movimento lateral em um arco perfeito.

Quer ver como isso funciona na prática? Vamos colocar a mão na massa!

Plataforma

Crie um objeto qualquer. Eu criei um com sprite de bola, daquelas que já vêm nos sources do GM. Agora, no evento Create, declare as variáveis:

Código:
vet[1] = 0;
vet[2] = 0;
vet[3] = .5;

lim = room_height - sprite_height*.5;

Os três vet significam os módulos dos vetores que usaremos. O "lim" é o limite inferior da room, para impedir que a nossa pseudo-gravidade atue indefinidamente. Naturalmente, você pode criar um objeto para ser o chão e adicionar uma colisão clássica.

Agora, no evento Step, as definições de movimento:

Código:
/*Adicionando uma magnitude ao vetor v[1]. Note que isso implica na criação
de um vetor-aceleração paralelo a v[1], cuja atuação se limita a |v[1]| < 6*/
if keyboard_check(vk_right) {
    if vet[1]<6 then vet[1] += 2;
};
if keyboard_check(vk_left) {
    if vet[1]>-6 then vet[1] -= 2;
};
//Adicionando uma magnitude ao vetor v[2]
if keyboard_check_pressed(vk_up) {
    if y = lim then vet[2] = 10;
};

//Aplicando uma desaceleração quando nenhuma tecla de movimento for pressionada
if !(keyboard_check(vk_right)||keyboard_check(vk_left))&&y = lim {
    if abs(vet[1]) > 0 {//previnindo uma divisão por zero
        vet[1] -= 2*vet[1]/abs(vet[1]);
        /*Abs(x) é uma função muito útil que retorna um valor positivo para qualquer
        variável. E.: abs(10) = 10 e abs(-30) = 30. É o módulo matemático.*/
    };
};
image_angle -= vet[1];
//Note que v[3] altera o módulo de v[2] para menos, logo:
vet[2] -= vet[3];
//Já o v[2] altera a posição vertical, no eixo y, até o limite inferior
y -= vet[2];
if y > lim {
    y = lim;
    vet[2] = 0;
};
//Enquando o vet[1] altera a posição horizontal, no eixo x
x += vet[1];

Observe que o módulo dos vetores às vezes vão ficar negativos, o que, do ponto de vista matemático é absurdo, mas aqui o GM interpreta como uma mudança de sentido. Por exemplo, se o vetor AB tem módulo -5, então o GM interpreta como o vetor BA de módulo 5. Em via de regra, o módulo de um vetor partindo da origem é a raiz da soma dos quadrados de suas coordenadas, por este motivo ele não pode ser negativo.

Pois bem, se você ainda não conseguiu enxergar os vetores nessa brincadeira, vamos desenhá-los no evento Draw:

Código:
//Vetor horizontal
draw_arrow(x,y,x + vet[1]*6,y,10);
//Vetor vertical
draw_arrow(x,y,x,y - vet[2]*6,10);
//Vetor resultante, v[1] + v[2]
draw_arrow(x,y,x + vet[1]*6,y - vet[2]*6,10);
//onde x e y são a origem do sistema

draw_sprite_ext(sprite_index,image_index,x,y,image_xscale,image_yscale,image_angle,noone,image_alpha);
Eu tomei a liberdade de aumentar o comprimento das setas 6x em relação aos vetores reais, isso para facilitar a vizualização.


Você, como um bom observador, sem dúvida notou que os vetores v[1] e v[2] fazem exatamente a mesma coisa que as variáveis canônicas hspeed e vspeed, respectivamente. Elas são perfeitamente coincidentes. O que nós fizemos aqui foi recriar essas variáveis para que você conseguisse enxergar o tratamento vetorial nelas.

Naturalmente, os vetores não se limitam a isso. Qualquer movimento ou projeção exige um tratamente vetorial. Vamos a outro exemplo.

Movimento Circular

Eu peguei um sprite de meteoro - chamado spr_meteoro - e criei um objeto. Vamos fazer um sistema binário com centro de gravidade mútuo. Parece difícil, mas com vetores fica bem fácil, veja só.

Utilizaremos o tempo todo conceitos do Movimento Circular Uniforme (você lembra das aulas de Física, não lembra?). E adivinha qual é a principal descrição desse tipo de movimento? Vetorial.
No Create, declare as variáveis:
Código:
//O vetor que representa a velocidade linear
vet[1] = 10;
dir[1] = pi/2;
//O vetor da aceleração centrípeta
vet[2] = .4;
dir[2] = pi;
//A origem do sistema, que também será o nosso centro de gravidade
Ox = room_width*.5;
Oy = room_height*.5;

Antes de prosseguirmos, é bom ter em mente o que é Aceleração Centrípeta. No exemplo anterior, a gravidade alterava a magnitude do nosso vetor que descrevia o movimento vertical. Mas a aceleração centrípeta não altera o módulo do vetor velocidade linear aqui, em vez disso, ele altera a direção desse vetor. Dessa forma, a velocidade é constante e a variação da direção provoca o movimento circular.

No Draw, adicione:
Código:
var w,R;
//determinando o Raio do círculo descrito pelo movimento
R = sqr(vet[1])/vet[2]
//determinando a velocidade angular pela relação Act = w^2 * R
w = sqrt(vet[2]/R);
//Alterando a direção do vetor V[1]
dir[1] += w;
dir[2] = dir[1] + pi/2
//Aplicando um efeito bacana
image_angle = radtodeg(dir[1]*3)

//Primeiro meteoro
x = Ox + cos(dir[1])*R;
y = Oy - sin(dir[1])*R;
draw_sprite_ext(spr_meteoro,0,x,y,image_xscale,image_yscale,image_angle,noone,image_alpha);
//Vetor velocidade linear
draw_arrow(x,y,x + cos(dir[1]+pi/2)*vet[1]*6,y - sin(dir[1]+pi/2)*vet[1]*6,10);
//Vetor A. Centrípeta (Muito provavelmente não será desenhado)
draw_arrow(x,y,x + cos(dir[2]+pi/2)*vet[2]*6,y - sin(dir[2]+pi/2)*vet[2]*6,10);

//Definindo um reflexo (basta trocar os sinais)
var x1, y1;
x1 = Ox - cos(dir[1])*R;
y1 = Oy + sin(dir[1])*R;
draw_sprite_ext(spr_meteoro,0,x1,y1,image_xscale,image_yscale,-image_angle,noone,image_alpha);
draw_arrow(x1,y1,x1 + cos(dir[1]+3*pi/2)*vet[1]*6,y1 - sin(dir[1]+3*pi/2)*vet[1]*6,10);
draw_arrow(x1,y1,x1 + cos(dir[2]+3*pi/2)*vet[2]*6,y1 - sin(dir[2]+3*pi/2)*vet[2]*6,10);

Você pode ser um cara mais organizado do que eu e colocar os cálculos no evento Step.
Note que para vetores paralelos aos eixos x e y, as transformações são mais simples. Mas quando o ângulo muda, precisa pedir ajuda à Trigonometria. Lembrando que as funções trigonométricas do GM trabalham com radianos, por isso achei legal já declarar tudo nessa unidade. Para mais informações sobre Trigonometria, veja este post.

O resultado é um sistema binário entre dois cometas que dividem um centro de gravidade.


Em resumo, vetores são poderosas ferramentas matemáticas que, bem usadas, podem descrever movimentos suaves de uma forma simples e, o melhor, sem bugs.
Voltar ao Topo
Permissão deste fórum:
Você não pode responder aos tópicos neste fórum