Spawn at tagged elements

Hey so I’ve been trying to spawn food at tagged elements. I’ve tagged the ones where the snake hasn’t yet reached as “Not Green” and the other ones “Green”. As the snake moves over the boxes the boxes turn green. I’m not able to figure out this logic as I’ve tried a couple of things and nothing has worked.

Some help would be really appreciated. I’m also not able to destroy the food after collision (isTrigger is set to true). The snake is on the far left.
This is the code I’ve typed out

Food.cs

using System.Collections;

using System.Collections.Generic;

using UnityEngine;

public class Food : MonoBehaviour

{

[SerializeField] GameObject foodPrefab;

[SerializeField] Transform borderTop;

[SerializeField] Transform borderLeft;

[SerializeField] Transform borderDown;

[SerializeField] Transform borderRight;

// Start is called before the first frame update

void Start()

{

    if(gameObject.tag == "Non Green"){

    InvokeRepeating("SpawnFood", 3, 4);

    }

}

private void SpawnFood() {

    int x = (int) Random.Range(borderLeft.position.x, borderRight.position.x);

    int z = (int) Random.Range(borderDown.position.z, borderTop.position.z);

    Instantiate(foodPrefab, new Vector3(x, 0, z), Quaternion.identity);

}

void OnTriggerEnter(Collider collision){

          Destroy(collision.gameObject);

    }

}

Collision Handler.cs

using System.Collections;

using System.Collections.Generic;

using UnityEngine;

public class CollisionHandler : MonoBehaviour

{

private void OnCollisionEnter(Collision other) {

if(other.gameObject.tag == "Player") {

    GetComponent<MeshRenderer>().material.color = Color.green;

    gameObject.tag = "Green";

}

}

}

Hi,

Have you already tried to add Debug.Logs to your code to see what is going on during runtime?

I’m not able to figure it out

In which course and lecture are you?

I’ve been following the Unity 3D course on udemy and this was an assignment given to me so I needed help. I got the game object to destroy itself. Just need help with the spawning of food on the tagged elements

Hey there…

So on this script, what object is it on? Can you put a debug statement in your “Spawn Food” method to see if its being called?

Right now its only going to call that if the game object this particular script is on is tagged “Non Green”. (Double check your spaces etc as well).

One other thought is if it is being called, check that 0 on the Y isnt underneath the gameboard…you may need to spawn it higher than 0.

The food spawns at random locations with no problem but I want it to spawn only at places where the snake hasn’t yet reached or collided with the box I’ve used in this game. I’ve labelled the boxes that haven’t collided with the snake as “Not Green” and the ones that have collided to “Green”. The moment the snake collides with a tile, it turns green.

I’m trying to instantiate the foodPrebab on “Not Green” tiles only.

The script is on the Play Space. When I used it on the boxes it, the foodPrebab spawned multiple times at one go.

Ok. So (assuming I understand correctly!) right now it’s not quite working to how you’re planning is its only running that script if the “Play space” target is “Non Green”. So it’s not really checking for non green tiles vs non green.

What I would do, is create a list of “Non Green” tiles. When one is green, remove it from the list. This way, you can pick a random tile in the “Non Green” list and instantiate a food on the position of that particular game object. All you have to do is pick a random number in that Non Green list/array index, and spawn food at that particular tile.

On the tiles themselves you can have a bool that is set to true when food is spawned on it, so that it doesnt double up, and check for this condition before you spawn on it.

That’s one way to do it, there could be many other ways but the main thing to note is you have to be able to scan through the tiles and pick a ‘non green’ one, and spawn at that particular location. You could theoretically do it on the tiles themselves, but it would be harder to check which other tiles have food on them etc.

I have a rough idea what you are talking about. I’m pretty new to this so I’m having a hard time trying to implement into code. Can you please give me an example?

Spawner.cs

using System.Collections;

using System.Collections.Generic;

using UnityEngine;

public class Spawner : MonoBehaviour

{

[Header("Food Settings")]

[SerializeField] GameObject foodPrefab;

[SerializeField] float foodSpawnTime = 5f;

[SerializeField] GameObject[] tiles;

[Header("Border Positions")]

[SerializeField] Transform borderTop;

[SerializeField] Transform borderLeft;

[SerializeField] Transform borderDown;

[SerializeField] Transform borderRight;

// Start is called before the first frame update

void Start()

{

    InvokeRepeating("SpawnFood", 3, 4);

   

}

private void SpawnFood() {

    int x = (int) Random.Range(borderLeft.position.x, borderRight.position.x);

    int z = (int) Random.Range(borderDown.position.z, borderTop.position.z);

    tiles = GameObject.FindGameObjectsWithTag("Non Green");

    foreach(GameObject tile in tiles) {

    GameObject food = Instantiate(foodPrefab, tile.transform.position, Quaternion.identity) as GameObject;

    Destroy(food, foodSpawnTime);

    }

    }

}

How do I instantiate at a random tile? It’s being spawned at every element

Ok - not quite. If you’re going to iterate through all the squares you’d have to check if its non green before you spawn it.

Instead, you can do something like this:

First, have a script called “Block” (or whatever you want to call it), where you can keep track of if a block is Green or not. In that script, have a bool called isGreen. If the snake collides with the block, in your collision code, set the bool to green/true. Also, make a public method in there, so the main spawner can check if the blocks are green or not. Like so:

public bool IsGreen()
{
    return isGreen; //returns the status of your "isGreen" bool.
}

Next, have a “FoodSpawner” game object where you put your “Spawner” script.

  [SerializeField] List<Block> blocks;
  [SerializeField] float spawnTime;
  [SerializeField] GameObject foodPrefab;

this is where you can store your list of all available blocks. A list is just like an array, except it lets you
add and remove items at runtime, whereas an array is a “fixed length”. It’s good when you need to track
a list of points (like way points), or other data.

  private void Start()
   {
     InvokeRepeating("SpawnFood", 0, spawnTime); 
   }

private void SpawnFood()
{

    int foodLocation = UnityEngine.Random.Range(0, blocks.Count);
    GameObject foodInstance =  Instantiate(foodPrefab, blocks[foodLocation].transform.position, Quaternion.identity);
    blocks.RemoveAt(foodLocation);
}

So what this does is pick a random block in the List. Then, it will instantiate the food at that location, and then remove it from the list so it can’t be spawned at again. You may need to do an offset to change the position of the block - in which case, you can do:

blocks[foodLocation].transform.position + new vector3(0,1,0) 

for example if you needed to raise it 1 unit on the Y axis to be above the ground.

Now…in your collision code on the block, you want to call the Spawner’s “Remove Block” method, which we’ll add to our spawner script.

public void RemoveBlock()
{

    foreach(Block block in blocks)
    {
        if(!blocks.IsGreen())
        {
            //remove the block from the list
        }
    }

}

You could also instead pass an index instead of iterating through all the blocks, but you’d have to think about how you could track that.

Anyway this is just a quick runthrough of one option that would work. You will want to spend some time learning a bit more basics before you implement it so you know what’s going on (lists, arrays, loops, etc) - but this will give you the idea.

Hey, thank you so much. I got it to work

1 Like

Fantastic. I’m glad @heckadactyl was able to help you fix the problem. :slight_smile:


See also:

This topic was automatically closed 24 hours after the last reply. New replies are no longer allowed.

Privacy & Terms