Math for calculating angle between two points (2d)

Started by
6 comments, last by peb 15 years, 9 months ago
I've been searching Google alot, and i just can't figure out how to do it. This is what i want to do: move my character (possible shoot as well, but I'm focusing on the moving part now) in the direction of my mouse.. Ive found a few sites, like: http://gpwiki.org/index.php/Math:Vector http://www.vb-helper.com/howto_find_angles.html http://compsci.ca/v3/viewtopic.php?t=17339&postdays=0&postorder=asc&start=0 But i just cant seem to figure out how to do it in C/C++.. This is what ive got so far: arg1 = (float) (rect.y + (rect.h/2)) - (float)MouseY; arg2 = (float) (rect.x + (rect.w/2)) - (float)MouseX; answ = arg1/arg2; But i really have no idea if I'm even on the right path to solving this problem... Any help would be appreciated. I'm not looking for C++ source code, i can handle that part.. I just need the theory(Math). Thanks for reading this!
Advertisement
What you need to do is set up a right triangle between the two points where the hypotenuse is the line connecting the two points. We'll call the position of the mouse (Mx, My) and the position of your player (Px, Py). If you draw this you'll see that the triangle has a horizontal side length of (Mx - Px) and a vertical side length of (My - Py).

If you remember your basic geometry, this means that the tangent of the angle you're looking for is (My - Py) / (Mx - Px). Thus, the angle that you're looking for is the arctangent of (My - Py) / (Mx - Px).

Thus, your code is almost correct. Make this change:
answ = atan2(arg1,arg2);
Look up vector math, you probably want to just add some amount to the x and y of the character position in the direction of the mouse click.

you have a character at some point, call it "cp"
you have a mouse click position at another point, call it "mp"

A vector that points from cp toward mp is dir = mp - cp. Normalize this direction, multiple it by how much you want to move

charPos = charPos + (dir * moveAmount), what do you need the angle for?
First of, thanks Colin for your fast reply. That helped finding the angle.

Quote:Original post by NumberXaero
Look up vector math, you probably want to just add some amount to the x and y of the character position in the direction of the mouse click.

you have a character at some point, call it "cp"
you have a mouse click position at another point, call it "mp"

A vector that points from cp toward mp is dir = mp - cp. Normalize this direction, multiple it by how much you want to move

charPos = charPos + (dir * moveAmount), what do you need the angle for?


Yes that's exactly what i want to do, move the character towards the mouse pointer.

However, I don't really understand what you are trying to say. I've read some about vectors, and as i understand it this vector should contain all of the X and Y values that the player character has to travel through to get to the mouse pointer. How would i load in these coordinates into my vector?

Or do you have a simpler way of doing this? The (dir * moveAmount) part confused me a bit...
I don't really know why i needed an angle in the first place, I've never done something like this and i figured it would be a good place to start :)
struct vec2
{
float x, y;

// needs operator -
// normalize function
// probably few others
};


We treat these two as points

vec2 charPos; // is where character is
vec2 mousePos; // the click point

vec2 dir = mousePos - charPos; // the difference between the two points

now at this point dir might be (-100, 30), (40, -90), (8, 8), whatever, it just means if you add this directly to charPos, you will be at mousePos.
You probably dont want to go directly to mousePos, you want to go toward it, so you normalize dir (look that up if you dont know, it makes its length 1).
Now that its length is one, you can make it whatever length you want, by multiplying by something ("moveAmount"). once youve multiplied it by the amount you want to move (dir * moveAmount), you add this to the original charPos
charPos = charPos + (dir * moveAmount) and you have a new pos for the character.
This is very basic, youll probably want to look up time based movement later.

Quote:Original post by peb
First of, thanks Colin for your fast reply. That helped finding the angle.

Quote:Original post by NumberXaero
Look up vector math, you probably want to just add some amount to the x and y of the character position in the direction of the mouse click.

you have a character at some point, call it "cp"
you have a mouse click position at another point, call it "mp"

A vector that points from cp toward mp is dir = mp - cp. Normalize this direction, multiple it by how much you want to move

charPos = charPos + (dir * moveAmount), what do you need the angle for?


Yes that's exactly what i want to do, move the character towards the mouse pointer.

However, I don't really understand what you are trying to say. I've read some about vectors, and as i understand it this vector should contain all of the X and Y values that the player character has to travel through to get to the mouse pointer. How would i load in these coordinates into my vector?

Or do you have a simpler way of doing this? The (dir * moveAmount) part confused me a bit...
I don't really know why i needed an angle in the first place, I've never done something like this and i figured it would be a good place to start :)


That's as simple as it gets, don't be afraid of vectors. They are your friends!
This is a little picture showing what he means:



First of all you need a struct for vectors:

struct Vec2D{  float x;  float y;};


You will try to find out the vector between your player sprite and the mouse pointer (orange arrow). You can multiply this vector by any number to increase/reduce its length while still maintaining the direction. You will probably only want to move a tenth to the mouse pointer for example, so you would use "yellowVector / 10" or something like that.

The red vector, we'll call it "player", starts at (0,0) and goes to the position of your player. So this basically behaves like the point. Same for the mouse cursor. Let's define these from the coordinates that you already have then!

Vec2D player;player.x = playerSprite->X();player.y = playerSprite->Y();Vec2D mouse;mouse.x = input->MouseX();mouse.y = input->MouseY();


Now comes the really nifty part about vectors: The yellow vector which we want to find out, we'll call it "direction", connects the end of the red and blue vector. You can use vectors in equations, similar to usual numbers:

player + direction = mouse

But we don't want to calculate the mouse vector, we have that one, we want "direction". Let's twiddle with that equation a bit:
player + direction = mouse | -player
direction = mouse - player

Now, this was easy. Thanks to vectors we didn't have to use an angle or arctangens to figure that out. Let's implement it in C:

Vec2D direction;direction.x = mouse.x - player.x;direction.y = mouse.y - player.y;


This will now be the x and y distance from your player sprite to the mouse cursor. If you want to move half of that towards the mouse cursor now, you'll do this:

player.x += direction.x / 2;player.y += direction.y / 2;


That's all to it, really :)

In C++ you may want to make the Vec2D struct more convenient. C++ version:

#include <iostream>struct Vec2D{  Vec2D(float x, float y) : x(x), y(y) {}  Vec2D() : x(0.0f), y(0.0f) {}  Vec2D operator+(const Vec2D& other) { return Vec2D(x + other.x, y + other.y); }  Vec2D operator-(const Vec2D& other) { return Vec2D(y - other.x, y - other.y); }  void operator+=(Vec2D other) { x += other.x; y += other.y; }  Vec2D operator*(float times) { return Vec2D(x * times, y * times); }  float x;  float y;};int main(){  Vec2D player(40, 40);  Vec2D mouse(60, 60);  Vec2D direction = (mouse - player) * 0.5f;  std::cout << "Need to move by (x=" << direction.x << ",y=" << direction.y << ")" << std::endl;}


Hope this helps and encourages more people to get into vector math ;)
Quote:Original post by NumberXaero
now at this point dir might be (-100, 30), (40, -90), (8, 8), whatever, it just means if you add this directly to charPos, you will be at mousePos.
You probably dont want to go directly to mousePos, you want to go toward it, so you normalize dir (look that up if you dont know, it makes its length 1).
Now that its length is one, you can make it whatever length you want, by multiplying by something ("moveAmount"). once youve multiplied it by the amount you want to move (dir * moveAmount), you add this to the original charPos
charPos = charPos + (dir * moveAmount) and you have a new pos for the character.
This is very basic, youll probably want to look up time based movement later.


Wow, thanks for an excellent answer. I got it working now. It was alot easier than i thought!

Oh and btw, for anyone else out there with the same kind of problems:
http://gpwiki.org/index.php/MathGem:Vector_Operations#Normalize
There you can learn about Normalization, also if length(); does not work for you (it did not for me) you can use this instead:
float len = sqrtf(dir.x * dir.x + dir.y * dir.y);

Once again, thanks! Never thought i would solve this issue so quickly :)
Eskapade:

Sorry, i got your answer when i was typing a reply hehe. Thanks for the source code! i will probably get use of it, the code i use now is very ugly so i'll need to put it into classes and make it look nicer.

Thanks alot for that class in vector math's Eskapade :)

I'll c you guys around i guess, Thanks and Good Bye!

This topic is closed to new replies.

Advertisement