Search Unity

[Solved] Limit rotation based on input.

Discussion in 'Scripting' started by Keith90, May 10, 2016.

  1. Keith90

    Keith90

    Joined:
    Sep 27, 2013
    Posts:
    116
    Hello,

    I'm currently trying to rotate an object using joystick input and limit it to 180. My goal is that if you hold up the angle is 0, down is 180 and right is 90. That way you can move the joystick to any position from up all the way to down, doing a half-circle motion with the joystick and the object's rotation will match that.

    I know that I can use Mathf.Atan2 to take in the input and use that in the rotation of an object. However, I'm not sure how to limit it so instead of having the object rotate 360, it only rotates 180.

    Does anyone have any information/advice? I greatly appreciate it.

    Thanks,

    - Keith.
     
  2. MD_Reptile

    MD_Reptile

    Joined:
    Jan 19, 2012
    Posts:
    2,664
    If you can get the angle of your joystick, you could just take that and divide it by two right? Like get the angle from the joystick as degrees, then just divide it before applying the rotation.
     
  3. steego

    steego

    Joined:
    Jul 15, 2010
    Posts:
    969
    I'd use -90 to 90 on up and down as well if I were you (if you need the object rotated differently, put it as a child and rotate on the parent object).

    Rotation in 3D space needs 3 angles though, not just 2, so how well this works will depend on what you do.

    Code (csharp):
    1.  
    2. float h = Input.GetAxis("Horizontal") * 90f; // Input is between -1...1, so multiplying with 90 will give us -90...90
    3. float v = Input.GetAxis("Vertical") * 90f;
    4. Quaternion rotation = Quaternion.Euler(v, h, 0f); // Arrange h,v,0f as makes sense for your game
    5. transform.localRotation = rotation;
    6.  
     
    Marcos-Elias likes this.
  4. Keith90

    Keith90

    Joined:
    Sep 27, 2013
    Posts:
    116
    The object is in 2D and I need to rotate only the Z axis so I'm not sure if that'd work.
     
  5. steego

    steego

    Joined:
    Jul 15, 2010
    Posts:
    969
    Ah ok, so you want the object to face the direction that you are pointing the joystick?

    You could probably do it something like this

    Code (csharp):
    1.  
    2. float h = Mathf.Max(0f, Input.GetAxis("Horizontal")); // Only get movement in positive X
    3. float v = Input.GetAxis("Vertical");
    4. if ( !(h == 0f && v == 0f) ) // This won't work if the stick is centered, so do nothing in that case
    5. {
    6.     Vector2 d = new Vector2(h, v);
    7.     transform.up = d.normalized;  // .up or .right, just use a parent object if you need to offset rotation
    8. }
    9.  
     
  6. Keith90

    Keith90

    Joined:
    Sep 27, 2013
    Posts:
    116
    Essentially what Im doing is making the players torso match the angle of the analog stick. So by holding up, he looks up, down is down and right/no hold he faces right. That way when you move the analog in any direction he faces that angle/direction. It gives you 180 aiming angle rather than set angles like you'd find in Metroid/Megaman type games.

    I think I'd have to change it to use angles/rotation but that might just work. I'll be sure to try that when I get home. Thanks. :)
     
  7. steego

    steego

    Joined:
    Jul 15, 2010
    Posts:
    969
    Ah I see. Yeah I'm pretty sure it should work, if you absolutely need angles just use atan2 like you suggested, with the h and v above.
     
  8. Keith90

    Keith90

    Joined:
    Sep 27, 2013
    Posts:
    116
    I tried it. It works on the hips bone, but when I try it on the hips spine, it goes all wonky.

    Basically what I'm trying to accomplish is this:

    The arrow is the angle you hold the joystick. You move the joystick to angle the guy, then you press the attack button to attack in that angle too.

    Player_Rotation.png
     
  9. steego

    steego

    Joined:
    Jul 15, 2010
    Posts:
    969
    You'll have to define wonky.

    If you are trying to distribute the rotation over several joints you will need an inverse kinematic solver.
     
  10. Keith90

    Keith90

    Joined:
    Sep 27, 2013
    Posts:
    116
    That sounds like it will make it more complicated than I expected.

    It rotates the torso around the hips, so it looks like he got cut in half and his upper half rotates around.
     
  11. steego

    steego

    Joined:
    Jul 15, 2010
    Posts:
    969
    If you can get away with rotating two joints, you can probably fake it. It's a bit involved, so I put together an example for you, see the attachment.

    For posterity, here's the script as well

    Code (csharp):
    1.  
    2. using UnityEngine;
    3. using System.Collections;
    4.  
    5. public class AimDude : MonoBehaviour
    6. {
    7.     [SerializeField] private Transform _hips;
    8.     [SerializeField] private Transform _spine;
    9.     [SerializeField] [Range(0f, 1f)] private float _weight = 0.33f;
    10.     void Update()
    11.     {
    12.         float h = Mathf.Max(0f, Input.GetAxis("Horizontal"));
    13.         float v = Input.GetAxis("Vertical");
    14.  
    15.         if (h == 0f && v == 0f)
    16.         {
    17.             _hips.right = Vector3.right;
    18.             _spine.right = Vector3.right;
    19.             return;
    20.         }
    21.  
    22.         float a = Mathf.Atan2(v, h) * Mathf.Rad2Deg;
    23.         Quaternion targetRot = Quaternion.Euler(0f, 0f, a);
    24.         _hips.localRotation = Quaternion.Slerp(Quaternion.identity, targetRot, _weight);
    25.         _spine.localRotation = Quaternion.Slerp(Quaternion.identity, targetRot, (1f - _weight));
    26.     }
    27. }
    28.  
     

    Attached Files:

    Last edited: May 11, 2016
  12. Keith90

    Keith90

    Joined:
    Sep 27, 2013
    Posts:
    116
    Wow. Thanks man.
    Let me try to understand this.

    You get the angle of both v and h, which then you use to set the z axis in the angle of the rotation you want. Since I want it to move forward, you use LookRotation to make sure it faces right? Then you set both bones to rotate using slerp so it moves between the angle it is at to the angle given by the joystick input. The weight I believe is how long it takes to rotate?

    I tried the package. It actually works quite well. All I'd need to do is limit it so it doesn't rotate so far back and so far forward.

    Edit: So I changed it to Mathf.Rad2Deg / 2 which limits the angle so I assume by dividing Mathf.Rad2Deg by a certain number, I can get the limit I want.

    Edit 2: So I seem to have got it working, thanks to you. Here is a small gif. Now the only thing I need to do left is to make the arm bones move in that direction when I press the attack button. I have a feeling it will be similar so I'll give that a shot. :)

    PlayerRotate.gif
     
    Last edited: May 11, 2016
    steego likes this.
  13. steego

    steego

    Joined:
    Jul 15, 2010
    Posts:
    969
    Code (csharp):
    1.  Quaternion fwd = Quaternion.LookRotation(transform.forward);
    is actually just Quaternion.identity, so just use that and save some computation, I updated the script above.

    It's basically just using Quaternion.Slerp to divide the rotation into two fractions. You could do the same with the angle, it's just messier because you have to account for negative angles. The weight is just how much of the rotation should happen in each of the joints, set it to 0 or 1 and only one joint will rotate, at 0.5 they will both rotate half the angle etc.

    The a variable is the actual angle of the rotation, so if you want to limit the rotation you can just clamp this value.

    Your gif looks great. If you change the pivot point of the torso to be closer to the hips, I think you might get an even better result.
     
  14. ericbegue

    ericbegue

    Joined:
    May 31, 2013
    Posts:
    1,353
    It seems you are on your way to build your own IK system. Maybe you could first have a look at the Unity build in IK system first, though I don't know if it fit well with your 2D requirements. More Specifically, have a look at (no pun intended):

    http://docs.unity3d.com/ScriptReference/Animator.SetLookAtPosition.html

    The look-at-IK-system naturally involves the head, neck as well as the torso.
     
  15. Keith90

    Keith90

    Joined:
    Sep 27, 2013
    Posts:
    116
    Once I get home later, I'll be sure to look into this more.

    Thank you everyone for their time and help. :)