Search code examples
c#unity-game-engineobjectinstantiation

Instantiate blocks evenly between two instantiated objects


I'm instantiating obstacles at random X seconds and they fall down the screen. I was looking for a way to instantiate blocks in between the falling obstacles.

Here’s the falling obstacle: GIF Example

IEnumerator ObstacleSpawner()
{
    while (true)
    {
        obstacleSpawn = Random.Range(0.25f, 0.9f);

        yield return new WaitForSeconds(obstacleSpawn);

        GameObject newObstacle = Instantiate(obstacle, new Vector2(-1, 6.5f), Quaternion.identity);
    }
}

And this is what I’m looking for: Example

I’m looking for two things.

  • To have the blocks created if the falling objects are within a certain distance. So in my code, if the obstacleSpawn time is between 0.25 – 0.6 secs, the block wont spawn. After that, the larger the obstacleSpawn time, the more blocks created.

  • To have the block spawn evenly in between the obstacles. If one block is instantiated, its in the middle of the two obstacles. If its two, three and so on, they’re spread out evenly as the above pic shows.

I’ve tried to do this using the following code but obviously with this, it’s instantiating every X secs as I’m a beginner and I honestly don’t know where to start to do this, so would appreciate some help.

IEnumerator BlockSpawner()
{
    while (true)
    {
        yield return new WaitForSeconds(Random.Range(0.25f, 0.9f));

        if (obstacleSpawn >= 0.5f && obstacleSpawn < 0.7f)
        {
            GameObject newBlock = Instantiate(block, new Vector2(Random.Range(-1.65f, 1.65f), 6.5f), Quaternion.identity);
        }
        else if (obstacleSpawn >= 0.7f && obstacleSpawn < 0.8f)
        {
            for (int i = 0; i < 1; i++)
            {
                GameObject go = Instantiate(Instantiate(block));

                go.transform.position = new Vector2(Random.Range(-1.65f, 1.65f), 6.5f);
            }
        }
        else if (obstacleSpawn >= 0.8f && obstacleSpawn < 0.9f)
        {
            for (int i = 0; i < 2; i++)
            {
                GameObject go = Instantiate(Instantiate(block));

                go.transform.position = new Vector2(Random.Range(-1.65f, 1.65f), 6.5f);
            }
        }
        else if (obstacleSpawn >= 0.9f)
        {
            for (int i = 0; i < 3; i++)
            {
                GameObject go = Instantiate(Instantiate(block));

                go.transform.position = new Vector2(Random.Range(-1.65f, 1.65f), 6.5f);
            }
        }
    }
}

Solution

  • Hopefully I am getting your question right please add more detail if I am wrong, but right now your variable "obstacleSpawn" is a random time and then the less this variable is, the closer together the objects are spawning. So you are using time to measure the distance between the objects. This works well but since you want to spawn the objects evenly this makes things a bit more complicated.

    The easiest way is probably to just mess around with the y position of the red blocks while they spawn until you get it right. This would look something like -

    for (int i = 0; i < 2 i++)
    {
        GameObject go = Instantiate(Instantiate(block));
        
        go.transform.position = new Vector2(Random.Range(-1.65f, 1.65f), newObstacle.transform.postition.y + (1 * i));
    }
    

    Now you would need a reference to the newObstacle from your other Coroutine, or you could change the "newObstacle" gameobject/variable's scope to be the entire script (declare the variable at the top and change it in ObstacleSpawner() if that makes sense). Then you can just play around with the 1 in "(1 * i)" to get different spacing.

    I recommend this ^ but I will explain another way too -

    If you really want to use the obstacles spawning, and divide the distance between them to get exact measurements you can, but it'll be more complicated. You would need a reference both to the most recent spawned obstacle (say object1), and the second most recent (say object2), then you could divide their y distance by however many blocks you have, say if you have 3 blocks you want to spawn - ((object1.transform.position.y - object2.transform.position.y) / 3) - this will return the increment of y each block will be, you could then substitute the (1 * 1) from before with this value.

    Edit - More explanation for second way - The easiest way would be to make a list of the obstacles you spawn and then use the last 2 obstacles in the list and calculate the distance between them.

    To add the list, at the top of your script you would add something that would look like

    private List<GameObjects> listOfObstacles;
    

    Then in the ObstacalSpawner() function you would add the gameobject to that list "listOfObjects.Add(newObstacle)", this will create a list of the obstacles from first spawned to last (most recent). Now you can use the way I said before to split them up -

    float distanceBetweenBlocks = ((listOfObjects[listOfObjects.Count - 2].transform.position.y - listOfObjects[listOfObjects.Count - 1].transform.position.y) / 3)
    go.transform.position = new Vector2(Random.Range(-1.65f, 1.65f), listOfObjects[listOfObjects.Count - 2].transform.postition.y + (distanceBetweenBlocks * i));
    

    the "listOfObjects[listOfObjects.Count - 1]" will get you the last item in that list (most recently spawned object) then -1 to the length will get you the second to last, then you just do what I said before, getting the distance between each and dividing it by however many blocks you want (you will want to change the 3 to however many blocks you want)

    Hopefully that clears up how that works and it makes sense. Good Luck!