I currently use the following snippet to spawn my mushrooms (level-ups) for a 2D sidescroller game.
void Update()
{
if (stopping == false)
{
transform.Translate(-Vector3.right * speed * Time.deltaTime);
mushroom = GameObject.FindGameObjectWithTag("Mushroom");
}
if (mushroom != null)
{
while (stopping == false && count < 6)
{
var position = new Vector2(Random.Range(-25f, 120f), Random.Range(-20f, 30f));
Instantiate(mushroom, position, Quaternion.identity);
count++;
}
}
}
The problem I have is the x position being way too close to eachother. sometimes they even overlap.
I wasn’t able to find a solution so far. really interesting random.range has similar values pretty often !!
my first idea was calculation last_position minus x and if that’s within a certain range I random x again.
this didn’t work out since I only compare the last_position of the last gameobject I created.
but it wouldn’t compare for example loop1 vs loop4
You can create a list of previously instanced positions.
Then check against it to see if your position is too close to any of them. If it isn’t , instantiate your object and add its position to the list.
thanks for your answer again.
I’ve been playing around with different settings and different code additions in the last hour but it seems that didn’t work out. the mushrooms are still too close to eachother.
current code produces an infinite loop too but didn’t know how to implement it the other way round …
void Update()
{
List<float> spawnspots = new List<float>();
if (stopping == false)
{
transform.Translate(-Vector3.right * speed * Time.deltaTime);
mushroom = GameObject.FindGameObjectWithTag("Mushroom");
}
if (mushroom != null)
{
float x, y = 0;
while (stopping == false && count < 6)
{
x = Random.Range(-25f, 100f);
y = Random.Range(-20f, 30f);
var position = new Vector2(x, y);
if (IsTooClose(x, 15, spawnspots) == false)
{
spawnspots.Add(x);
Instantiate(mushroom, position, Quaternion.identity);
count++;
}
else
{
x = Random.Range(-25f, 100f);
}
}
}
}
bool IsTooClose(float x, float minimumDistance, List<float> list)
{
if (list == null)
{
return false;
}
bool tooClose = true;
foreach (var f in list)
{
if (Mathf.Abs(x) > Mathf.Abs(f) + minimumDistance)
{
tooClose = false;
break;
}
}
return tooClose;
}
That’s actually my mistake as well, I submitted the wrong code, then quickly updated it.
The code was wrong because it checked to see if x was far enough from ANY list element (where it should have been checking if it was far enough from ALL of them).
Also, the way to get the number of elements in a list would be “list.Count”, not “list.Length” (as i said, it was untested).
On top of this, you replaced this with (list == null) which is always false, since you create it every update “List spawnspots =new List();”.
But when you’re trying to add the first element, it won’t even go once through the foreach (because the count of the list is 0), so your method will ALWAYS return true. That’s why you were stuck in an infinite loop
Check my previous answer for the updated logic. You also don’t need the else statement (if the IsTooClose returns true).
thanks again for that lecture.
I’m still not used to C# enough.
wasn’t able to test if it’s actually working now since I’m still in an infinite loop due to my count variable not being incremented outside the if statement. but if I do so there are obviously not enough mushrooms
Then generate them “from left to right”.
You need to know the boundaries of your level along the x axis, to make sure they don’t spawn outside.
An example:
Say you want to spawn 4 mushrooms between x[10, 110].
Range delta = max - min = 100
Average distance = range delta / # mushrooms = 25
This would mean we spawn the mushrooms at (10, 35, 60, 85). We don’t want them to be distributed this evenly though.
We could add a random value to them. Now, this random value must not exceed the average distance. Otherwise the first one may spawn behind the second.
rnd = +/- average distance / 2 = +/- 12.5
The second problem would be that they might spawn too close to each other. If the fist random value would be almost the maximum and the next one would be almost the minimum. (35 + 12 and 60 - 12)
To fix this, we make sure that the values are always positive.
rnd = average distance / 2 = 12.5
position = (average distance * mushroom-index) + rnd
In this example the following values would be calculated: #1 x[10-22.5] #2 x[35-47.5] #3 x[60-72.5] #4 x[85-97.5]
thanks for that huge amount of information.
too be honest I’m sitting here with my eyes wide open and try to adapt my code I already posted in my previous comments but math plus me leads to a deadly dosis of frustration
tried to implement it but was stuck again translating algorithms to actual code.
I think I better stick to alegoris answer and try to find a solution for my infinite loop.
edit: okay I at least got rid of the infinite loop switching from a while to an if statement
but the mushrooms are sadly enough still too close to eachother. this really drives me up the wall
edit2: okay I’m too stupid switching from while to if only executes it once (if at all) everytime update is called and I’m creating a new List deleting the old one too. No light at the end of the tunnel
You can fix the infinite loop by just using the method i posted. (IsTooClose)
As I said in my previous post, it has been fixed and should work.
See if it’s different from your method and in what way. You CAN’T have if(list == null) as your initial check, it will not work.
Try and copy the entire method again, see if that fixes it for you.
// Generates the desired amount of mushrooms within set boundaries
// x_min is the position from where mushrooms should start spawning (somewhere after the start of the level)
// x_max is the position after which no more mushromms should spawn (somewhere before the end of the level)
// amount is the desired amount of mushrooms you want to spawn
private void GenerateMushrooms(float x_min, float x_max, int amount) {
if(x_min >= x_max)
throw new AgumentException("x_min must be smaller than x_max");
float rangeDelta = x_max - x_min;
float avg_dist = rangeDelta / amount;
float rnd = UnityEngine.Random.Range(0.0f, avg_dist * 0.5f);
for(int i=0; i<amount; i++) {
float x_pos = (avg_dist * i) + rnd;
// Now create a mushroom using x_pos as position along the x axis here
}
}
You call this function once at the beginning of your level.
thanks for the information.
mhmm well that’s akward. it doesn’t crash at all if I create the mushrooms with the script I posted in the starting thread.