Rotating a direction Vector according to the already determined angle of a wall (almost working)

Hello,

as part of a custom entity controller for my specific use case i need to make the moving entity move along angled walls. so far i have 90% of it done and working. My approach is as follows:

Basic move function

public void Move(Vector3 direction)
{
    transform.Translate(CanMove(direction) * _speedMultipler * Time.deltaTime);
}

CanMove check

private Vector3 CanMove(Vector3 direction)
{
    //boxcast in movedirection
    if (Physics.BoxCast(_bc.transform.position,
                       new Vector3(((_bc.size.x * 0.95f) / 2), (_bc.size.y / 2), ((_bc.size.z * 0.95f) / 2)),
                       direction,
                       out RaycastHit hit,
                       _bc.transform.rotation,
                       _castDistance
                       ))
    {
        var castHeight = hit.point.y;

        //(debug) draw impact ray
        if (_drawCheckRays) Debug.DrawRay(hit.point, -MaximizeVector(direction, 1f), _rayColor, 0f);

        //check if floor slope or wall
        if (!SlopeCheck(hit, castHeight, direction))
        {
            //check wall angle
            return WallAngle(hit, castHeight, direction);
        }
    }

    return direction.normalized;
}

SlopeCheck() simply checks whether the object hit is a walkable slope or a wall and returns true if the slope is walkable, false if the slope is steeper than _param degrees.

WallAngle

private Vector3 WallAngle(RaycastHit hit, float castHeight, Vector3 direction)
{
    //store angle of the wall
    var hitAngle = Vector3.Angle(hit.normal, -direction);

    Debug.Log($"Wall Angle: {hitAngle}");

    //check if wall angle is movable along, also excluding 0-angles because that's causing bugs
    if (hitAngle <= _maxDiagonalWall && hitAngle > 0.01)
    {
        //rotate movement vector by wall angle
        return ((Quaternion.AngleAxis(hitAngle, Vector3.up) * direction).normalized * 0.5f); //TODO: calculate slowness factor through angle
    }

    return new Vector3();
}

Here the magic happens and it is also where the issue lies. I’m getting the wall angles (which are perfectly fine) and then check if the angled wall should be able to be walked along. All good here, too. However, during the rotation of the vector according to the wall angle the issue arises.

If in the rotation function hitAngle is positive, my character can move along the angled wall horizontally perfectly fine how it should be, but vertically my character gets stuck.

If in the rotation function hitAngle is negative, my character can move along the angled wall vertically perfectly fin, but horizontally gets stuck.

I somehow have to determine the ±-value of hitAngle dynamically, but don’t know how. I know that the hit.normal kind of stores the direction but calculating it from that would probably mess up at 45° angles.

So…you’re looking for the SignedAngle function?

Also note that you’re doing a 3D angle comparison and then applying that angle purely in the 2D plane, so if your direction or hit.normal are not perfectly horizontal you may get weirdness from that.

Yes, I guess that should help the issue.

for my use case I only need to project the angles on the 2D plane, i guess if the wall is steeply sloped as in not walkable, the hit normal would shoot off in 3 dimensions, is there a way to project it onto the 2d plane ? My high school math days are long gone, but can’t I just project the 3d normal onto the ray origin y value to get the angle on the plane?

Edit:// Using SignedAngle() i finally do get working results, so thats good. In order to solve the issue with the hit.normals at walls, which are not 90° steep, I simply calculate with a modified hit.normal, where I set the y-value to 0, which gives me correct 2d-plane angles even if the walls are sloped steeply.

To test how well two vectors are aligned to each other, use Vector3.Dot
Antiparallel vectors will get you -1, congruent +1, and perpendicular 0. This is probably the sign you need if only you come up with a proper vector to test the slope against.

If you consider this image, dot product gives you the factor of the projection magnitude of A onto B, relative to B’s magnitude, but you can compare two unit vectors instead to get a reliable result.

Vector3.ProjectOnPlane

(Don’t forget to normalize the result, if appropriate.)