Páginas

segunda-feira, 3 de junho de 2013

Trigonometria em Ambientes Virtuais

O uso de trigonometria em ambientes virtuais nos permite simular as forças da física com realismo. Vamos tratar nesse post do lançamento obliquo. Para saber o que é isso preparei logo abaixo um jogo que demonstra. Mude a força do lançamento e seu ângulo para obter diferentes resultados. esse jogo leva em conta uma força constante de gravidade atuando sobre y. Não considero uma força de resistência em x, como a resistência do ar no mundo real.

Lançamento de Projétil

Força: 50
Ângulo: 45°



Seu navegador não suporta HTML5!


O conceito é similar ao do jogo Angry Birds, amplamente conhecido. Alterações no ângulo e força alteram a altura máxima alcançada, o tempo da trajetória e o alcance. Para definir tudo isso esse jogo só precisa de 2 parâmetros: a força empregada no lançamento e o ângulo. Porém para representar graficamente um objeto em movimento nós precisamos, em um instante do tempo por todo o percurso, saber suas coordenadas em relação ao eixo x e y do plano cartesiano. Como extrair a coordenada (x,y) se temos somente a força e o ângulo? É aí que entra a trigonometria!

Vamos ver o gráfico para analisar as informações que temos no momento inicial do lançamento:



Se o usuário setou uma força de 50 e angulo de 45 graus, temos a figura acima. A ponta da seta representa onde o objeto deverá estar no final do primeiro período de tempo. Porém, essa localização representa um valor no eixo x e no eixo y, como mostra a figura abaixo:



Como achar essa posição (x,y)? Analise bem essa gravura. Ela te lembra alguma coisa? Triângulo retângulo! Veja abaixo:



Todo triângulo retângulo tem um ângulo reto de 90 graus, uma hipotenusa (o maior lado) e dois catetos: adjacente (o lado colado ao angulo de referência (45 graus)) e o oposto (o lado oposto a esse ângulo de 45 graus). Se acharmos as medidas desses catetos, temos então a localização x,y do objeto daquele instante no tempo. Como determinar as medidas dos catetos? Vamos utilizar as clássicas relações trigonométricas: 

O seno de um ângulo é igual ao cateto oposto a esse ângulo dividido pela hipotenusa. Conforme abaixo:



Já o cosseno de um ângulo é igual ao cateto adjacente a esse ângulo dividido pela hipotenusa. Conforme abaixo:



Assim, substituindo os valores, poderemos achar a força em y conforme abaixo:



Utilize uma calculadora científica para achar o seno de 45. Achamos a força atuante no eixo y! Agora para achar a força atuante em x, vamos utilizar a fórmula abaixo:



Pronto, temos agora a força atuante em x. Para achar as coordenadas devemos ter em mente que o movimento em x é um simples M.R.U. (Movimento Retilínio Uniforme). Isso quer dizer que a velocidade do deslocamento em x (da esquerda para a direita) não se altera pois nesse eixo não temos nenhuma resistência ao projétil lançado (não temos o ar nem empurrando ou criando resistência). Assim basta somar a força ao ponto original de x e multiplicar pelo tempo decorrido que teremos essa coordenada. Logo, se x começou no ponto 0 do plano cartesiano, x agora vale 35,3 após o primeiro período de tempo decorrido. Então a fórmula é essa: 

X = (Pos.emX.Original) + (Força.emX) x (Tempo.decorrido)

Substituindo os valores temos:

X = 0 + 35,3 x 1 = 35,3 (no primeiro período de tempo o projétil andou 35,3 em x)

X = 0 + 35,3 x 2 = 70,6 (no segundo período de tempo o projétil andou 70,6 em x)

X = 0 + 35,3 x 3 = 100,9 (no terceiro período de tempo o projétil andou 100,9 em x)

Ou seja, no terceiro período de tempo a coordenada em x terá se deslocado 100,9 em relação ao ponto original, e isso em uma velocidade constante.

Já para achar o ponto em Y é um pouco mais complicado, pois agora temos a força da gravidade atuando. O movimento em Y é um M.R.U.V. (Movimento Retilínio Uniforme Variado). É variado por que a velocidade varia ao longo do tempo. Ela vai desacelerando a medida que chega no ponto mais alto e acelera até o chão, tudo devido a força constante da gravidade. Assim no próximo instante de tempo a força no eixo y sofrerá alteração. Veja o gráfico abaixo:



Para calcular o ponto em y num determiado período do tempo a partir dessa força vamos usar a fórmula:

Y = (Pos.emY.Original) - (Força.emY) x (Tempo.decorrido) + (Força.Gravidade) x (Tempo.decorrido²)/2

Substituindo os valores temos (supondo uma força 10 na gravidade):

Y = 0 - 35,3 x 1 + 10 x 1²/2 = -30,3  (no primeiro período de tempo o projétil andou 30,3 em y. Observe que andou menos que x nesse mesmo período por causa da gravidade. O valor está negativo por que no plano cartesiano computacional, quanto menor o valor de Y mais alto o projétil vai. Isso se da porque as coordenadas 0,0 estão no canto superior esquerdo do monitor)

Y = 0 - 35,3 x 2 + 10 x 2²/2 = -50,6  (no segundo período de tempo o projétil andou 50,6 em y. Observe que andou menos que x nesse mesmo período por causa da gravidade)

Y = 0 - 35,3 x 3 + 10 x 3²/2 = -60,9  (no segundo período de tempo o projétil andou 60,9 em y. Observe que andou menos que x nesse mesmo período por causa da gravidade)

Comparando os valores tanto no eixo x como em y os três períodos de tempo chegamos a conclusão:

         

Perceba que enquanto no eixo X o projétil se move a uma velocidade constante, no eixo Y ele sofre desaceleração devido a gravidade. Em determinado momento a força da gravidade terá anulado totalmente a força em Y, fazendo com que o projétil comece a descer ao invés de subir.

Dessa forma, podemos simular o lançamento oblíquo com a ajuda da trigonometria algumas contas.

Segue o código do game no início:

<center>
        <h1>Lançamento de Projétil</h1>
        <script>
            
            //força e angulo do lançamento definido pelo usuario atraves do slider
            var xo = 50;
            var yo = 265;
            var forca = 50;            
            var forca_gravidade = 10;
            var t = 0;
            var dt = 0.2;
            var angulo = 45;
            var lancou = false;
            
        </script>
        <table>
            <tr>
                <td>
                    Força: <span id="forca_label">50</span><br/>
                    <div id="slider_forca" style="width: 100px;"></div>
                    <script>
                        $('#slider_forca').slider({min:10,max:100, value:50, slide:function(event, ui){  forca = parseInt(ui.value); $('#forca_label').html(ui.value); }} );
                    </script>
                </td>
                <td>
                    Ângulo: <span id="angulo_label">45°</span><br/>
                    <div id="slider_angulo" style="width: 100px;"></div>
                    <script>
                        $('#slider_angulo').slider({min:1,max:90, value:45, slide:function(event, ui){  angulo = parseInt(ui.value); $('#angulo_label').html(ui.value+'°'); }} );
                    </script>
                </td>
                <td>
                    &nbsp;<br/>
                    <input type="button" value="Lançar" onclick="lancou = true;"/>
                </td>
            </tr>
        </table>

        <br/>
        <br/>
        <canvas id="game_lancamento" width="416" height="302" style="border: 1px solid #000000;">
            <p>Seu navegador não suporta HTML5!</p>
        </canvas>
        <script >
            // cria o contexto grafico no canvas
            var drawingCanvas = document.getElementById('game_lancamento');
            var ctx = drawingCanvas.getContext('2d');

            var framecount = 0;


            // carrega imagens

            var bgReady1 = false;
            var bgImage1 = new Image();
            bgImage1.onload = function () {
                bgReady1 = true;
            };

            bgImage1.src = 'campo_1.png';

            var bgReady2 = false;
            var bgImage2 = new Image();
            bgImage2.onload = function () {
                bgReady2 = true;
            };

            bgImage2.src = 'campo_2.png';

            var bolaReady = false;
            var bolabg = new Image();
            bolabg.onload = function () {
                bolaReady = true;
            };

            bolabg.src = 'bola_golf.png';

            //objetos do jogo
            var bola = {    
                x:50,
                y:265,
                w:30,
                h:30    
            };




            // frame update
            var update_lancamento = function(modifier){
                if(lancou && bola.y <= 265){
                    var rad= parseInt(angulo) * Math.PI / 180;
                    var vxo = forca * Math.cos(rad);
                    var vyo = forca * Math.sin(rad);
        
                    bola.x = xo + vxo * t;
                    bola.y = yo - vyo * t + forca_gravidade * Math.pow(t,2)/2;
                    t = t + dt;
                
                }else if(lancou){
                    // bola já tocou o chão
                    lancou = false;
                    bola.x = 50;
                    bola.y = 265;
                    t = 0;
        
                }
    
            }

            //render game
            var render_lancamento = function(){
                //clear no canvas
    
  
                if (bgReady1 && bgReady2) {
                    ctx.beginPath()
                    if(lancou){
                        ctx.drawImage(bgImage2, 0, 0);
                    }else{            
                        ctx.drawImage(bgImage1, 0, 0);   
                        //desenha atrajetoria da bola conforme o angulo e força
                        ctx.fillStyle = 'rgb(255, 255, 255)';
                        ctx.strokeStyle = 'rgb(255, 255, 255)';
                        ctx.moveTo(bola.x+14, bola.y+14);
                        var rad= parseInt(angulo) * Math.PI / 180;
                        var vxo = forca * Math.cos(rad);
                        var vyo = forca * Math.sin(rad);
                        ctx.lineTo(bola.x+vxo+14,bola.y-vyo+14);
                        ctx.arc(bola.x+vxo+14, bola.y-vyo+14, 5, 0, Math.PI*2, true);
                        ctx.stroke();
                        ctx.fill();
            
                    }
                    ctx.closePath()
                }
                if (bolaReady) {
                    ctx.drawImage(bolabg, bola.x, bola.y);
                }
            }

            //função que irá controlar o game loop
            var main_lancamento = function () {
                var now = Date.now();
                var delta = now - then;
                update_lancamento(delta / 1000);
                render_lancamento();
                then = now;
            };

            //iniciando o game
            var then = Date.now();
            setInterval(main_lancamento, 70);
        </script>  
    </center>

Não esqueça de importar no <head> o jquery e o jquery ui

<head>
        <title>Jogo</title>
        <link href='http://code.jquery.com/ui/1.9.2/themes/redmond/jquery-ui.css' rel='stylesheet'/>
        <script src="http://code.jquery.com/jquery-1.9.1.js" type="text/javascript"></script>
        <script src="http://code.jquery.com/ui/1.10.3/jquery-ui.js" type="text/javascript"></script>
    </head>

Atenciosamente,
Gustavo Marques






Veja também

Related Posts Plugin for WordPress, Blogger...