See title; this is for ZScript, just in case someone asks.
I'd like to find the surface normal of any wall that the player touches, from the side of the wall that they touched. I do understand that LineTrace exists, but I would like to know if there's a pre-existing way to get a normal vector before I try working with it.
Anyone have any pointers?
Re: Obtaining the Surface Normal of a Touched Wall
vector2 get_line_normal_to_player(vector3 player_pos, line test_line)
{
//normal to the vector in 2d case is (vector.-y, vector.x), simple rotation on 90 degree
//works only in 2d case
if(player_pos.xy dot (test_line.delta.-y, test_line.delta.x) >= 0)
return (test_line.delta.-y, test_line.delta.x);
else return (test_line.delta.y, test_line.delta.-x);
}
vector2 get_line_normal_to_player(vector3 player_pos, line test_line)
{
//normal to the vector in 2d case is (vector.-y, vector.x), simple rotation on 90 degree
//works only in 2d case
if(player_pos.xy dot (test_line.delta.-y, test_line.delta.x) >= 0)
return (test_line.delta.-y, test_line.delta.x);
else return (test_line.delta.y, test_line.delta.-x);
}
When I added this to my file with some value tracing code on it and attempted to run, I got an "Unexpected '-'" error. Were the - symbols supposed to be before their respective "test_line"s?
Making that replacement and assuming that this is the intended output, this function doesn't seem to be what I'm looking for. It returns the delta of the line length rather than the normal.
I'll make my own jab at this code and get back here with the results, once I have them.
EDIT: Err... how would I go about getting the endpoints of a line? Planning on using the signed distance of the player's XY position in relation to the line, which is what I need this for.
Re: Obtaining the Surface Normal of a Touched Wall
Posted: Mon Nov 22, 2021 2:56 pm
by Apeirogon
Replace all test_line.delta.-y and test_line.delta.-x to -test_line.delta.y and -test_line.delta.x.
Re: Obtaining the Surface Normal of a Touched Wall
Posted: Mon Nov 22, 2021 6:15 pm
by Pyhrrous
Yeah, it's still not producing the desired effect. Running this function on two walls on opposite sides of a hallway does not produce opposite-signed return values.
Gonna re-ask this again, I suppose: how do I get the start and endpoints of a line found from LineTrace?
Re: Obtaining the Surface Normal of a Touched Wall
Posted: Tue Nov 23, 2021 9:52 am
by Pyhrrous
Okay, I think I found a satisfactory way to do this. If anyone knows there's a more efficient method though, do let me know.
//takes a line, returns the surface normal of the line, depending on if the player's positioned on one side or the other of it
vector2 LineNormal(line test_line)
{
//finding the surface normal vectorof a given line can be broken down into multiple steps:
//- step 1: get the signed distance between the line and point
// (point being the player's XY position)
//- step 2: get the vector of the line
//- step 3: rotate the line by 90 degrees, depending on if the signed
// is positive or negative
//step 1: signed distance line-to-point
//ensure that v1 is the lowest X vertex, v2 is the highest X vertex
//if their x coordinates are equal, v1 is lowest Y, v2 is highest Y
//this is a safeguard; with signed line-to-point, the order of the vertices matters,
//so ensure that it'll be processing any two lines identically regardless of how the mapmaker
//entered them
vector2 vecOne, vecTwo;
if (test_line.v1.p.x < test_line.v2.p.x)
{
vecOne = test_line.v1.p;
vecTwo = test_line.v2.p;
}
else if (test_line.v2.p.x < test_line.v1.p.x)
{
vecOne = test_line.v2.p;
vecTwo = test_line.v1.p;
}
else
{
if (test_line.v1.p.y < test_line.v2.p.y)
{
vecOne = test_line.v1.p;
vecTwo = test_line.v2.p;
}
else
{
vecOne = test_line.v2.p;
vecTwo = test_line.v1.p;
}
}
//signed distance is = ( ax + by + c ) / sqrt(a*a + b*b), where
//a = y1 - y2
//b = x2 - x1
//c = x1 y2 - y1 x2
//sqrt is removed for speed; we are not calculating precise distance
int signedDist = ( (vecOne.y - vecTwo.y)*Pos.x + (vecTwo.x - vecOne.x)*Pos.y + (vecOne.x*vecTwo.y - vecOne.y*vecTwo.x) );
//step 2: unit vector of the line
vector2 lineVec = SafeUnit2((vecTwo.x - vecOne.x, vecTwo.y - vecOne.y));
//step 3: rotate 90 degrees, based on whether the line test returned positive or negative
return RotateVector(lineVec, (signedDist/abs(signedDist)) * 90.0);
}
vector2 SafeUnit2(Vector2 VecToUnit)
{
if(VecToUnit.Length()) { VecToUnit /= VecToUnit.Length(); }
return VecToUnit;
}