0
\$\begingroup\$

I have this code that generates blocks in random position and it works but some times it generates blocks at the same position ,how can I fix it?

 var dupeobject : GameObject;

 function Start(){
     yield WaitForSeconds(0);
     var position : Vector3 = Vector3(Random.Range(-50,10),Random.Range(-10,5),Random.Range(-100,20));
     Instantiate(dupeobject,position,Quaternion.identity);
     yield WaitForSeconds(0);
     //Destroy(gameObject);
 }
\$\endgroup\$
  • \$\begingroup\$ Simplest solution: track the generated positions and, if you get a duplicate, make a new one. \$\endgroup\$ – 3Dave Oct 25 '16 at 17:32
1
\$\begingroup\$

Because of the nature of Random this will happen occasionally because in a random set there is always a chance of collision. The only real way to mitigate this is to keep a list of positions you've seen before and then ignore and positions that collide. For example:

import System.Collections.Generic;

var dedupeobject : GameObject
var positionsSeen : List.<Vector3>

function Start() {
    yield WaitForSeconds(0);
    var position : Vector3 = Vector3(Random.Range(-50,10),Random.Range(-10,5),Random.Range(-100,20));
    while (positionsSeen.Contains(position) {
        position = Vector3(Random.Range(-50,10),Random.Range(-10,5),Random.Range(-100,20));
   }

   positionsSeen.Add(position)
   Instantiate(dupeobject,position,Quaternion.identity);
   yield WaitForSeconds(0);
}

As an aside, this looks suspiciously like UnityScript, rather than C# (which is what the question is tagged as)

\$\endgroup\$
  • \$\begingroup\$ it's javascript I accedintly tagged it in c#, Thanks a lot!!! \$\endgroup\$ – lyger Oct 25 '16 at 15:51
  • \$\begingroup\$ No problem :-) Just thought I'd point it out in case you hadn't realised :-) \$\endgroup\$ – hobnob Oct 25 '16 at 15:53
  • \$\begingroup\$ Im getting an error "Cannot convert 'null' to 'UnityEngine.Vector3" \$\endgroup\$ – lyger Oct 25 '16 at 15:58
  • \$\begingroup\$ Yup, my bad, position can't be null because a Vector3 is a struct. Sorry, I'm not at a computer with Unity on at the moment so couldn't test. I've made an edit that should work. TBH, I like @Sam 's suggestion of using a Shuffle Bag. It's not a design pattern I'd come across before, and looks like it will solve your issue more efficiently than this will :-) \$\endgroup\$ – hobnob Oct 25 '16 at 16:02
  • \$\begingroup\$ No problem at all :-) \$\endgroup\$ – hobnob Oct 25 '16 at 16:12
4
\$\begingroup\$

In general, if you do not want randoms throwing the same value twice, you implement a Shuffle Bag.

Here's the idea:

  1. Generate every possible outcome and store them in a list.
  2. Remove from list randomly until list runs out.
  3. Repeat.

Unlike what hobnob suggested, this can be done once in Awake() or Start(), is more efficient as you do not need to iterate through the entire list to check if the value has already been used every time you want a new random value, and will allow you to get random values during runtime as well with little overhead.

Here's an example:

//Initialize 2 lists
List<Vector3> shuffleBag = new List<Vector3>();
List<Vector3> shuffleBagBackup;

void Start()
{
    //x,y,z range is define in these nested for loops
    for (int x = -50; x < 10; x++)
    {
        for (int y = -10; y < 5; y++)
        {
            for (int z = -100; z < 20; z++)
            {
                shuffleBag.Add(new Vector3(x, y, z));
            }
        }
    }

    shuffleBagBackup = shuffleBag;
}

And whenever you want to get a new random position within your range, call this:

Vector3 GetRandomPos()
{
    if (shuffleBag.Count == 1)
    {
        Vector3 pos = shuffleBag[0];

        shuffleBag = shuffleBagBackup;

        return pos;
    }

    int index = Random.Range(0, shuffleBag.Count);

    Vector3 position = shuffleBag[index];

    shuffleBag.RemoveAt(index);

    return position;
}

Looking at the code that you've provided, you may also consider making the list a singleton and the GetRandomPos() function static, should you need to access the random positions from multiple objects with this script.

\$\endgroup\$
  • \$\begingroup\$ Great answer but Im new to unity,can you give me an example on how to use it(generatin blocks)?,thanks by the way \$\endgroup\$ – lyger Oct 25 '16 at 16:04
  • \$\begingroup\$ You might have to rewrite my code in UnityScript, but with the two methods that I've provided, you should be able to grab a new position with GetRandomPos() wherever, and whenever you want to generate blocks. If you want even more specifics, you'll have to also provide more information such as the context, as well as your class structures and such. \$\endgroup\$ – eclmist Oct 25 '16 at 16:09

Your Answer

By clicking “Post Your Answer”, you agree to our terms of service, privacy policy and cookie policy

Not the answer you're looking for? Browse other questions tagged or ask your own question.