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