Search Unity

How can I rule out object rotation only twice in a row on same direction ?

Discussion in 'Scripting' started by DubiDuboni, Jun 24, 2019.

  1. DubiDuboni

    DubiDuboni

    Joined:
    Feb 5, 2019
    Posts:
    131
    The object is rotating to both directions randomly. Right or left. The range is between 90 and 270.

    But I want to add a rule that if the object rotated for example twice in a row on the left direction or the right direction the next random number should on the other side. So the object can rotate randomly only twice in a row in the same side. If rotated twice on the same side range the next it must be rotating randomly on the other side.

    Code (csharp):
    1.  
    2. using System.Collections;
    3. using System.Collections.Generic;
    4. using UnityEngine;
    5.  
    6. public class RotateRandom : MonoBehaviour
    7. {
    8.    bool noTarget = true;
    9.    Quaternion qTo;
    10.    Quaternion[] qTos;
    11.    float rotateSpeed = 3.0f;
    12.    float timer = 0.0f;
    13.  
    14.    private void Start()
    15.    {
    16.        qTo = Quaternion.Euler(new Vector3(0.0f, Random.Range(90.0f, 270.0f), 0.0f));
    17.        qTos = new Quaternion[100];
    18.        for(int i = 0; i < qTos.Length; i++)
    19.        {
    20.            qTos[i] = Quaternion.Euler(new Vector3(0.0f, Random.Range(90.0f, 270.0f), 0.0f));
    21.        }
    22.    }
    23.  
    24.    private void Update()
    25.    {
    26.  
    27.        timer += Time.deltaTime;
    28.  
    29.        if (noTarget == true)
    30.        {    
    31.            if (timer > 2)
    32.            { // timer resets at 2, allowing .5 s to do the rotating
    33.                qTo = Quaternion.Euler(new Vector3(0.0f, Random.Range(90.0f, 270.0f), 0.0f));
    34.                timer = 0.0f;
    35.            }
    36.            transform.rotation = Quaternion.Slerp(transform.rotation, qTo, Time.deltaTime * rotateSpeed);
    37.        }
    38.    }
    39. }
    40.  
    I tried to add a qTos array and maybe to make that rule already in the Start or using this array to make the rule inside the Update.

    Or maybe to make the rule directly already in the Euler line in the timer :

    Code (csharp):
    1.  
    2. qTo = Quaternion.Euler(new Vector3(0.0f, Random.Range(90.0f, 270.0f), 0.0f));
    3.  
    Then I tried this but it's not working like I wanted it keep just rotating randomly like before :

    Code (csharp):
    1.  
    2. using System.Collections;
    3. using System.Collections.Generic;
    4. using UnityEngine;
    5.  
    6. public class RotateRandom : MonoBehaviour
    7. {
    8.    bool noTarget = true;
    9.    Quaternion qTo;
    10.    float speed = 1.25f;
    11.    float rotateSpeed = 3.0f;
    12.    float timer = 0.0f;
    13.    int counter = 0;
    14.  
    15.    private void Start()
    16.    {
    17.        qTo = Quaternion.Euler(new Vector3(0.0f, Random.Range(90.0f, 270.0f), 0.0f));
    18.    }
    19.  
    20.    private void Update()
    21.    {
    22.  
    23.        timer += Time.deltaTime;
    24.  
    25.        if (noTarget == true)
    26.        {    
    27.            if (timer > 2)
    28.            {
    29.                var rand = Random.Range(90.0f, 270.0f);
    30.                counter += 1;
    31.                if (rand >= 90 && rand <= 180)
    32.                {
    33.                    if(counter == 2)
    34.                    {
    35.                        rand = Random.Range(180.0f, 270.0f);
    36.                        counter = 0;
    37.                    }
    38.                }
    39.  
    40.                if (rand >= 270 && rand >= 180)
    41.                {
    42.                    if (counter == 2)
    43.                    {
    44.                        rand = Random.Range(90.0f, 180.0f);
    45.                    }
    46.                    counter = 0;
    47.                }
    48.  
    49.                qTo = Quaternion.Euler(new Vector3(0.0f, rand, 0.0f));
    50.                timer = 0.0f;
    51.            }
    52.            transform.rotation = Quaternion.Slerp(transform.rotation, qTo, Time.deltaTime * rotateSpeed);
    53.        }
    54.    }
    55. }
    56.  
     
  2. csofranz

    csofranz

    Joined:
    Apr 29, 2017
    Posts:
    1,556
    A pragmatic (though ugly) solution is to use a counter for how many times you have turned to the current direction, and use a direction variable.

    This means that you first randomly determine the angle as an absolute (0..90, half of the total range)
    Then you determine the direction as random bool (false = left, true = right)
    If the direction is the same as last time, increment the counter. If the counter is greater than a threshold (in your case two), force the other direction (direction = not direction)
    If the new direction is different from the last direction, reset the direction counter
    According to the direction, calculate the final turn value and apply it to object.

    -ch
     
    DubiDuboni likes this.
  3. DubiDuboni

    DubiDuboni

    Joined:
    Feb 5, 2019
    Posts:
    131
    Can you show me how to do it in my code ?

    Code (csharp):
    1.  
    2. using System.Collections;
    3. using System.Collections.Generic;
    4. using UnityEngine;
    5.  
    6. public class RotateRandom : MonoBehaviour
    7. {
    8.     bool noTarget = true;
    9.     Quaternion qTo;
    10.     float rotateSpeed = 3.0f;
    11.     float timer = 0.0f;
    12.     int counter = 0;
    13.     bool directions = false;
    14.  
    15.     private void Start()
    16.     {
    17.         qTo = Quaternion.Euler(new Vector3(0.0f, Random.Range(135.0f, 225.0f), 0.0f));
    18.     }
    19.  
    20.     private void Update()
    21.     {
    22.         timer += Time.deltaTime;
    23.  
    24.         if (noTarget == true)
    25.         {    
    26.             if (timer > 2)
    27.             {
    28.                 var rand = Random.Range(135.0f, 225.0f);
    29.                
    30.                 if(rand < 180)
    31.                 {
    32.                     directions = false;
    33.                 }
    34.  
    35.                 if(rand > 180)
    36.                 {
    37.                     counter++;
    38.                     directions = true;
    39.                 }
    40.  
    41.                 qTo = Quaternion.Euler(new Vector3(0.0f, rand, 0.0f));
    42.                
    43.                 timer = 0.0f;
    44.             }
    45.             transform.rotation = Quaternion.Slerp(transform.rotation, qTo, Time.deltaTime * rotateSpeed);
    46.         }
    47.     }
    48. }
    49.  
     
  4. csofranz

    csofranz

    Joined:
    Apr 29, 2017
    Posts:
    1,556
    Ok, here's how this could work. The code isn't tested, and carefully read the final comment about the way you slerp sloppily :)

    Code (CSharp):
    1. using System.Collections;
    2. using System.Collections.Generic;
    3. using UnityEngine;
    4. public class RotateRandom : MonoBehaviour
    5. {
    6.     bool noTarget = true;
    7.     Quaternion qTo;
    8.     float rotateSpeed = 3.0f;
    9.     float timer = 0.0f;
    10.     int sameDirectionCounter = 0;
    11.     public int maxSameDirection = 2;
    12.     bool currentDirection = false; // false = left, true = right, would be more elegant to use an enum
    13.     private void Start()
    14.     {
    15.         qTo = Quaternion.Euler(new Vector3(0.0f, Random.Range(135.0f, 225.0f), 0.0f));
    16.     }
    17.     private void Update()
    18.     {
    19.         timer += Time.deltaTime;
    20.         if (noTarget == true)
    21.         {  
    22.             if (timer > 2)
    23.             {
    24.             // to arrive at a range from 90 to 270 (180 degrees) we
    25.             // take a random range of 0..90, and add or subtract that from
    26.                 // 180. This will then range from 90 to 270.
    27.  
    28.                 float rand = Random.Range(0.0f, 90.0f);
    29.         // now flip a coin for left / right
    30.                 bool newDirection = Random.Range(0.f, 1.0f) < 0.5f;            
    31.  
    32.         // now see if the new direction is the same as the old direction
    33.         if (newDirection == currentDirection) {
    34.             // if we are here, this is the same direction as last time
    35.             // so we need to check how many times this happened already,
    36.             // and if it happened too many times, force the other direction
    37.             sameDirectionCounter += 1;
    38.          
    39.             if (sameDirectionCounter >= maxSameDirection) {
    40.                 // if we are here, we need to flip the direction
    41.                 newDirection = !newDirection; // flip direction
    42.                 samedirectionCounter = 0; // reset count
    43.             }
    44.          
    45.         } else {
    46.            samedirectionCounter = 0;
    47.         }
    48.  
    49.         durrentDirection = newDirection;
    50.  
    51.         // now calculate the effective turn in degrees
    52.         float turnAmount = 180.0f;
    53.         if (newDirection) {
    54.             // right
    55.             turnAmount += rand; // add the random value
    56.         } else {
    57.             // left
    58.             turnamount -= rand; // subtract the random value
    59.         }
    60.                 qTo = Quaternion.Euler(new Vector3(0.0f, rand, 0.0f));
    61.              
    62.                 timer = 0.0f;
    63.             }
    64.          // note that the way you use Slerp here will probably work, but only because you compount two errors :)
    65.          // because the Slerp value should run from 0..1 (yours will alway be 1/FPS), and because the starting
    66.              // slerp value should be constant (yours is constantly changing because you are changing transform.rotation)
    67.             transform.rotation = Quaternion.Slerp(transform.rotation, qTo, Time.deltaTime * rotateSpeed);
    68.         }
    69.     }
    70. }
     
    DubiDuboni likes this.
  5. DubiDuboni

    DubiDuboni

    Joined:
    Feb 5, 2019
    Posts:
    131

    Tried it. And it's not working good enough. In some cases I could count more then twice in a row at the same side.