Problems with joystick / controller axes being 1/-1 "way too often"

EDIT: If your controller axes “snap” to 8-directional rotations, make sure the axis sensitivity is set to a “mild” value like 1 and/or that you’re using radial deadzones . Those two seem to be the main issues that make the problem rise. The reply might be useful if your joystick controls make use of the magnitude (how far from the center of the stick you move)

I’m making a 2.5d space shooter, and rather than having a “twin stick” movement I have a “thrust” button and a “turn” thumbstick: wherever you point, the ship turns that way.

I also have mouse-kb input which works well.

I have a “controller snapping” problem on my hands, where the horizontal/vertical axes only have extreme values (either -1 or 1) when the thumbstick is on the edge of its “circle”.

I’ve tried with three pads so far: a generic Logitech, a (severely worn) 360 and a Steam Controller.

I don’t know if this is what exactly is happening, but my best guess is that the axes only have the intermediate values inside a square:
129955-unityaxeshlep.png

Now, this is an extreme representation, but on the edge of the circle it seems very easy to be on the (1,1), (-1,1), etc. inputs compared to… anything else, really. BUT when the stick is approximately inside the square then I can rotate freely.

Just to be sure it’s not a hardware/driver problem, I tried playing Beat Hazard Demo and I was able to move around as I pleased, as close to the edge as I wished.

The “Horizontal” and “Vertical” input axes that I’m using pretty much have the default parameters, and I’m using a radial deadzone, a clamping to the input magnitude and a “square to circle” transformation.

Keep in mind that this snapping problem is present with or without those things.

Is there something I don’t understand about how the input axes work?

These are the hor/ver axes:

This is the relevant code, although I believe it has to do with the axis input itself, but might as well show it:

        //JOYSTICK INPUT
        float h = Input.GetAxisRaw("Horizontal");
        float v = Input.GetAxisRaw("Vertical");
            
        //Transform square axes into circle
        float horin = h * Mathf.Sqrt(1 - 0.5f * h * h);
        float verin = v * Mathf.Sqrt(1 - 0.5f * v * v);

        joyin = (new Vector3(horin, 0.0f, verin));

        //Joystick deadzone and clamping
        if (Mathf.Abs(joyin.magnitude) <= JoystickDeadzone)
            joyin = Vector3.zero;
        else
            joyin = Vector3.ClampMagnitude(joyin, JoystickClamp);

        //MOUSE INPUT
        ...

        bool UsingJoystick = (joyin != Vector3.zero);
        bool UsingMouse = ...

        //Mouse input: project mouse position onto game plane
        if (UsingMouse)
        {
            ...
        }

        //Joystick input: depending on joystick output, turn around
        if (UsingJoystick)
        {
            float r = 256.0f;
            directioninput = r * joyin;
            targetpos = transform.position + directioninput;

        }

        //Boost input
        ...
        //Thrust input
        ...

        //Actually move the ship
        #region
        Vector3 goalpos = transform.position + directioninput;
                    engine.MoveThing(goalpos, thrustinput, boostinput, true);

For reference, engine.MoveThing() simply thrusts and turns the ship towards the desired position.

If your intent is to clamp to a magnitude of 1 when your combined x/y inputs exceed it, then you don’t really need to be able to provide x/y inputs both at values of 1 on a 45° angle. A 45° angle would maximize input to sqrt(2.0) /2 or ~0.707 per axis.


However, if your intent is to have two separate axes, each capable of reaching a value of 1 simultaneously, then the logical problem instead is having a circular "joystick" to provide input in the first place.

Obviously, for any physical controllers, insisting that their analog stick should have their framing circle(s) cut into a square shape would be silly.

Realistically, a meaningful alternative at this point would be mapping a square to a circle. This would result in uneven shifts in input values with certain kinds of movement, but there’s also no real means of avoiding that when deforming the inputs in the first place.