Welcome, Guest. Please login or register. Did you miss your activation email?

Author Topic: Calculating direction  (Read 7592 times)

0 Members and 1 Guest are viewing this topic.

zoran404

  • Newbie
  • *
  • Posts: 41
    • View Profile
Calculating direction
« on: March 19, 2013, 10:02:36 pm »
On the middle of the screen I have a sprite whose origin is set near the bottom, so in the start it "points" up.
Now when I get cursor coordinates how do I calculate what to set for rotation so that it "points" to the cursor position?

eXpl0it3r

  • SFML Team
  • Hero Member
  • *****
  • Posts: 10819
    • View Profile
    • development blog
    • Email
Re: Calculating direction
« Reply #1 on: March 19, 2013, 10:37:37 pm »
This is quite a common problem and with a bit math should be more or less easy to figure out.
But if it doesn't, then you can always google for something like: "calculate direction vector" :)
Official FAQ: https://www.sfml-dev.org/faq.php
Official Discord Server: https://discord.gg/nr4X7Fh
——————————————————————
Dev Blog: https://duerrenberger.dev/blog/

AlexAUT

  • Sr. Member
  • ****
  • Posts: 396
    • View Profile
Re: Calculating direction
« Reply #2 on: March 19, 2013, 10:44:34 pm »
There you will need some maths  ;)

I think this site will solve your problem : http://www.wikihow.com/Find-the-Angle-Between-Two-Vectors

In your case the first vecotor is the vector between the origin and the mouseposition and the second is the x-axis.


Some more informations:

the cos-1 = std::acos(); -> acos needs rad and not deg.

How to convert deg to rad : http://www.teacherschoice.com.au/maths_library/angles/angles.htm

zoran404

  • Newbie
  • *
  • Posts: 41
    • View Profile
Re: Calculating direction
« Reply #3 on: March 19, 2013, 11:48:30 pm »
Here is what I got from your link, but it appears that it dose not work correctly. Do you happen to know what is the problem?
gun.setRotation(std::acos(
        (vMode.width/2 * event.mouseMove.x + vMode.width/2 * event.mouseMove.y)/
        (std::sqrt(vMode.width*vMode.width/4 + event.mouseMove.x*event.mouseMove.x) *
            std::sqrt(vMode.height*vMode.height/4 + event.mouseMove.y*event.mouseMove.y))
    ) * todegrees); //57.2957795131
acos((x1*x2 + y1*y2) / ((x1^2 + x2^2) * (y1^2 + y2^2))) ?

AlexAUT

  • Sr. Member
  • ****
  • Posts: 396
    • View Profile
Re: Calculating direction
« Reply #4 on: March 20, 2013, 01:26:31 am »
I´m sorry, i did a misstake  :-[

std::acos returns a rad angle not needs one. Cos will need a angle and return a length

i wrote and example wich should help you:

  //Your origin
  sf::Vector2f origin(400,600);
           
  //Calculate the direction vector
  sf::Vector2f dirVec = sf::Vector2f(sf::Mouse::getPosition(window).x - origin.x, sf::Mouse::getPosition(window).y - origin.y);
           
  //Calculate the length^2
  float magSquare = (dirVec.x * dirVec.x) + (dirVec.y * dirVec.y);
           
  //Change the mag to 1 (you dont need the y for getting the angle)
  //Because the x-axis vector = (1|0) so dirVec.y * 0 = 0 -> it doesnt matter.
  dirVec.x = (dirVec.x * dirVec.x) / magSquare;

  //Get the angle and change it to deg (SFML need deg)
  float rotAngle = std::acos(dirVec.x) * (180/PI);
           
  //Do some stuff with it
  std::cout << rotAngle << std::endl;
 


AlexAUT

zoran404

  • Newbie
  • *
  • Posts: 41
    • View Profile
Re: Calculating direction
« Reply #5 on: March 20, 2013, 09:36:16 am »
This dosen't work either.
event.mouseMove.x -= vMode.width/2;
event.mouseMove.y -= vMode.height/2;
gun.setRotation(std::acos(
        (event.mouseMove.x * event.mouseMove.x)/
        (event.mouseMove.x * event.mouseMove.x + event.mouseMove.y * event.mouseMove.y)
    ) * todegrees);
acos((x * x) / (x * x + y * y)) ?

AlexAUT

  • Sr. Member
  • ****
  • Posts: 396
    • View Profile
Re: Calculating direction
« Reply #6 on: March 20, 2013, 10:15:48 am »
Yes, the formula is correct but you have to calculate the result (the angle) from rad to deg ( deg = rad * (180 / PI) ).

shape.setRotation(std::acos((x * x) / (x * x + y * y)) * (180/PI));


When it still dont work maybe you calculate your dirVector wrong. event.mouseMove.x return the change of the Mouseposition, but you need the current mouseposition.

sf::Vector2f dirVec = sf::Vector2f(sf::Mouse::getPosition(window).x - origin.x, sf::Mouse::getPosition(window).y - origin.y);

AlexAUT
« Last Edit: March 20, 2013, 10:20:45 am by AlexAUT »

zoran404

  • Newbie
  • *
  • Posts: 41
    • View Profile
Re: Calculating direction
« Reply #7 on: March 20, 2013, 10:43:14 am »
I do have  * (180/PI), it is * todegrees, which I defined in the program.
And I think event.mouseMove.x is the new position of the cursor.
« Last Edit: March 20, 2013, 11:14:30 am by zoran404 »

zoran404

  • Newbie
  • *
  • Posts: 41
    • View Profile
Re: Calculating direction
« Reply #8 on: March 20, 2013, 12:38:11 pm »
Your vector origin, that the position of my object, right?

AlexAUT

  • Sr. Member
  • ****
  • Posts: 396
    • View Profile
Re: Calculating direction
« Reply #9 on: March 20, 2013, 03:47:04 pm »
Ok i though you have a Sprite wich looks like an arrow, the peak should always aim at the mousecursor? Am I right?

And you change the Origin of the Sprite to its bottom side? So my Origin vector would be your sprite.getOrigin();



I made an whole example (you can find the image in the Attachments):

#include <iostream>
#include <SFML/Graphics.hpp>

#include <cmath>


const float PI = 3.14159265359f;

int main()
{
    sf::RenderWindow window;
    window.create(sf::VideoMode(800,600), "Test");

    sf::Texture tex;
    tex.loadFromFile("arrow.png");

    sf::Sprite arrow;
    arrow.setTexture(tex);
    arrow.setOrigin(arrow.getLocalBounds().width/2, arrow.getLocalBounds().height);
    arrow.setPosition(400,600);


    while(window.isOpen())
    {
        sf::Event e;

        while(window.pollEvent(e))
        {
            if(e.type == sf::Event::Closed)
                window.close();

            if(e.type == sf::Event::MouseMoved)
            {
                //Your origin
                sf::Vector2f origin = arrow.getPosition();

                //Calculate the direction vector
                sf::Vector2f dirVec = sf::Vector2f(sf::Mouse::getPosition(window).x - origin.x, sf::Mouse::getPosition(window).y - origin.y);

                //Calculate the length^2
                float magSquare = std::sqrt((dirVec.x * dirVec.x) + (dirVec.y * dirVec.y));

                //Change the mag to 1 (you dont need the y for getting the angle
                dirVec.x = (dirVec.x) / magSquare;

                //Get the angle and change it to deg (SFML need deg)
                float rotAngle = std::acos(dirVec.x) * (180/PI);

                arrow.setRotation(90-rotAngle);
            }


            window.clear();

            window.draw(arrow);

            window.display();
        }
    }


    return 0;
}


 



AlexAUT

[attachment deleted by admin]
« Last Edit: March 20, 2013, 03:49:05 pm by AlexAUT »

Grimshaw

  • Hero Member
  • *****
  • Posts: 631
  • Nephilim SDK
    • View Profile
Re: Calculating direction
« Reply #10 on: March 20, 2013, 04:50:30 pm »
I am not sure I understood what you're trying to achieve correctly. If what you want is to know the direction between point A and point B, here are two solutions:

Let's say your point A is at (100,100) and the point B(mouse cursor) is at (200,200) and you want to know programatically what is the direction the point A has to follow to meet point B.

You can get the radian angle between the two with this plug and play function:
float computeAngle(float ax, float ay, float bx, float by){
        return atan2((by - ay), (bx - ax));
};
 

Then compute the direction vector as (cos(angle), sin(angle)).

Or simpler, whenever you have two points, A and B, (A - B) gives you the direction vector between the two. Of course you may need to normalize that resulting vector between using it for calculations!

Hope this helps..

zoran404

  • Newbie
  • *
  • Posts: 41
    • View Profile
Re: Calculating direction
« Reply #11 on: March 20, 2013, 08:52:21 pm »
Ok i though you have a Sprite wich looks like an arrow, the peak should always aim at the mousecursor? Am I right?
And you change the Origin of the Sprite to its bottom side? So my Origin vector would be your sprite.getOrigin();
I made an whole example (you can find the image in the Attachments):
You are right, although, the origin isn't at the very botom because it is the top part of the tank.
And I just figured out why my implementation of your code didn't worked, it is because I use vindowmodes width/height (because it is in center), but from some reason it dosen't work unless I get position of the sprite like you did.
There was only one problem with your example, it only works with if the mouse is above the tanks gun, if it is lower than it then it still points up, that is because we get the cosinus. But I added a condition to switch it to down if it is lower than it.

Thanks for helping :)