• Products
  • Solutions
  • Made with Unity
  • Learning
  • Support & Services
  • Community
  • Asset Store
  • Get Unity

UNITY ACCOUNT

You need a Unity Account to shop in the Online and Asset Stores, participate in the Unity Community and manage your license portfolio. Login Create account
  • Blog
  • Forums
  • Answers
  • Evangelists
  • User Groups
  • Beta Program
  • Advisory Panel

Navigation

  • Home
  • Products
  • Solutions
  • Made with Unity
  • Learning
  • Support & Services
  • Community
    • Blog
    • Forums
    • Answers
    • Evangelists
    • User Groups
    • Beta Program
    • Advisory Panel

Unity account

You need a Unity Account to shop in the Online and Asset Stores, participate in the Unity Community and manage your license portfolio. Login Create account

Language

  • Chinese
  • Spanish
  • Japanese
  • Korean
  • Portuguese
  • Ask a question
  • Spaces
    • Default
    • Help Room
    • META
    • Moderators
    • Topics
    • Questions
    • Users
    • Badges
  • Home /
avatar image
2
Question by ryanmillerca · Oct 06, 2014 at 03:06 PM · inputinput.getaxis

How to get overall intensity for each Joystick Axis?

As you all know, Input.GetAxis("Horizontal") and Input.GetAxis("Vertical") each return a value between -1 and 1, which is great for calculating things like walk speed.

I want to get one number from both of these axes combined, between 0 and 1 that is equal to how far the joystick is being pressed in any direction. Essentially, I want a normalized number for two axes.

Mathf.Max(Input.GetAxis("Horizontal"), Input.GetAxis("Vertical")); doesn't work, since any diagonal position will just return 0.5f, 0.5f (doesn't approach 1). Adding each axis together and dividing by two doesn't work for the same reason.

If anyone can help me with an equation that will return 1 for the Joystick pressed all the way in any direction (up/down, left/right and any diagonal), 0.5 for halfway, 0 for not-pressed, etc. I would be grateful. Thanks!

Comment
Add comment
10 |3000 characters needed characters left characters exceeded
▼
  • Viewable by all users
  • Viewable by moderators
  • Viewable by moderators and the original poster
  • Advanced visibility
Viewable by all users

4 Replies

· Add your reply
  • Sort: 
avatar image
6
Best Answer

Answer by robertbu · Oct 06, 2014 at 03:30 PM

Note the axes produce values between -1 an 1, so a upper right diagonal will be (1,1) not (0.5, 0.5). You can do:

  float mag = new Vector2(Input.GetAxi("Horizontal"), Input.GetAxis("Vertical")).magnitude / Mathf.Sqrt(2.0f);

But this will produce a value of 1.0/sqrt(2) (0.707) for left, right, up and down. You only get 1.0 for a full diagonal. You may want this instead:

  float mag = Mathf.Clamp01(new Vector2(Input.GetAxi("Horizontal"), Input.GetAxis("Vertical")).magnitude);
Comment
Add comment · Show 3 · Share
10 |3000 characters needed characters left characters exceeded
▼
  • Viewable by all users
  • Viewable by moderators
  • Viewable by moderators and the original poster
  • Advanced visibility
Viewable by all users
avatar image Anxo · Oct 06, 2014 at 03:40 PM 0
Share

ya das is gut.

avatar image ryanmillerca · Oct 06, 2014 at 05:42 PM 0
Share

Thanks! That works perfectly.

avatar image SpaceManDan · Mar 10, 2021 at 01:37 AM 0
Share

This is stupid old but I thought I'd update this to reflect the fact that sqrmag is faster than mag and you'll get the same result. This is for those going for optimized code.

 float mag = Mathf.Clamp01(new Vector2(Input.GetAxis("Horizontal"), Input.GetAxis("Vertical")).sqrMagnitude)
avatar image
1

Answer by camta005 · Mar 14, 2019 at 05:41 AM

The original idea works you just need to take the absolute value of each axis:

 Mathf.Max(Mathf.Abs(Input.GetAxis("Vertical")), Mathf.Abs(Input.GetAxis("Horizontal")));
Comment
Add comment · Show 1 · Share
10 |3000 characters needed characters left characters exceeded
▼
  • Viewable by all users
  • Viewable by moderators
  • Viewable by moderators and the original poster
  • Advanced visibility
Viewable by all users
avatar image SpaceManDan · Mar 10, 2021 at 01:54 AM 0
Share

This idea will sometimes kick back a number less than 1. For example, at 45 degree, full tilt will spit out 0.76.... I don't think this is the best solution if you want it to represent 1 at full tilt all the way around the axis.

avatar image
0

Answer by ThoseGrapefruits · Oct 25, 2020 at 08:44 PM

In order to do this right, you have to normalise against the maximum possible magnitude for that angle.

If you just clamp the magnitude of the vector to [0, 1], then you only have to move Mathf.Sqrt(magnitude) in any diagonal direction to get the same normalised magnitude as moving magnitude in a horizontal or vertical direction. You run into the opposite problem if you just take the max of the 2 magnitudes, where diagonals are underrepresented instead of overrepresented.

First, the code.

 Vector2 vector = new Vector2(
   Input.GetAxis("Horizontal"),
   Input.GetAxis("Vertical")
 );
 
 float angle = Mathf.Atan2(vector.x, vector.y);
 float maxMagnitude = Mathf.Abs(vector.x) > Mathf.Abs(vector.y)
   ? 1 / Mathf.Sin(angle)
   : 1 / Mathf.Cos(angle);
 float magnitude = abs(vector.magnitude / maxMagnitude);

(The above is untested, as I was looking for a JS solution when I came across this question, and just translated it into Unity C#)

Now, the explanation.

unit circle with enclosing rectangle and 2 sample points

The circle here is the unit circle, and the enclosing square encloses all possible {x,y} values that can be given back by a joystick. The orange and pink dots are 2 example positions of the joystick, which fall into the 2 separate pink and orange tinted parts of the graph respectively. These tinted areas represent the 2 different cases that are handled by the ternary in the code above — more on that later.

The fundamental problem is that the magnitude coming out of the vector is relative to that outer square, but you want the magnitude relative to the unit circle, so that it is always in the range [0, 1]. You also want it to stay proportional no matter where the joystick is, so if the joystick's current values fall outside of the unit circle (e.g. { x: 0.9, y: 0.9 }) the output magnitude should be almost but not quite 100%, because the user isn't actually pushing the joystick full-speed-ahead in that direction.

The solution is pretty straightforward: we take the vector's value and divide it by the maximum possible magnitude at that angle. In the diagram, the vector's value is the solid coloured line, and the maximum possible magnitude is that plus the dotted line extending all the way to the edge of the square.

Like I said before, there are 2 cases. Both are gonna use some trig to calculate the maximum possible lengths, taking advantage of the fact that we're working with right triangles.

"Case 1" (the pink case)

Looking at the diagram, we know θ1 (the angle) and the length of the adjacent side from that corner (that pink 1). We want to find h1, which is the maximum possible magnitude at that angle. Referring to your trigonometric ratios (or wikipedia if you're like me and forgot them all) you'll see that the cosine of an angle θ is the ratio between the adjacent side and the hypotenuse, so we can use that to calculate the length of the hypotenuse. The formula is:

 cos(θ1) = adjacent / hypotenuse = 1 / h1

Solving for h1, we get:

 h1 = 1 / cos(θ1)

"Case 2" (the orange case)

The problem we're solving is exactly the same here: how long is the hypotenuse (`h2` in this case). However, the 1-length side is now opposite θ2 instead of adjacent to it (you can see this side in faint dotted orange). No problem, as sine is the ratio between the opposite and hypotenuse.

 sin(θ2) = opposite / hypotenuse = 1 / h2

again, solving for h2 this time:

 h2 = 1 / sin(θ2)


So, that explains the 2 cases, but how do you differentiate between them? Simple! When the absolute value of x is larger than the absolute value of y, it falls into the first (pink) case. Otherwise, it's the second (orange) case. Again, these are visually split up with the pink and orange tinted areas on the graph. Note that it's important to use the absolute value because, although the examples were both in the positive-positive quadrant, the joystick could be in any of the 4 quadrants, so both x and y could be negative.

Side note: when they are equal, you could use either one and get the same result (approximately, floating point math probably will make it slightly different), as that means you are hitting one of the corners.

Comment
Add comment · Show 2 · Share
10 |3000 characters needed characters left characters exceeded
▼
  • Viewable by all users
  • Viewable by moderators
  • Viewable by moderators and the original poster
  • Advanced visibility
Viewable by all users
avatar image SpaceManDan · Mar 10, 2021 at 01:47 AM 0
Share

Hey, if you're still out there I thought I'd tell you I plugged this in and it's spitting out weird numbers. Not getting the result you explained we should see. Any idea where the math is off? I certainly have no idea as you're way over my head but I'd like to understand so if you are down to dig back into this I'd love to see how this works and get it to spit out the correct result.

avatar image ThoseGrapefruits SpaceManDan · Mar 10, 2021 at 02:45 AM 0
Share

Ah whoops, I tried updating this a while back but didn't realise it got blocked by a captcha. The Mathf.Sin and Mathf.Cos were reversed. It should be fixed now, although full disclaimer, the C# code sample has barely been tested. I was looking for a JS solution when I found this question, so that was the main language I was testing in. Give it a shot now and see if it's giving you what you want! I'm also gonna actually boot up Unity and check the C# solution.

avatar image
0

Answer by tofurocks · May 30 at 06:15 PM

For anybody looking for a solution that works with the new Input System:

     private float getMagnitude(Vector2 vector)
     {
         float x = Mathf.Abs(vector.x);
         float y = Mathf.Abs(vector.y);
         float xSq = x * x;
         float ySq = y * y;
         return Mathf.Sqrt(xSq + ySq);
     }
Comment
Add comment · Share
10 |3000 characters needed characters left characters exceeded
▼
  • Viewable by all users
  • Viewable by moderators
  • Viewable by moderators and the original poster
  • Advanced visibility
Viewable by all users

Your answer

Hint: You can notify a user about this post by typing @username

Up to 2 attachments (including images) can be used with a maximum of 524.3 kB each and 1.0 MB total.

Follow this Question

Answers Answers and Comments

34 People are following this question.

avatar image avatar image avatar image avatar image avatar image avatar image avatar image avatar image avatar image avatar image avatar image avatar image avatar image avatar image avatar image avatar image avatar image avatar image avatar image avatar image avatar image avatar image avatar image avatar image avatar image avatar image avatar image avatar image avatar image avatar image avatar image avatar image avatar image avatar image

Related Questions

`Input' does not contain a definition for `GetAxis' 2 Answers

Input.GetAxis("Vertical") on touch devices. 2 Answers

Is it possible to work around Input.getAxis always returning 0 after scene loads? 4 Answers

Game doesn't recognize X-axis input from XBox 360 controller 1 Answer

S, D, and C keys not working together 1 Answer


Enterprise
Social Q&A

Social
Subscribe on YouTube social-youtube Follow on LinkedIn social-linkedin Follow on Twitter social-twitter Follow on Facebook social-facebook Follow on Instagram social-instagram

Footer

  • Purchase
    • Products
    • Subscription
    • Asset Store
    • Unity Gear
    • Resellers
  • Education
    • Students
    • Educators
    • Certification
    • Learn
    • Center of Excellence
  • Download
    • Unity
    • Beta Program
  • Unity Labs
    • Labs
    • Publications
  • Resources
    • Learn platform
    • Community
    • Documentation
    • Unity QA
    • FAQ
    • Services Status
    • Connect
  • About Unity
    • About Us
    • Blog
    • Events
    • Careers
    • Contact
    • Press
    • Partners
    • Affiliates
    • Security
Copyright © 2020 Unity Technologies
  • Legal
  • Privacy Policy
  • Cookies
  • Do Not Sell My Personal Information
  • Cookies Settings
"Unity", Unity logos, and other Unity trademarks are trademarks or registered trademarks of Unity Technologies or its affiliates in the U.S. and elsewhere (more info here). Other names or brands are trademarks of their respective owners.
  • Anonymous
  • Sign in
  • Create
  • Ask a question
  • Spaces
  • Default
  • Help Room
  • META
  • Moderators
  • Explore
  • Topics
  • Questions
  • Users
  • Badges