- Home /
 
Rigidbody2D velocity in random direction with exceptions
Hey Guys, so I'm trying to recreate Pong and want the ball to spawn in the middle with a desired start speed. The ball should start being faced in a random direction. However it should not face 0-30, 150-210 and 330-360 degrees. How can I do these exceptions? Here's my code:
 using UnityEngine;
 
 public class Ball : MonoBehaviour {
 
     public float startSpeed;
 
     private Rigidbody2D rb;
 
     void Awake () 
     {
         rb = GetComponent<Rigidbody2D> ();
         rb.velocity = Random.onUnitSphere * startSpeed;
     }
 }
 
              Answer by Bunny83 · Jul 21, 2017 at 12:41 PM
One straight forward way is to just calculate a random angle for one side and than randomly choose a side:
 float angle = Random.Range(30f, 150f) + Random.Range(0,2) * 180f;
 
               This angle will be in the range you specifed. To turn it into a direction vector, just use:
 float radAngle = angle * Mathf.Deg2Rad;
 Vector2 dir = new Vector2(Mathf.Cos(radAngle), Mathf.Sin(radAngle));
 
               This of course assumes that 0° is the usual mathematical convention of "right". So 90° is "up", 180° is "left" and 270° is "down".
Note that this approach only works if you have nice symmetric areas. A more general apporach would be to define "valid" areas, each with a $$anonymous$$ and max value. To get a random direction in any of the valid areas you would first sum up the total range if each sub area and just roll a random value in between 0 and that sum. All you have to do is to distribute the value between those areas.
 pubilc struct Range
 {
     public float $$anonymous$$;
     public float max;
     public float range { get { return max - $$anonymous$$; } }
     public Range(float a$$anonymous$$in, float a$$anonymous$$ax)
     {
         $$anonymous$$ = a$$anonymous$$in;
         max = a$$anonymous$$ax;
     }
 }
 
 List<Range> ranges = new List<Range>();
 range.Add(new Range(30, 150)); // range of 120°
 range.Add(new Range(210, 330)); // range of 120°
 float GetRandomAngle(List<Range> aRanges)
 {
     float total = 0;
     foreach(var r in aRanges)
         total += r.range;  
     float v = Random.Range(0, total); // 0 - 240
     foreach(var r in aRanges)
     {
         if (v < r.range)
             return r.$$anonymous$$ + v;
         v -= r.range;
     }
     return aRanges[0].$$anonymous$$;
 }
 
                  Here's a diagram how the final value is deter$$anonymous$$ed:
 //                   v = 163
 // 0            120    |       240
 // ------------------------------
 // |  30 - 150   |  210 - 330   |
 // ------------------------------
 
 v -= 120 --> 43
 
 //    v = 43
 // 0    |       120
 // ---------------
 // |  210 - 330  |
 // ---------------
 
 return 210 + v;  --> 253
 
                  This will work with any non-overlapping ranges. They also doesn't need to be ordered in a particular way. This approach is especially useful when the ranges are not symmetric.
 public static Vector3 GetRandomPointAroundTarget(Vector3 point, float desiredDistance, 
             float $$anonymous$$Angle = 0, float maxAngle = 360)
         {
             // 0 Degrees = Right // 90 Degrees = Up  // 180 Degrees = Left // 270 Degrees = Down
             var angleRad = Random.Range($$anonymous$$Angle, maxAngle) * $$anonymous$$athf.Deg2Rad;
             Vector3 dir = new Vector3($$anonymous$$athf.Cos(angleRad), 0, $$anonymous$$athf.Sin(angleRad)).normalized;
             return (dir * desiredDistance) + point;
         }
 
                  Turned it into an easy to use function, where you can specify the point around which you want the random direction, with a specific distance.
Your answer