Im using a RaycastHit to read the angle of a wall from the direction im moving. The issue with that is, that depending on the axis I am moving on, I will get different angles for the same angled wall.
How I determine the wall angle:
var wallAngle = Vector3.SignedAngle(hitNormal, -direction, Vector3.up);
One of the angles will always correspond to the correct angle of the wall, approaching from the other axis will always be the difference between 90 and the angle I need. I can’t find a dynamic way to program this.
Which axis is giving me the correct angle depends on both the axis im moving on, as well as the rotation of the wall.
This is literally the last piece of functionality I need to finish my movement system, so it’s extra frustrating.
I’m confused about what you are trying to calculate. Why is one of the angles in your picture “right” and the other one “wrong”? Is player movement constrained to be axis-aligned? If so, why are you drawing reflections at non-axis-aligned angles? If not, why are you assuming axis-aligned angles of incidence? Or are you trying to get the black text from your picture (40 degrees in world space), in which case why are you using the player direction at all?
If you are trying to make something “bounce” off of a wall (flat surface), the typical physical model for that is angle of incidence = angle of reflection (relative to surface normal). So to calculate the direction of movement after the bounce, you’d reverse the entry vector, calculate the rotation that would turn that into the surface normal, and then apply that rotation twice so that you end up on “the opposite side of” the normal.
If you just need to get the angle of the wall, compare the hit normal to Vector3.up (or whatever your world up is). I’m not sure how the player direction would come into effect.
What do you need to get the angle of the wall for? Can you describe the use case? Perhaps there’s a better way to achieve whatever it is you’re trying to achieve.
Excuse me, I forgot to put the use case. I am trying to get a new movement direction Vector parallel to the wall by rotating the current movement Vector by (wall angle) degrees, so that when i press horizontal/vertical against an angled wall, i move along it. This always works in one direction (the one that’s the “correct” one in the image) and in the other it jitters, as it rotates the direction vector too far.
I used the player direction, because that’s all I found when googling for a way to determine a wall angle from a raycast normal, since I am not looking for a slope, but the angle, like if the wall is diagonal in the world and at which angle. It’s been some years since I learned my maths.
i want to rotate the direction vector of my player movement around the wall angle, so that when pressing either horizontal or vertical, the move direction is along the wall. The way it is now, it will always work smoothly in one axis, but in the opposing one it’ll jitter (basically it will be smooth in the direction that gives the “correct” vector in my picture, and overrotate the vector in the other since that’s always the difference between 90 and the wall angle). Problem with that is, that the rotation of the wall as well as the direction you move towards the wall changes which axis gives the “correct” vector.
If you want to move parallel to the wall (and also parallel to the ground), there are only two possible directions you could end up with: normal+90, or normal-90. The angle of the player is only needed to pick which of those two you’re going to use, and I think the decision algorithm is just to pick whichever one is closer to the original player movement.
(If the wall isn’t perfectly vertical, then project its normal onto a horizontal plane before starting. If the ground isn’t perfectly flat, then things might get more complicated…)
One solution is to dispense with angle calculations entirely and project the movement vector onto the plane defined by the current normal. You can do this using Vector3.ProjectOnPlane, which will work for either 2D or 3D.
var mag = velocity.magnitude;
var dir = Vector3.ProjectOnPlane( velocity, hit.normal );
velocity = dir.normalized * mag;
Either way you go with it, angle or projection, you will also have deal with transition cases to make sure you don’t tunnel into the ground or pop out of it at the bottom and top of slopes.
So I just had the chance to get back on my project and @Madgvox damn! That was actually it, it works perfectly fine like that and was exactly what I needed. I’d kiss you if i could.
As that solved my issue so neatly, I could delete all further calculations with the normal angle apart from the one needed to calculate the dynamic deceleration depending on the wall angle.
For transition cases I already have a slope check that checks whether the contact object is a slope or a (steep and unwalkable) wall, the wall angle check only gets called when the object is an unwalkably steep wall.