Envie Artigos e Concorra a Prêmios
 
Artigos
Article List
Relacionando Angulos e Vetor Diretor com XNA
Explicacao baseada em um jogo
Enviado por Luciano José em 10/1/2008 0:00:00

Para demonstrar esse relacionamento entre angulos e vetor diretor, será usado como base um tech demo.

Link do tech demo

 Os Sprites do Et e Missel sao propriedades de André Furtado.


 

Após ter dado uma jogada, a explicação do assunto em questao será baseado na criaçao de um prototipo:

Observe o Et, e imagine um plano cartesiano sobre ele. Observe também a flecha que sai do Et; essa seta é chamada de vetor diretor. Esse vetor vai representar a orientação do Et, e também aonde ele está apontando.

foto1

No tech demo foi escolhido de inicio o vetor diretor (1, 0).

Iniciando o Prototipo:

public class Et
{ 
        ///
        /// Textura do Et
        ///
        public Texture2D Textura;
       
        ///
        /// posicao do Et na tela
        ///
        public Vector2 Posicao;
 
        ///
        /// Angulo de inclinacao do et em graus
        ///
        private float angulo;
 
        ///
        /// Este campo indica a Inclinacao do Et
        /// sendo utilizado no metodo Draw, e sera
        /// modificado apenas dentro da Propriedade Angulo
        ///
        private float rotacao;
 
        ///
        /// Direcao a qual o Et aponta, esse vetor, esse
        /// Vetor sempre estará normalizado, tendo como comprimento,
        /// tamanho, intensidade, etc, o valor 1
        ///
        private Vector2 direcao;
 
        public Vector2 Direcao
        {
            get { return this.direcao; }
        }

 

Construtor do Et:
 
public Et()
{
            this.rotacao = 0;
            this.Missel = new Missel();
            this.Direcao = new Vector2(1, 0);

}

No momento que o Et é instanciado, o ângulo de inclinação do Et é 0(zero). Logo o Et como orientação um vetor diretor (1, 0) . Observe a figura:

foto2

Quando é pressionado as teclas: seta para cima ou seta para baixo, é requerido que o Et mude a sua rotação. Quando a seta para cima é pressionada o ângulo é aumentado de um em um, então, a orientação do Et é modificada no sentido Anti-Horario. Se a seta para baixo é pressionada, a orientação do Et é modificada no sentido Horário. 

if (kb.IsKeyDown(Keys.Up))

            {

                this.et.Angulo += 1;

            }

Veja o comportamento na figura: 

 foto3

            if (kb.IsKeyDown(Keys.Down))
            {
                this.et.Angulo -= 1;
                   
            }

 Veja o comportamento na figura: 

 

 

foto4

Obtendo o vetor diretor com o ângulo atual que foi passado para a propriedade et.Angulo

 

Observe na figura o problema:

foto5

No código, o ‘a’ da foto representa o et.Angulo
 
O que queremos é o Vetor v e já temos o Ângulo a, como estamos abstraindo um plano catersiano, observe o triangulo no qual o ângulo a pertence. Observe o triangulo com seus catetos e sua hipotenusa.
 
 
Sabe-se que :
 
cos(a) = catetoAdjacente/hipotenusa
 
                         e
 
 sin(a) = catetoOposto / hipotenusa.
 
 
cos(a) e sin(a) já é conhecido nosso. E a hipotenusa também.
 
Como o vetor v, que é o objetivo a ser encontrado, é um vetor diretor  e será um vetor normalizado pelo fato dos resultados de seno e coseno sempre apresentarem resultados entre -1 e 1, e todo vetor normalizado tem comprimento 1.
 
Procura-se as componentes do vetor v, o seu x e y.
 
Logo, para obtermos o x precisamos achar o valor do cateto oposto e para se obter o valor do y é necessário achar o valor do cateto adjacente.
 
catetoAdjacente = hipotenusa * cos(a)
 
A hipotenusa é 1, logo temos catetoAdjacente = cos(a)  ou  ainda  x = cos(a)
 
catetoOposto = hipotenusa * sin(a)
 
A hipotenusa é 1, logo temos catetoOposto = sin(a)  ou ainda   y = sin(a)

 

Para melhor entendimento, olhe novamente a foto5

 
Mediante o que foi dito acima, observe a propriedade Ângulo:
 
public float Angulo
{
            get { return this.angulo; }
           
            set
            {
                this.angulo = value;
 
                if (angulo < 0)
                {
                    this.angulo = 360;
                }
                else if (angulo > 360)
                {
                    this.angulo = 0;
                }
 
                // o campo angulo nesse momento estará entre 0 e 360
                // entao, será necessario armazenar o seu valor
                // em radianos, para ser utilizado no metodo draw               
                this.rotacao = MathHelper.ToRadians(angulo);
 
                /*
                 * os metodos Math.Cos e Math.Sin recebem como parametro
                 * o angulo estando em radianos
                 * */
                this.Direcao.X = (float)Math.Cos(rotacao);
                this.Direcao.Y = (float)Math.Sin(rotacao);            
               

}

 

Movendo o Et - tanto para esquerda ou direita - de acordo com a sua orientação(vetor diretor):
 

 No metodo Update tem-se:

if (kb.IsKeyDown(Keys.Right))
            {
                this.et.Posicao +=
                   Vector2.Multiply(et.Direcao,
                    5);
            }
 
            if (kb.IsKeyDown(Keys.Left))
            {
                this.et.Posicao -=
                    Vector2.Multiply(et.Direcao,
                    5);
            }
 

Observe a foto:

Imagine que um vetor diretor (1,1), quando multiplica-se, ambas as componentens (x, y) – o resultado é um vetor multiplo ao vetor diretor, com a mesma direção. No código foi colocado o vetor diretor sendo multiplicado por 5. Entenda o 5 sendo a quantidade de pixels.

--------------------------------------------------------------------------------------------------------------

Observação.: Se você quisesse implementar aceleração, por exemplo, no Et ou no Missel, bastava fazer os devidos calculos de aceleração e logo após faria:

 

velocidade += aceleracao;

this.et.Posicao += Vector2.Multiply(et.Direcao, velocidade);

----------------------------------------------------------------------------------------------------------------

Atirando o Missel com a mesma direcao que o Et aponta:

No método Update é encontrado fragmento de codigo a seguir:
 
if (kb.IsKeyDown(Keys.Space))
            {
                this.et.Atacar();
            }
 
Observemos o metodo Atacar do Et:
 
public void Atacar()
        {
            this.Missel.Direcao = this.Direcao;
 
            this.Missel.Posicao = this.Posicao;
 
            this.Missel.Rotacao = this.rotacao;
        }
 

O missel atribuido ao Et, depois que o Metodo Atacar é chamado, tem a mesma Direcao que o Et, observe a foto:

Logo após a chamada do metodo Atacar, ele também tem a mesma posicao e a mesma rotacao que o Et, como pode ser visto na imagem.
Observe o metodo Update Do missel e veja que ele segue a mesma regra que a movimentação do Et:
 
public void Update(GameTime gameTime)
        {
            this.Posicao +=
                Vector2.Multiply(this.Direcao, 2);

        }

 

Código do Prototipo:

Código final:
 
    public class Et
    {
        ///
        /// Textura do Et
        ///
        public Texture2D Textura;
       
        ///
        /// posicao do Et na tela
        ///
        public Vector2 Posicao;
 
        ///
        /// Angulo de inclinacao do et em graus
        ///
        private float angulo;
 
        ///
        /// Este campo indica a Inclinacao do Et
        /// sendo utilizado no metodo Draw, e sera
        /// modificado apenas dentro da Propriedade Angulo
        ///
        private float rotacao;
 
        ///
        /// Direcao a qual o Et aponta, esse vetor, esse
        /// Vetor sempre estará normalizado, tendo como comprimento,
        /// tamanho, intensidade, etc, o valor 1
        ///
        private Vector2 direcao;
 
        public Vector2 Direcao
        {
            get { return this.direcao; }
        }
 
        ///
        /// A Rotacao do Et sera modificada apenas
        /// por meio dessa propriedade, é aqui, também, aonde
        /// será obtido a direcao do Et mediante ao angulo
        ///
        public float Angulo
        {
            get { return this.angulo; }
           
            set
            {
                this.angulo = value;
 
                if (angulo < 0)
                {
                    this.angulo = 360;
                }
                else if (angulo > 360)
                {
                    this.angulo = 0;
                }
 
                // o campo angulo nesse momento estará entre 0 e 360
                // entao, será necessario armazenar o seu valor
                // em radianos, para ser utilizado no metodo draw               
                this.rotacao = MathHelper.ToRadians(angulo);
 
                /*
                 * os metodos Math.Cos e Math.Sin recebem como parametro
                 * o angulo estando em radianos
                 * */
                this.direcao.X = (float)Math.Cos(rotacao);
                this.direcao.Y = (float)Math.Sin(rotacao);            
               
            }
        }
 
        public Missel Missel;
 
        public void Atacar()
        {
            this.Missel.Direcao = this.direcao;
 
            this.Missel.Posicao = this.Posicao;
 
            this.Missel.Rotacao = this.rotacao;
        }
       
        public Et()
        {
            this.rotacao = 0;
            this.Missel = new Missel();
            this.direcao = new Vector2(1, 0);
        }
 
        public void Draw(SpriteBatch spriteBatch)
        {
            spriteBatch.Draw(
                this.Textura, this.Posicao, null, Color.White,
                this.rotacao, new Vector2(0, 0),
                1f, SpriteEffects.None, 0);
        }
    }
 
    public class Missel
    {
        ///
        /// Textura do Missel
        ///
        public Texture2D Textura;
 
        ///
        /// Posicao do Missel na Tela
        ///
        public Vector2 Posicao;
 
        ///
        /// Direcao a qual o Missel aponta, esse vetor, esse
        /// Vetor sempre estará normalizado, tendo como comprimento,
        /// tamanho, intensidade, etc, o valor 1
        ///
        public Vector2 Direcao;
      
        ///
        /// Este campo indica a Inclinacao do missel
        /// sendo utilizado no metodo Draw, e sera
        /// modificado apenas dentro da Propriedade Angulo
        ///
        public float Rotacao;
 
        public Missel()
        {
            this.Rotacao = 0;
            this.Direcao = new Vector2(1, 0);
        }
 
        public void Update(GameTime gameTime)
        {
            this.Posicao +=
                Vector2.Multiply(this.Direcao, 2);
        }
 
        public void Draw(SpriteBatch _spriteBatch)
        {
            _spriteBatch.Draw(
                this.Textura, this.Posicao, null, Color.White,
                this.Rotacao, Vector2.Zero, Vector2.One,
                SpriteEffects.None, 0);
        }
    }
 
    public class Game1 : Microsoft.Xna.Framework.Game
    {
        GraphicsDeviceManager graphics;
 
        SpriteBatch spriteBatch;
 
        Et et;
 
        . . .
        protected override void Initialize()
        {
            this.et = new Et();          
 
            base.Initialize();
        }
               
        protected override void LoadContent()
        {
            spriteBatch = new SpriteBatch(GraphicsDevice);
 
            this.et.Textura = this.Content.Load<Texture2D>("Et");
 
            this.et.Missel.Textura =
                this.Content.Load<Texture2D>("Missile");
        }

        . . .

 
        protected override void Update(GameTime gameTime)
        {
            if (GamePad.GetState(PlayerIndex.One).Buttons.Back == ButtonState.Pressed)
                this.Exit();
 
            KeyboardState kb = Keyboard.GetState();
 
            if (kb.IsKeyDown(Keys.Space))
            {
                this.et.Atacar();
            }
 
            if (kb.IsKeyDown(Keys.Right))
            {
                this.et.Posicao +=
                    Vector2.Multiply(et.Direcao,
                    5);
            }
 
            if (kb.IsKeyDown(Keys.Left))
            {
                this.et.Posicao -=
                    Vector2.Multiply(et.Direcao,
                    5);
            }
 
            if (kb.IsKeyDown(Keys.Up))
            {
                this.et.Angulo += 1;
            }
 
            if (kb.IsKeyDown(Keys.Down))
            {
                this.et.Angulo -= 1;
                   
            }
 
            this.et.Missel.Update(gameTime);
 
            base.Update(gameTime);
        }
        . . .
    }

 

Algumas fotos do Prototipo:

 
 

 

Prototipo para download:  anguloevetordiretor.zip 55062 bytes

 


Críticas, Dúvidas e Sugestões sao bem-vindas.

Obrigado!

 


Sobre o Autor

???
Não Definido
Não Definido
Ocorreu um erro.
Ocorreu um erro.


Clique para avaliar:

Comentários
" aeew pessoal, Obrigado, vlw!!!"
Enviado por lucianoJose em 22/4/2008 11:31:30:
 
" Perfeito o artigo! Parabéns cara!"
Enviado por Gutemberg Ribeiro em 27/1/2008 13:46:27:
 
" realmente, um ótimo material :-)
parabéns.
"
Enviado por jferreira em 14/1/2008 13:37:27:
 
" Mais um excelente artigo luciano, parabéns. Muito útil. "
Enviado por Jose Antonio Farias em 11/1/2008 9:29:58:
 

Adicione seu Comentário
PrêmiosMinimizar

Envie um artigo para o Sharpgames, colabore com a comunidade e fique famoso! Clique aqui e saiba mais.

Logos do XBox 360, XNA e Games For Windows
Copyright 2010 por SharpgamesPolítica de Privacidade  |  Termos de Uso