Search Unity

Understanding Clamping Rotation

Discussion in 'Scripting' started by Mergster, Dec 6, 2017.

  1. Mergster

    Mergster

    Joined:
    Dec 8, 2016
    Posts:
    10
    Hello! I'm trying to clamp only my x rotation between -90 and 90 degrees using:

    private float xRotation = 0.0f;

    void Update()
    {
    xRotation = Mathf.Clamp(xRotation, -90, 90);
    transform.eulerAngles = new Vector3(xRotation, 0.0f, 0.0f);
    }


    However, the result of this is that my character can only rotate -1 to 1 on all axis.
    I don't understand why this is working like that.


    Iv'e been looking through all code samples and trying things for 2 hours now. :(
    Any help is very much appreciated :)
     
  2. StarManta

    StarManta

    Joined:
    Oct 23, 2006
    Posts:
    8,775
    When you set the rotation to that value, it's going to completely overwrite your Y and Z values. So those two are effectively being "clamped" at 0.

    I don't see how you're ever changing the value of xRotation, but unless there's other code that affects that value, you're probably also setting that to 0. If you ever see values other than 0 in any of your rotation values, I strongly suspect the only reason is because whatever Update is rotating your thing, is happening after this code sets everything to 0... because this code definitely sets everything to 0.

    Trying to clamp rotation is not as simple as it sounds, mostly because Euler angles are terrible. (Yes, it's a long article, but read the whole thing - it's important.) It's not possible to simply (and reliably) clamp the Euler angles to specific values because any given rotation has multiple valid Euler angle equivalents. In order to properly help you determine how to accomplish your clamping goal, I'd need to see more context. If, for example, you're trying to clamp a viewing angle that's being moved by mouse movement, you'll want to use the mouse movement to modify something like your xRotation variable, and then do the same for a yRotation variable - those movements would have to affect those variables directly, you cannot get those variables from the transform's rotation value.
     
  3. Mergster

    Mergster

    Joined:
    Dec 8, 2016
    Posts:
    10
    Oh, ok. I'll check out your article.

    I'm just moving the character by the character controller. I'm trying to accomplish smooth moving by the arrow keys with rotation that follows the player's direction along with a force always pushing the player forward. Also I want the player to slow down when they turn.
    In short, I'm trying to accomplish a moving system as in Mario Odyssey's Bullet Bill (
    )

    That is all pretty much accomplished in my script


    public class PlayerController : MonoBehaviour {

    public float speed = 6.0F;
    public float baseSpeed;
    public float rotateSpeed = 3.0F;
    private Vector3 moveDirection = Vector3.zero;

    private float rotatingStart;
    private float rotatingUpdate;

    void Update()
    {

    //make speed stay above 50
    if (speed < 50) {
    speed = 50;
    }

    //check if player is rotating along y and adjust speed
    rotatingStart = transform.rotation.y;

    if (rotatingStart != rotatingUpdate) {
    speed -= 5;
    rotatingUpdate = rotatingStart;
    }
    else {
    if (speed < baseSpeed) {
    speed++;
    }
    }

    //move player

    CharacterController controller = GetComponent<CharacterController>();

    transform.Translate(Vector3.forward * speed * Time.deltaTime);

    moveDirection = new Vector3(Input.GetAxis("Horizontal"), Input.GetAxis("Vertical" ), 0);
    moveDirection = transform.TransformDirection(moveDirection);
    controller.Move(moveDirection * speed * Time.deltaTime);

    //Rotate Player
    transform.Rotate(-Input.GetAxis("Vertical"), Input.GetAxis("Horizontal"), 0);


    }
    }


    It's just that when the player rotates 'up' along the x axis, he will be able to flip a full circle and as a result, he will become wonky which is why I wish to restrict rotation on x.

    I hope I'm being clear ^^;
     
    Last edited: Dec 6, 2017
  4. methos5k

    methos5k

    Joined:
    Aug 3, 2015
    Posts:
    8,712
    I want to guess that you mean limiting the camera and not the player?
    If you keep track of a variable, that you adjust based on input, you can clamp that 1 variable (it sounds like you only want one), and then apply them together..
    Code (csharp):
    1.  
    2. float rotationX = 0;
    3. float rotationY = 0;
    4. // you might also have some rotation speed variable
    5. void Update() {
    6.    rotationX += Input.GetAxis("Vertical") * Time.deltaTime;
    7.    rotationX = Mathf.Clamp(rotationX, minRotationX, maxRotationX);
    8.    rotationY += Input.GetAxis("Horizontal" * Time.deltaTime;
    9.    transform.rotation = Quaternion.Euler(rotationX, rotationY, 0);
    10.  }
    11.  
     
    kononi likes this.
  5. Mergster

    Mergster

    Joined:
    Dec 8, 2016
    Posts:
    10
    I'm trying to limit the player.

    I gave your script a try and my character's rotation bounces back to zero.

    I kinda just want to to stay based on the player's input between two values ^^;
     
    Last edited: Dec 6, 2017
  6. methos5k

    methos5k

    Joined:
    Aug 3, 2015
    Posts:
    8,712
    Okay, the player.. um.. Did you add the min and max rotation & maybe some speed? Currently it's probably very slow.
     
  7. Mergster

    Mergster

    Joined:
    Dec 8, 2016
    Posts:
    10
    Yes, I added a ton of speed.
    The way that's acting for me is that it always wants to be neutral. So whenever the player stops feeding it input, the values return to 0.
     
  8. methos5k

    methos5k

    Joined:
    Aug 3, 2015
    Posts:
    8,712
    Can you paste just the part you tried here?
     
  9. Mergster

    Mergster

    Joined:
    Dec 8, 2016
    Posts:
    10
    Code (CSharp):
    1. float rotationX = 0;
    2.     float rotationY = 0;
    3.  
    4.     float minRotationX = -9;
    5.     float maxRotationX = 9;
    6.  
    7.  
    8.         void Update()
    9.         {
    10.  
    11.         rotationX += Input.GetAxis("Vertical") * rotateSpeed * Time.deltaTime;
    12.         rotationX = Mathf.Clamp(rotationX, minRotationX, maxRotationX);
    13.         rotationY = transform.rotation.y;
    14.         transform.rotation = Quaternion.Euler(rotationX, rotationY, 0);
    15.  
     
  10. methos5k

    methos5k

    Joined:
    Aug 3, 2015
    Posts:
    8,712
    hm.. So I copied exactly what you pasted here into a script, which I placed on a cube.. it's working perfectly for me.
    Perhaps paste your full Update, if maybe there is other stuff interfering? :)
     
  11. Mergster

    Mergster

    Joined:
    Dec 8, 2016
    Posts:
    10
    I'm not sure...This is my entire script

    Code (CSharp):
    1. using System.Collections;
    2. using System.Collections.Generic;
    3. using UnityEngine;
    4.  
    5. public class PlayerController : MonoBehaviour {
    6.  
    7.     public float speed = 6.0F;
    8.     public float baseSpeed;
    9.     public float rotateSpeed = 3.0F;
    10.     private Vector3 moveDirection = Vector3.zero;
    11.  
    12.     private float rotatingStart;
    13.     private float rotatingUpdate;
    14.  
    15.     float rotationX = 0;
    16.     float rotationY = 0;
    17.  
    18.     float minRotationX = -9;
    19.     float maxRotationX = 9;
    20.  
    21.  
    22.         void Update()
    23.         {
    24.  
    25.         rotationX += Input.GetAxis("Vertical") * rotateSpeed * Time.deltaTime;
    26.         rotationX = Mathf.Clamp(rotationX, minRotationX, maxRotationX);
    27.         rotationY = transform.rotation.y;
    28.         transform.rotation = Quaternion.Euler(rotationX, rotationY, 0);
    29.  
    30.    
    31.  
    32.         //make speed stay above 50
    33.         if (speed < 70) {
    34.             speed = 70;
    35.         }
    36.  
    37.         //check if player is rotating along y and adjust speed
    38.         rotatingStart = transform.rotation.y;
    39.  
    40.         if (rotatingStart != rotatingUpdate) {
    41.             speed -= 3;
    42.             rotatingUpdate = rotatingStart;
    43.         }
    44.         else {
    45.             if (speed < baseSpeed) {
    46.                 speed++;
    47.             }
    48.         }
    49.  
    50.             //move player
    51.            
    52.             CharacterController controller = GetComponent<CharacterController>();
    53.            
    54.             transform.Translate(Vector3.forward * speed * Time.deltaTime);
    55.  
    56.             moveDirection = new Vector3(Input.GetAxis("Horizontal"), Input.GetAxis("Vertical" ), 0);
    57.             moveDirection = transform.TransformDirection(moveDirection);
    58.             controller.Move(moveDirection * speed * Time.deltaTime);
    59.  
    60.             //Rotate Player
    61.         transform.Rotate(-Input.GetAxis("Vertical")* rotateSpeed, Input.GetAxis("Horizontal") * rotateSpeed, 0);
    62.  
    63.  
    64.         }
    65.  
    66.  
    67.  
    68.     }
    69.    
    70.  
     
  12. methos5k

    methos5k

    Joined:
    Aug 3, 2015
    Posts:
    8,712
    Well, sure you still have your old rotate code at the bottom there :)

    Just change the rotationY in the snippet I wrote you to be what it was originally...(this):
    Code (csharp):
    1.  rotationY += Input.GetAxis("Horizontal" * Time.deltaTime * rotateSpeed; // added speed
    then, comment out your rotate at the bottom & see if it works ;)
     
  13. Mergster

    Mergster

    Joined:
    Dec 8, 2016
    Posts:
    10
    Aww, I can't believe I forgot to do that :rolleyes:

    Thank you so so much, it works great now! :D:D:D:D

    For anyone else reading this who may have my problem/or want my movement system, here's the complete code:

    Code (CSharp):
    1. using System.Collections;
    2. using System.Collections.Generic;
    3. using UnityEngine;
    4.  
    5. public class PlayerController : MonoBehaviour {
    6.  
    7.     public float speed = 6.0F;
    8.     public float baseSpeed;
    9.     public float rotateSpeed = 3.0F;
    10.     private Vector3 moveDirection = Vector3.zero;
    11.  
    12.     private float rotatingStart;
    13.     private float rotatingUpdate;
    14.  
    15.     float rotationX = 0;
    16.     float rotationY = 0;
    17.  
    18.     float minRotationX = -45;
    19.     float maxRotationX = 45;
    20.  
    21.  
    22.         void Update()
    23.         {
    24.  
    25.         rotationX += -Input.GetAxis("Vertical") * rotateSpeed * Time.deltaTime;
    26.         rotationX = Mathf.Clamp(rotationX, minRotationX, maxRotationX);
    27.         rotationY += Input.GetAxis("Horizontal") * Time.deltaTime * rotateSpeed; // added speed
    28.         transform.rotation = Quaternion.Euler(rotationX, rotationY, 0);
    29.  
    30.  
    31.  
    32.         //make speed stay above 50
    33.         if (speed < 30) {
    34.             speed = 30;
    35.         }
    36.  
    37.         //check if player is rotating along y and adjust speed
    38.         rotatingStart = transform.rotation.y;
    39.  
    40.         if (rotatingStart != rotatingUpdate) {
    41.             speed -= 5;
    42.             rotatingUpdate = rotatingStart;
    43.         }
    44.         else {
    45.             if (speed < baseSpeed) {
    46.                 speed++;
    47.             }
    48.         }
    49.  
    50.             //move player
    51.        
    52.             CharacterController controller = GetComponent<CharacterController>();
    53.        
    54.             transform.Translate(Vector3.forward * speed * Time.deltaTime);
    55.  
    56.             moveDirection = new Vector3(Input.GetAxis("Horizontal"), Input.GetAxis("Vertical" ), 0);
    57.             moveDirection = transform.TransformDirection(moveDirection);
    58.             controller.Move(moveDirection * speed * Time.deltaTime);
    59.  
    60.         }
    61.  
    62.  
    63.  
    64.     }
     
    Last edited: Dec 7, 2017
    Edisyo likes this.
  14. methos5k

    methos5k

    Joined:
    Aug 3, 2015
    Posts:
    8,712
    Cool, I'm glad it's working for you. :)

    Just 1 small note for reference, in case you didn't already know. transform.rotation.y is not a euler angle representation. That is the 'y' component of a quaternion. I often see people confusing the two when getting/setting (did it too when I started).

    Enjoy your game :)
     
  15. Mergster

    Mergster

    Joined:
    Dec 8, 2016
    Posts:
    10
    I'll keep that in mind!

    Thanks again! :)
     
  16. methos5k

    methos5k

    Joined:
    Aug 3, 2015
    Posts:
    8,712
    No problem :) Take care.
     
    Edisyo likes this.