Search Unity

  1. Welcome to the Unity Forums! Please take the time to read our Code of Conduct to familiarize yourself with the forum rules and how to post constructively.
  2. We have updated the language to the Editor Terms based on feedback from our employees and community. Learn more.
    Dismiss Notice
  3. Join us on November 16th, 2023, between 1 pm and 9 pm CET for Ask the Experts Online on Discord and on Unity Discussions.
    Dismiss Notice

Rotate object in random direction

Discussion in 'Scripting' started by omatase, Jun 9, 2016.

  1. omatase

    omatase

    Joined:
    Jul 31, 2014
    Posts:
    159
    I am writing a script to rotate my object in a random direction. My object is a cube that starts facing a single direction and I want it to generally face that same direction forever but I want to apply a random rotation at sporadic intervals to create the illusion that the cube is alive and looking around. Since I want the cube to generally face the same direction over the lifetime of the game object my plan is to start out by storing the cube forward rotation and then pick a random number for Z and Y. I would then add those numbers to the original forward rotation and slowly rotate the cube to the new rotation.

    I'm not really sure how to do this, but here's what I've got so far (slowMove will be called at a random interval to give the appearance of not being predetermined.

    Code (CSharp):
    1.  
    2. private void slowMove()
    3. {
    4.      
    5.     if (_fromOrigin)
    6.     {
    7.         _fromOrigin = false;
    8.  
    9.         // if we're in our origin rotation, then pick a new random rotation
    10.         // x +/- 90 degrees, y +/- 90 degrees and z +/- 90 degrees from our
    11.         // current rotation
    12.         _toRotation = Quaternion.LookRotation(new Vector3(UnityEngine.Random.Range(-90, 90), UnityEngine.Random.Range(-90, 90), UnityEngine.Random.Range(-90, 90)) + _originalRotation.eulerAngles, transform.up);
    13.     }
    14.     else
    15.     {
    16.         // if we're rotated away from our origin rotation, rotate back
    17.         _toRotation = _originalRotation;
    18.     }
    19. }
    20.  
    21. void Update()
    22. {
    23.     if (_toRotation != null)
    24.     {
    25.         // slowly move to our new rotation over time
    26.         transform.rotation = Quaternion.Slerp(transform.rotation, _toRotation.Value, Time.deltaTime * 20f);
    27.  
    28.         // until the difference in angle between our current rotation and
    29.         // our destination rotation is < 1
    30.         if (Quaternion.Angle(transform.rotation, _toRotation.Value) < 1)
    31.         {
    32.             _toRotation = null;
    33.         }
    34.     }
    35. }
    36.  
    Obviously the _toRotation value isn't being calculated correctly because it's not taking into account my current rotation so it can't be an offset like I would like, but I don't really know how to do that.

    Thanks for the help friends!
     
  2. neginfinity

    neginfinity

    Joined:
    Jan 27, 2013
    Posts:
    13,327
    Store:
    Original localRotation.
    Target localRotation.

    And then slerp between those in update.

    Do not slerp between current and desired rotation.

    Code (csharp):
    1.  
    2. float t = 0.0f;
    3. Quaternion targetRotation;
    4. Quaternion originalRotation;
    5. void Start(){
    6.      originalRotation = transform.localRotation;
    7.      t = 0;
    8.      targetRotation = someRandomQuaternionGeneratorFunction();
    9. }
    10.  
    11. Update(){
    12.     t = Mathf.Clamp01(t + Time.deltaTime);
    13.     localRotation = Quaternion.Slerp(originalRrotaiton, targetRotation, t);    
    14. }
    15.  
    ^^Pseudocode, untested.
     
  3. omatase

    omatase

    Joined:
    Jul 31, 2014
    Posts:
    159
    slerping between start and end position made it really jumpy. It would move a bit on each frame, then reset and move the same distance on the next frame. It looks like slerping from current and target is what I want because that's nice and smooth. localRotation, rotation, tried them both and they both have the same look. My big problem is the rotation calculation. I need to calculate a rotation that is no more than +/- 90 degrees from my starting rotation in all three directions (x,y,z). If I use UnityEngine.Random.rotation everything works perfectly, I just need a rotation that is clamped to that 180 degree range in all directions.

    This code works perfectly for what I'm doing other than that clamping.

    Code (CSharp):
    1. private void slowMove()
    2.     {
    3.         if (_fromOrigin)
    4.         {
    5.             _fromOrigin = false;
    6.  
    7.             // if we're in our origin rotation, then pick a new random rotation
    8.             // x +/- 90 degrees, y +/- 90 degrees and z +/- 90 degrees from our
    9.             // current rotation
    10.             _toRotation = UnityEngine.Random.rotation;
    11.         }
    12.         else
    13.         {
    14.             _fromOrigin = true;
    15.  
    16.             // if we're rotated away from our origin rotation, rotate back
    17.             _toRotation = _originalRotation;
    18.         }
    19.     }
    20.  
    21.     void Update()
    22.     {
    23.         if (_toRotation != null)
    24.         {
    25.             // slowly move to our new rotation over time
    26.             transform.rotation = Quaternion.Slerp(transform.rotation, _toRotation.Value, Mathf.Clamp01(Time.deltaTime * 10));
    27.  
    28.             // until the difference in angle between our current rotation and
    29.             // our destination rotation is < 1
    30.             if (Quaternion.Angle(transform.rotation, _toRotation.Value) < 1)
    31.             {
    32.                 _toRotation = null;
    33.             }
    34.         }
    35.     }
     
  4. omatase

    omatase

    Joined:
    Jul 31, 2014
    Posts:
    159
    Hmmmm, I found a method called Quaternion.FromToRotation that is supposed to create a rotation between two vectors which looked promising but didn't really work. I still get a rotation that is beyond the 90 degrees I want to go.

    Code (CSharp):
    1. float rotationVariance = 90;
    2.  
    3. var newRotation = new Vector3(_originalRotation.x, _originalRotation.y + UnityEngine.Random.Range(rotationVariance * -1, rotationVariance), _originalRotation.z + UnityEngine.Random.Range(rotationVariance * -1, rotationVariance));
    4.            
    5. _toRotation = Quaternion.FromToRotation(_originalRotation.eulerAngles, newRotation);
     
  5. omatase

    omatase

    Joined:
    Jul 31, 2014
    Posts:
    159
    Actually, nevermind, that looks like it's sort-of working. although, oddly, whether I have the rotationVariance to 90 or 1 it seems to work exactly the same way...