godotengine / godot-proposals

Godot Improvement Proposals (GIPs)
MIT License
1.16k stars 97 forks source link

Add Axis option to `Vector2.angle_to_point()` #9092

Closed LordMcMutton closed 9 months ago

LordMcMutton commented 9 months ago

Describe the project you are working on

A project that requires the use of angle_to_point on the forward axis

Describe the problem or limitation you are having in your project

I'm making a "simple" piece of target tracking code, and need to know what side of the Tracker the Tracking Target is on

angle_to_point is the best way to get the angle between the Tracking Target and the Tracker, but since it can only use the X axis in its calculations, the resulting radian angle is offset at 90 degrees

Describe the feature / enhancement and how it helps to overcome the problem or limitation

Add in an extra argument that tells angle_to_point which axis to base its calculations on, between X and Y

Describe how your proposal will work, with code, pseudo-code, mock-ups, and/or diagrams

float angle_to_point ( Vector2 to, Vector2 axis )

If this enhancement will not be used often, can it be worked around with a few lines of script?

I haven't been able to find a way to rotate the radian result by 90 degrees

Is there a reason why this should be core and not an add-on in the asset library?

Adding a useful function to an already-existing method

AThousandShips commented 9 months ago

This would need a separate method, ~the original method would change behaviour even with a default value as it doesn't rely on any axis~

~I'd suggest a angle_to_in_plane or similar, with the second argument being the normal of said plane~

Edit: didn't realize it was 2D at first, then it works differently

aaronfranke commented 9 months ago

I don't think this is common enough to need this functionality in the engine core.

LordMcMutton commented 9 months ago

It's equally as valid as basing the angle on the object's X axis- more functionality is always better, anyway.

Especially given that Godot's system focuses on having Z as a forward axis.

aaronfranke commented 9 months ago

@LordMcMutton No, the X axis being zero rotation is the standard in mathematics and in all of Godot's angle functions. If you run Vector2.from_angle(0) you will get a unit vector on the X axis ((1, 0)). It is not equally valid, X is preferred.

more functionality is always better, anyway.

This is not true, in fact Godot's philosophy is the exact opposite. Local solutions to local problems, avoid uncommon things bloating the core. More functionality means more bloat for people not using that functionality.

LordMcMutton commented 9 months ago

X axis being zero rotation is the standard in mathematics and in all of Godot's angle functions

Which steps on the toes of the Z-Forward mentality.

Currently, it works if you need to figure out if something is in front of behind something- it needs to also work if you need to figure out if something is to the left or right of something

X is only perferred in situations where X is useful- if X isn't useful, then the function is useless

This wouldn't be "bloat", it would be an expansion of the functionality

Regardless, thank you for expounding on your thoughts

AThousandShips commented 9 months ago

So to work this out for the four principal axes you do:

func angle_to_point_pos_x(vec1: Vector2, vec2: Vector2) -> float:
    return vec1.angle_to_point(vec2)

func angle_to_point_pos_y(vec1: Vector2, vec2: Vector2) -> float:
    return (vec2 - vec1).orthogonal().angle()

func angle_to_point_neg_x(vec1: Vector2, vec2: Vector2) -> float:
    return (vec1 - vec2).angle()

func angle_to_point_neg_y(vec1: Vector2, vec2: Vector2) -> float:
    return (vec1 - vec2).orthogonal().angle()

You can also do, with any axis:

func angle_to_point_axis(vec1: Vector2, vec2: Vector2, axis: Vector2) -> float:
    return angle_difference(axis.angle(), vec1.angle_to_point(vec2))

Or

func angle_to_point_axis(vec1: Vector2, vec2: Vector2, axis: Vector2) -> float:
    return axis.angle_to(vec2 - vec1)
LordMcMutton commented 9 months ago

That looks like it should be what I was looking for

I tried refactoring my code using that, but it didn't seem to change the result- the behavior was still X Forward. That said, I don't have a lot of time at the moment, so I only did some cursory modifications. I'll have more time tomorrow to try several alterations.

If that is, indeed, the solution, then I'd recommend adding an addendum to the _Vector2.angle_topoint() documentation mentioning Vector2.orthogonal() as a way to get the angle along the Y Axis

AThousandShips commented 9 months ago

Then you didn't copy my code correctly as the code I provided works, unless you want something else than the angle relative to some other axis

I don't think this needs to be added to the documentation, it's extremely unusual to use, and the way to do it is to just use angle_to with the direction (the third example I provided), I don't see anyone else needing this really, so I don't think we should clutter the documentation with it

For example:

print(rad_to_deg(angle_to_point_axis(Vector2(1, 1), Vector2(2, 2), Vector2(1, 0)))) # Prints 45, as desired
print(rad_to_deg(angle_to_point_axis(Vector2(1, 1), Vector2(2, 2), Vector2(0, 1)))) # Prints -45, as desired

You also have angle_difference which is also for this purpose, and is well documented, I don't think this niche use case should be added to the documentation, the established coordinate system (and mathematics in general) is followed by having the angle be relative to the x axis

LordMcMutton commented 9 months ago

My use case is a bit more complicated than just getting the angle- like I said, I was going to try more involved changes when I have more time. Until I do, I won't be able to speak on the specifics of the use case with this new information in mind.

I was going to mention this to AaronFranke, but Godot is more than just a basic math engine- it's a game development tool. It's okay to have stuff that helps with game development, even if it doesn't perfectly align with general mathematical practices.

If the engine uses Z Forward as a concept, why shouldn't there be support for that, especially something as minor as a small documentation addition? Personally, I think the documentation is too bare-bones as it is, anyway.

AThousandShips commented 9 months ago

What does z forward have to do with anything? This is two dimensions where there is no z axis?

The documentation tells you what it does and how it works, it works just like the angle works in general mathematics and geometry, essentially equivalent to atan2, which it uses

My use case is a bit more complicated than just getting the angle

Well then your proposal should contain that very fundamental information so people can understand what you are asking for... You asked for:

Add in an extra argument that tells angle_to_point which axis to base its calculations on, between X and Y

And I gave you exactly that, and I don't know what was not sufficient in that solution

If you need an angle from a Node2D then use get_angle_to which is in the local coordinates of the node

LordMcMutton commented 9 months ago

What an unfriendly place this is.

What does z forward have to do with anything? This is two dimensions where there is no z axis?

Sorry, I meant Y- I'm working with 3D space on a 2D plane, so I keep getting them mixed up.

Either way, though, X is always a sideways axis

I don't know what was not sufficient in that solution

Neither do I- that's why I keep saying I'll need to wait until I have more time to work with it.

If you need an angle from a Node2D then use get_angle_to which is in the local coordinates of the node

That sounds promising as well, though it is a bit galling that I spent two days trying to work with this and never came across it in my searches. That's not me casting blame, to clarify.

AThousandShips commented 9 months ago

I'm sorry that you felt that I was unfriendly, I was trying to communicate the situation and the needs, and asking questions to try and help you solve your confusion, there's nothing unfriendly about people expressing their experience and knowledge though and the principles of this engine

I am sorry if my frustration at you being very ambiguous and unhelpful in explaining what it was you needed, and rejecting ideas and suggestions because of that when I was trying to help got out of hand :)

That sounds promising as well, though it is a bit galling that I spent two days trying to work with this and never came across it in my searches.

There I can't help you sorry, it helps to learn basic search methods to get a grip on the documentation, I always trawl around looking everywhere that makes sense when I have a hard time figuring something out

Sorry, I meant Y- I'm working with 3D space on a 2D plane, so I keep getting them mixed up.

Okay... That's not the forward axis in 3 dimensions either though, Godot has -Z as forward, +Y is up, just like it is in 2 dimensions (though Y is flipped), in fact in both 3d and 2d (-1, 0) is left, (1, 0) is right, (0, -1) is up, and (0, 1) is down, as you can see here and here, in 2D the four cardinal directions map to their 3D equivalents (save for the convention that y is flipped)

I'd suggest you take a step back and figure out what it is you are actually needing or asking for, as you have been confused this whole time and essentially made it impossible to help you since you don't seem to know what you are asking for

Have a nice day, good luck figuring out what feature you need

For clarification, this is how the angle works for angle_to_point with Vector2: image

And this is for angle_to: image

And this is for Node2D.get_angle_to: image

AThousandShips commented 9 months ago

If you need help understanding how all of this works, or help figuring out how to make your code work, please turn to the forums as that's the place for support questions and ideas :)

And when you've figured out how these systems work and what you need you can come back if there's still a feature that is missing

LordMcMutton commented 9 months ago

I appreciate the apology, friend!

I do know what I want to suggest, but I almost immediately felt like I was put on the back foot and lost track of my intention.

So, starting the proposal over:

1) Local vs Global is irrelevant, as converting to one or the other is easy enough

2) My own use case is irrelevant (I already got it working with a different, albeit more complicated method. I appreciate your willingness to assist me in that regard, but-- like you said-- that's what the forum is for, and not why I'm here)

3) My own use case did get my perception of general 2D world setups skewed- I caused confusion in that regard, so my apologies.

Now then!

We have Use Case X: image

And Use Case Y: image

I don't really get why Use Case Y is so unusual- The two main setups for a 2D game world that I can think of are Top-Down and Sidescroller and-- in either setup-- Left-To-Right is just as important as Above-To-Below, which are the circumstances I would think are most common.

Am I misunderstanding something in regards to this? As a genuine question, to clarify.

AThousandShips commented 9 months ago

The general convention for coordinate systems is to have the x-axis as the origin of directions, this is reflected in how atan2 has the x-axis be 0 radians, this is simply the standard

Also your X example is backwards, 0 degrees is to the right not the left

But the main question is: Why, what does it matter where the 0 angle is? This method angle_to_point is very specific, it's a certain use case that needs some reference

If you need the angle between two directions you don't use it, you use more appropriate methods such as angle_to

So your use case does matter a lot, this is very unusual and breaks with convention (not just in Godot, but mathematics), see for example this, which also uses the x-axis convention (though it uses a counter-clockwise convention, which is the opposite to Godot as Godot uses graphics coordinates for 2D, as explained here)

So why does the actual angle relative to a point based on this method matter? Why do you need this method rather than the more appropriate get_angle_to or angle_to which compute angles relative to a given direction?

The actual origin angle doesn't matter, it's just a convention, you should work with your local coordinate spaces instead, so you should probably ask yourself why the specific angle matters

I'd say you are expecting the angle_to_point to do things it's not designed for, and should use other methods instead, like, again angle_to with some forward direction, or just in the local space of the Node2D

So unless you provide some specific reasons for why you would actually need this convention (assuming corrections to your illustrations as the x-axis one is flipped, and both use the wrong winding, they should be clockwise), I still don't see why this is needed, and I think you should look at what it is you are actually needing and wanting to do, and consider that you are approaching it from the wrong direction :)

aaronfranke commented 9 months ago

@AThousandShips In Godot, Y is down in 2D. -Y is up.

AThousandShips commented 9 months ago

Yes, clarified the difference between the visual direction above :) but forgot the vector signs for the 2D case

LordMcMutton commented 9 months ago

The general convention for coordinate systems is to have the x-axis as the origin of directions

Aaronfranke mentioned this as well. My particular issue with that was that, having a very weak grasp on vector math, only allowing the X Axis just seemed like an arbitrary limitation

Also your X example is backwards, 0 degrees is to the right not the left

I don't wanna talk about it (I couldn't be arsed to go in and experiment to see which way was which)

But the main question is: Why, what does it matter where the 0 angle is? This method angle_to_point is very specific, it's a certain use case that needs some reference

Mainly, the intent behind the suggestion is to allow both of the use cases I'd mentioned previously- at the moment, it can only be used for Front-To-Back use cases (Is the Target In Front/Above, or Behind/Underneath the Point?), while the addition of a second Axis option would allow for Right-To-Left (Which side of this Point is the Target on?), and could be used based on the needs of the code.

To give very specific examples:

-A sidescroller is only able to use it for checking if the Target is Above or Below the Point, when being able to see if something is In Front or Behind the Target would also be useful

-A top-down game is only able to use it for checking if the Target is In Front or Behind the Point, when being able to see if something is To The Left or To The Right of the Target would also be useful

THAT SAID

as far as I can tell, using Vector2.orthogonal() achieves the desired effect

_Node2D.get_angleto sounds like another solution (I never came across that one, as I didn't expect there to be angle methods in that class, though searching never brought it up, either)

_Vector2.angleto feels very strange to me- I can't think of the use case for getting the angle in relation to an arbitrary point in space unrelated to the two inputs

I think this topic is well covered at this point- as plenty of alternative solutions have been mentioned here, I think we can close the thread as the suggestion is unneeded.

Unless anybody else has anything to add?