Skip to main content

On Sale: GamesAssetsToolsTabletopComics
Indie game storeFree gamesFun gamesHorror games
Game developmentAssetsComics
SalesBundles
Jobs
TagsGame Engines

How to Create Spawn Prefab in Random Location?

A topic by Art Ink Studios created Sep 19, 2021 Views: 616 Replies: 7
Viewing posts 1 to 3

We are creating a 2-D vector assets with a fade-in animation that flash multi-colors. But the tricks is that we tried to create a Unity C# script into having the prefab to spawn 15 times in a different location in front of the Earth to where each prefab would appear 2 seconds and only start appearing for every 20 seconds on the timer of the game. I created an image below of how the assets called the "Vectoroc" asteroids would appear in the game. The question is that how to create a C# script for Unity to spawning a prefab in a different location, but do not spawn in the same location after the last 15 asset that spawn. It will be a big help, and thank you.


Two google searches is all it takes.


In case you don't know how to use Google:

(1 edit)

Thanks, but I have been using google on the subject in the past. But will use the two links for more idea. 

(1 edit) (+1)

Hello! It's been a while since I've visited the forums, so I'm a little rusty.

If I understand correctly, you want to make an element to spawn N times without repeating position. 

Here is a possible solution:

Keep a list of positions already used. 

And when going for spawning a Prefab and selecting the new random position, make the random position generator to avoid those positions already used. A way to do this is by trial and error.

Some code to help you get the idea...


    private List<Vector3> GenerateRandomPositions(Vector2 xRange, Vector2 yRange, Vector2 zRange, int amount)
    {
        List<Vector3> randomPositions = new List<Vector3>();
        for (int i = 0; i < amount; i++)
        {
            Vector3 newRandomPosition = RandomPosition(xRange, yRange, zRange, randomPositions);
            randomPositions.Add(newRandomPosition);
        }
        return randomPositions;
    }
    private Vector3 RandomPosition(Vector2 xRange, Vector2 yRange, Vector2 zRange, List<Vector3> usedPositions)
    {
        Vector3 newRandomPosition;
        do
        {
            newRandomPosition =
                new Vector3(
                    Random.Range(xRange.x, xRange.y),
                    Random.Range(yRange.x, yRange.y),
                    Random.Range(zRange.x, zRange.y));
        } while (usedPositions.Contains(newRandomPosition));
        return newRandomPosition;
    }
    private void ShowLogRandomPositions(List<Vector3> positions)
    {
        string report = string.Empty;
        foreach (var item in positions)
        {
            report += item.ToString() + "\n";
        }
        Debug.Log("ShowLogRandomPositions: " + "\n" + report);
    }
    private void Start()
    {
        List<Vector3> randomPositions =
            GenerateRandomPositions(new Vector2(-2, 2), new Vector2(-2, 2), new Vector2(-2, 2), 15);
        ShowLogRandomPositions(randomPositions);
    }

The next thing from here is to get sure they don't step on each other. For that, you should take care of the size of the objects you're spawning so playing with the allowed positions around area/proximity should do the trick.

If this was what you're trying to reach for, I hope this helps.

If you have any questions, please ask.

Good luck!

(1 edit)

Thanks, I'll give it a shot.

(1 edit)

I finally got the idea random spawn going, but now need help in wanting the spawning prefabs located within a rectangle area. Here are ideas of want I mean from these web links.  how to create a spawn point within shape area for unity - Google Search 

Also here is the random spawn script that I made if needed to apply where for the rectangle script to go to. 

public GameObject objectToSpawn;

    public GameObject parent;

    public int numberToSpawn;

    public int limit = 15;

    public float rate;

    float spawnTimer;

    // Start is called before the first frame update

    void Start()

    {

        spawnTimer = rate;

    }

    void Update()

    {

        if (parent.transform.childCount < limit)

        {

            spawnTimer -= Time.deltaTime;

            if (spawnTimer <= 0f)

            {

                for (int i = 0; i < numberToSpawn; i++)

                {

                    Instantiate(objectToSpawn, new Vector3(this.transform.position.x + GetModifier(), this.transform.position.y + GetModifier())

                        , Quaternion.identity, parent.transform);

                }

                spawnTimer = rate;

            }

        }

    }

    float GetModifier()

    {

        float modifier = Random.Range(-10.5f, 10.5f);

        if (Random.Range(0, 2) > 0)

            return -modifier;

        else

            return modifier;

    }

}

Hello again...

Ok, a few things...

- Your timer tries to work in a way that it will create 'limit' gameobjects every 'rate' seconds, non-stop. And the only condition to stop it is 'parent.transform.childCount < limit'. You can improve this, both the timer mechanic and the condition used. The problem with this condition is working with something that may be used by another script (counting the childs of the objectToSpawn parent node). In other words, an element that it's outside your script's scope.  

That's two things actually.

- GetModifier(). You have set a single range to obtain values from (and in a hardcoded way). This will limit you to a square, in best of cases. And later, you apply a second random generation that will give you a negative value most of the time. So positions will concentrate mostly on one corner of that square.

That's two things again...

Now a little theory. For a rectangle, in your case, the fastest way to define it is by placing two position vectors: (x1, y1) and (x2, y2). If you want to take a new 'X' contained inside the rectangle, take a random value between x1 and x2. The same way with the new 'Y' value. 

Vector2 newPosition = new Vector2(Random.Range(x1,x2), Random.Range(y1,y2));

I imagine you want to try your own solution (I've noticed you're not reusing the code I left for you), and that's a good thing. Trying to find an alternative and possibly better solution. But remember that you will find later yourself with the problem of overlaping positions. What I think it is the original problem you write the post about.

Hope this helps you to find a solution. 

If you need to ask again, do not hesitate.

Cheers!

(1 edit)

Okay, I'll give test, and thank you.