Control stick map analysis

I'm implementing this map of inputs (from the gamecube title Super Smash Bros. Melee) and translating it into code for my game: The map is depicted using hardware coordinates (the square shape of the map) while the game itself limits the range of inputs to a circle (depicted by the gray circular outline). If a hardware input is outside the range of the circular game input, then it is rounded down. This is what causes the radial patterns. Each colored section is a different output based on the input. The gray square in the center is the deadzone of the stick.

The zones "fsmash", "usmash", and "dsmash" were easy to code in. It was as simple as

if (pos.x > 0.80 || pos.x < -0.80) fsmash
if (pos.y > 0.66) usmash
if (pos.y < -0.66) dsmash


My question is how to incorporate the other 4 zones. It's simple for "jab" as it is in the deadzone so it will be the else condition (when pos.x && pos.y == 0) The inputs go out radially which seems to suggest it follows the same patterns as the larger zones. When inputs are outside of the black circle I have drawn, they could be rounded down then I could simply do..

if (pos.x > 0) ftilt
if (pos.x < 0) jab
if (pos.y > 0) utilt
if (pos.y < 0) dtilt
else jab


However I'm not sure of how I could implement it since the cutoff point for the outer zones was the actual implemented radius of the stick in game. Any help would be appreciated or ask if I need to clarify anything. Thanks!

• If it's radial, you probably want to compute the radius and direction angle/convert to polar coordinates. r = math.sqrt(pos.x^2) + pos.y^2); – Coburn Oct 11 '16 at 18:37
• Something I should add: I'm trying to emulate the engine this map is from and it does not calculate any angles. The radial patterns are from rounding inputs outside the circular radius – Jeff L Oct 11 '16 at 18:39

Note that your four other regions are divided along the diagonal lines where y = ±x, so you can test for these using absolute values:

Assume the following constants:
horizontalCoefficient = 1.0
verticalCoefficient   = 1.0

ftilt:  pos.x > abs(pos.y) * horizontalCoefficient
jab:   -pos.x > abs(pos.y) * horizontalCoefficient
utilt:  pos.y > abs(pos.x) * verticalCoefficient
dtilt: -pos.y > abs(pos.x) * verticalCoefficient


It's up to you how you want to handle values exactly on the cusp where y = ±x. For instance, you could decide that horizontal moves ftilt & jab take precedence over vertical moves by changing their signs to >=

If you want the angle thresholds to be at some angle different than 45-degrees, you can change the constant coefficients used. This doesn't require any trigonometry or angular calculations at runtime - we use trig to figure out the value we want at design time/compile time, and at runtime we just compare ratios.

Let theta be the angle between the horizontal axis and the utilt/ftilt boundary. Then we can calculate our coefficients using the tangent and cotangent trigonometric functions:

verticalCoefficient = tan(theta)
horizontalCoefficient = 1.0/verticalCoefficient

• is it though? it doesn't look like it's projected out at 45 degrees – Jeff L Oct 11 '16 at 19:19
• If you know the exact angle you want, you can adjust this technique to work with it. I can't tell you what angle is appropriate, but I'll edit the answer to demonstrate how to introduce an angular threshold. – DMGregory Oct 11 '16 at 19:22
• It's just strange because the game the map is from doesn't check for stick angles – Jeff L Oct 11 '16 at 19:35
• Not strange at all. An angular threshold can also be expressed as a ratio. So, you can make angular decisions without ever explicitly calculating the angle of a particular input vector. – DMGregory Oct 11 '16 at 19:39