[Beginner question] 2D Time based spawning of objects like weeds or stones/ore

Hi there,

I’m currently working on a topdown 2D game and have a question about spawning stuff like Weeds or rocks after a certain amount of time.

What I’m trying to achieve:

  • Similar to games like Stardew Valley and Forager, I am trying to make a spawner that spawns weeds, rocks, or even trees that the player can interact with (chop them or gather them etc).

  • This would need a timer, and something that checks if the area is empty.

Where I am lost:

So right now I have my tilemap, which is the background. I then want to spawn trees, weeds, and other objects at random which I can cut or collect.

I am just unsure if I need to make a separate grid for this, that checks if the cell is empty, and if it is, it can spawn an item at random. Or, if somehow I should just do this without a grid?

I’m also a little confused as to how I achieve this the best and what the best practice is for this.

Below is a video, with a timestamp. At the timestamp, you see a bunch of ores that randomly spawned. I’m trying to create something similar. As far as I can tell, the spawner checks if the area is empty (on a grid?) and then it spawns say 1 object on a random cell that is empty every 1 minute or so.

Video is here

Anyone got any idea on how to do this?

I did this but I don’t think it’s right…

	public int numberToSpawn;
	public List<GameObject> spawnPool;

	public void SpawnObjects()
	{
		for (int i = 0; i < 10; i++)
		{
			float spawnY = Random.Range
				(Camera.main.ScreenToWorldPoint(new Vector2(0, 0)).y, Camera.main.ScreenToWorldPoint(new Vector2(0, Screen.height)).y);
			float spawnX = Random.Range
				(Camera.main.ScreenToWorldPoint(new Vector2(0, 0)).x, Camera.main.ScreenToWorldPoint(new Vector2(Screen.width, 0)).x);

			Vector2 spawnPosition = new Vector2(spawnX, spawnY);
			Instantiate(spawnPool, spawnPosition, Quaternion.identity);
		}
	}

I’m also creating a 2d open-world farming game that is somewhat similar to forager…


The way I did i handled spawning of objects : I made my world randomly generated tiles that are simple gameobjects. Then I actually instatintiated the objects as children of the tile… So when I need to check whether the tile is full or not I just check the childCount of the object


BUT, I think you are using a tilemap to make your world.
A possible solution is to this is set up a timer and use raycasts to check whether an object is present in the given position… If you need code for reference on how to do it, I can provide some :slight_smile:


Reference code :

[SerializeField] private int MaxX, MaxY, MinX, MinY; //Assign all these in the inspector according to the size of the tilemap

[SerializeField] private GameObject[] SpawnObjs; //These are the objects like weeds, stones, etc...

private float Timer;
[SerializeField] private float MaxTime; //This is the time between spawns, change accordingly

private void Update()
{
    Timer += Time.deltaTime;
    if (Timer >= MaxTime)
    {
        int XPos = Random.Range(MinX, MaxX + 1);
        int YPos = Random.Range(MinY, MaxY + 1);

        int InstNum = Random.Range(0, SpawnObjs.Length);

        Instantiate(SpawnObjs[InstNum], new Vector3(XPos, YPos, 0f), Quaternion.identity);

        Timer = 0;
    }
}

This isn’t tested but i think it should work :slight_smile:


Reference code 2 : Change the code to this if you want to be sure that no objects spawn on top of each other

 [SerializeField] private int MaxX, MaxY, MinX, MinY; //Assign all these in the inspector according to the size of the tilemap
    
    [SerializeField] private GameObject[] SpawnObjs; //These are the objects like weeds, stones, etc...
    
    private float Timer;
    [SerializeField] private float MaxTime; //This is the time between spawns, change accordingly
    
    private void Update()
    {
        Timer += Time.deltaTime;
        if (Timer >= MaxTime)
        {
            int XPos = Random.Range(MinX, MaxX + 1);
            int YPos = Random.Range(MinY, MaxY + 1);
    
            int InstNum = Random.Range(0, SpawnObjs.Length);
            
            RaycastHit2D = hit;
            if (Physics2D.Raycast(new Vector3(XPos, YPos, 1f), Vector3.back, out hit))
            {
                if (hit.tranform.tag != "InstObj")
                { 
                   Instantiate(SpawnObjs[InstNum], new Vector3(XPos, YPos, 0f), Quaternion.identity);
                }
            } 
            Timer = 0;
        }
    }

Important : All the Objects like weeds, stones and whatever you are instantiating must have the tag InstObj


Sorry for not posting this code sooner, i got caught up in some other work… Good Luck :slight_smile:

@Caeser_21 I’m sorry but could you help me. The first code reference works fine, but the second one gives errors
“‘RaycastHit2D’ is a type but is used like a variable”
and “The name ‘hit’ does not exist in the current context”