Search Unity

Random point within circle with Min/Max radius

Discussion in 'Scripting' started by MeekoSoup, Dec 13, 2018.

  1. MeekoSoup

    MeekoSoup

    Joined:
    Apr 11, 2015
    Posts:
    13
    I know this question has been asked before, but most of the time it is for 3D, and they don't take into account the center point.

    I have an enemy that burrows and unburrows at a point around the player. I don't want it to unburrow too close, or too far away.

    Currently I am using (essentially):
    Code (CSharp):
    1. animator.transform.position = Random.insideUnitCircle * radius + player.transform.position;
     
    Hollow_Spy likes this.
  2. Thimble2600

    Thimble2600

    Joined:
    Nov 27, 2015
    Posts:
    165
    haii

    Give this a whirl

    Code (CSharp):
    1.         if ( Vector2.Distance(a, b) < rangeMin && Vector2.Distance(a, b) > maxRange )
    2.         {
    3.                 TryAgain();
    4.         }
    Or use
    Vector2.Distance
    to find which the enemy is closest to them move them in that direction

    On second thoughts what I said is arguably terrible, what you're trying to do is much smarter.
     
    Hollow_Spy likes this.
  3. MeekoSoup

    MeekoSoup

    Joined:
    Apr 11, 2015
    Posts:
    13
    Thanks for the quick reply.
    I would prefer as little rerolling as possible, as that can cause a lot of unnecessary lag on the system. I'm going for a more mathematical solution.
     
    Hollow_Spy likes this.
  4. Thimble2600

    Thimble2600

    Joined:
    Nov 27, 2015
    Posts:
    165
    Hollow_Spy likes this.
  5. MeekoSoup

    MeekoSoup

    Joined:
    Apr 11, 2015
    Posts:
    13
    Again, I thank you for your reply, but I believe I came across this before, and found it to be far more complicated than I needed. Also, I was looking for a more 2D solution. Sorry for being difficult.
     
    Hollow_Spy likes this.
  6. MeekoSoup

    MeekoSoup

    Joined:
    Apr 11, 2015
    Posts:
    13
    Hollow_Spy likes this.
  7. MeekoSoup

    MeekoSoup

    Joined:
    Apr 11, 2015
    Posts:
    13
    Hollow_Spy and Markstam291 like this.
  8. Emolk

    Emolk

    Joined:
    Feb 11, 2014
    Posts:
    241
    I couldn't find an easy solution so i made one myself, for anyone stumbling upon this:

    Code (CSharp):
    1. public Vector2 RandomPointInAnnulus(Vector2 origin, float minRadius, float maxRadius){
    2.  
    3.         var randomDirection = (Random.insideUnitCircle * origin).normalized;
    4.  
    5.         var randomDistance = Random.Range(minRadius, maxRadius);
    6.  
    7.         var point = origin + randomDirection * randomDistance;
    8.  
    9.         return point;
    10. }






    TestClass

    Code (CSharp):
    1. using System.Collections;
    2. using System.Collections.Generic;
    3. using UnityEngine;
    4.  
    5. public class RandomAnnul : MonoBehaviour
    6. {
    7.     public float minRadius = 3f;
    8.     public float maxRadius = 7f;
    9.     public int pointAmount = 100;
    10.     public GameObject prefab;
    11.     void Start()
    12.     {
    13.         var origin = transform.position;
    14.  
    15.         for (int i = 0; i < pointAmount; i++)
    16.         {
    17.             var pointToSpawnAt = RandomPointInAnnulus(origin, minRadius, maxRadius);
    18.  
    19.             Instantiate(prefab, pointToSpawnAt, prefab.transform.rotation);
    20.         }
    21.  
    22.     }
    23.  
    24.     public Vector2 RandomPointInAnnulus(Vector2 origin, float minRadius, float maxRadius){
    25.  
    26.         var randomDirection = (Random.insideUnitCircle * origin).normalized;
    27.  
    28.         var randomDistance = Random.Range(minRadius, maxRadius);
    29.  
    30.         var point = origin + randomDirection * randomDistance;
    31.  
    32.         return point;
    33.     }
    34. }
    35.  
     
    Last edited: Jun 9, 2020
    eliteforcevn, blisz, eterlan and 10 others like this.
  9. Quassanex

    Quassanex

    Joined:
    Jan 18, 2015
    Posts:
    2
    Just do
    Code (CSharp):
    1. Vector2 point = Random.insideUnitCircle.Normalized * Random.Range(MinRadius, MaxRadius);
     
    Karwoch, Hollow_Spy, Banaaani and 8 others like this.
  10. n8dev_yt

    n8dev_yt

    Joined:
    Apr 14, 2020
    Posts:
    22
    I find it really silly that I did something like this about a month ago, forgot about it, and spent a couple hours trying to do something similar in my current project
    smh
    thank you for this
     
  11. EDevJogos

    EDevJogos

    Joined:
    Jul 24, 2014
    Posts:
    75
    Worked like a charm, thank you!
     
    Hollow_Spy likes this.
  12. Majadroid

    Majadroid

    Joined:
    Jul 9, 2019
    Posts:
    1
    I think, what you need is this:
    Code (CSharp):
    1. private Vector3 GetRandomSpawnPosition()
    2.     {
    3.         Vector3 randomPosition = (Vector3)Random.insideUnitCircle;
    4.         return transform.position + randomPosition.normalized * spawnRadiusMin + randomPosition * (spawnRadiusMax - spawnRadiusMin);
    5.     }
     
  13. jvo3dc

    jvo3dc

    Joined:
    Oct 11, 2013
    Posts:
    1,520
    I'd say that none of these solutions offer a random position in an annulus that is uniformly distributed and gives an answer in one pass. (So without rejecting and trying again.)

    The solution of Random.insideUnitCircle and then rejecting in the inner circle is uniformly distributed, but not in one pass. All others break the uniform distribution.

    All in all the math is not that difficult. You'd start with a random direction and distance, but you'll have to adjust the distance to make it uniform. (Else if the minimum radius is 1 and the maximum radius is 2 for example, the points will be twice as dense at the minimum.)
    Code (csharp):
    1.  
    2. public Vector2 RandomPointInAnnulus(Vector2 origin, float minRadius, float maxRadius) {
    3.     Vector2 randomDirection = Random.insideUnitCircle.normalized; // There are more efficient ways, but well
    4.     float minRadius2 = minRadius * minRadius;
    5.     float maxRadius2 = maxRadius * maxRadius;
    6.     float randomDistance = Mathf.Sqrt(Random.value * (maxRadius2 - minRadius2) + minRadius2);
    7.     return origin + randomDirection * randomDistance;
    8. }
    9.  
    It might be a bit too puristic for the goal here, but this returns a random point in an annulus with uniform distribution in one pass. The other options above simply don't.
     
  14. rebichini19

    rebichini19

    Joined:
    Aug 8, 2019
    Posts:
    2

    You are a genius! After 1 hour this is the only solution that works correctly