[Solved] Limit rotation based on input.

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.

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.

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.

float h = Input.GetAxis("Horizontal") * 90f; // Input is between -1...1, so multiplying with 90 will give us -90...90
float v = Input.GetAxis("Vertical") * 90f;
Quaternion rotation = Quaternion.Euler(v, h, 0f); // Arrange h,v,0f as makes sense for your game
transform.localRotation = rotation;
1 Like

The object is in 2D and I need to rotate only the Z axis so I’m not sure if that’d work.

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

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

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. :slight_smile:

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.

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.

2630016--184852--Player_Rotation.png

You’ll have to define wonky.

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

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.

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

using UnityEngine;
using System.Collections;

public class AimDude : MonoBehaviour
{
    [SerializeField] private Transform _hips;
    [SerializeField] private Transform _spine;
    [SerializeField] [Range(0f, 1f)] private float _weight = 0.33f;
    void Update()
    {
        float h = Mathf.Max(0f, Input.GetAxis("Horizontal"));
        float v = Input.GetAxis("Vertical");

        if (h == 0f && v == 0f)
        {
            _hips.right = Vector3.right;
            _spine.right = Vector3.right;
            return;
        }

        float a = Mathf.Atan2(v, h) * Mathf.Rad2Deg;
        Quaternion targetRot = Quaternion.Euler(0f, 0f, a);
        _hips.localRotation = Quaternion.Slerp(Quaternion.identity, targetRot, _weight);
        _spine.localRotation = Quaternion.Slerp(Quaternion.identity, targetRot, (1f - _weight));
    }
}

2630081–184857–aimdude.unitypackage (10.8 KB)

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. :slight_smile:

2630104--184861--PlayerRotate.gif

1 Like

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.

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):

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

Once I get home later, I’ll be sure to look into this more.

Thank you everyone for their time and help. :slight_smile: