This might be a pointless post at this point, but I’ll chime in.
First, there is nothing wrong with Xbox controller input, and second, square movement does not mean it is working well. The thumbstick is bound in a circular plastic ring, and the input when done without any extra bounding would result in a circular shape. Why it’s making a square is because a maximum range has been set for each axis(what 1 is- normal XInput range is ~32737) and anything over that is reduced to one. This maximum is set below the limit the plastic bounds create(to guarantee that the stick will output 100% throw), but that means that the stick can lean beyond that maximum(36000 or so in XInput).
The blue line is the full, circular range the stick can access if let register until the plastic ring, and the red box is the bounding area set as default(not sure if you can change that). Since the stick can lean over the red line for quite a bit of its circumference, those values are reduced to 1 on the axes, which create the sides of the square. The corners are rounded because the outer limit of the plastic ring goes within the red bound and limits input first.
The green circle is what you want to set up. A circular bounding area within the area set by the engine.
Doing that isn’t too hard mathematically, but it will take a few steps. It’s a little more wonky with visual scripting, but it’s straightforward enough.
For this to work fully, you might need to change the default deadzones in the axis config(below the axis events in input settings). The deadzones are set up by axis, creating a square deadzone which can affect full circular movement since it zeros a lot of the axis input. Reduce the deadzone to zero and you can create them in the code.
DanaFo mentioned the Atan2(degrees) which is the main thing you’ll want to use( Atan gives the reference angle, so avoid that for this). By using Atan2(stickY, stickX) you can get the angle.
To make this somewhat short, we basically want:
magnitude = sqrt[ pow((stickX - 0), 2) + pow((stickY - 0), 2) ]; if(magnitude>1){ magnitude = 1;}
This finds the distance from the center of the stick. Since the stick can overlean the normal max, setting it to 1 will normalize it.
activeRange = (magnitude - deadzone)/(1 - deadzone); if(activeRange<0){activeRange = 0;).
Rescales values so a linear 0-1 range of values occur after the deadzone. If it goes below 0, motion will be negative. Exactly like the default settings, but this creates a circular deadzone.
angle = Atan( stickY/stickX );
Finds the angle. Important for the next step.
newStickX = cos(angle);
newStickY = sin(angle);
Doing this both ensures that the stick output will point in the correct direction the stick is facing, but also normalizes the vector distance to make a perfect circle.
newStickX = newstickXactiveRange;
newStickY = newStickYactiveRange;
This will let the stick move with circular motion and give you a single circular deadzone and 0-1 range to work with. This should meet your goal.
It’s a little messy, but you can see it applied here. I was setting up an aiming system so you can ignore the accelCurve and sensitivity stuff. The newStick values should work just the way you expect at this point.