Respawn a Pickup Using Instantiate

Hey guys! Have a question about instantiating a prefab.

I followed the Instantiate steps in the Unity manual and was able to get a prefab to show up on the screen in a grid or a circle. I would like to have my prefab respawn in the same place after it is picked up by the player. How would I go about doing this?

I’ve tried just about everything from using Yield WaitForSeconds to SetActive as false or true with no progress on getting the prefab to show up again.

Any suggestions?

You can create a spawn script.

Have a bool that checks if you need to spawn or not. If you pick up the object, set the bool true, and spawn another one

Or…

Use a coroutine to give the elision that you picked it up, set the GameObject in active wait 3 seconds, then set it active.

Paste your code for what you have tried

^ coroutine, since you can use yield waitforseconds

I think a better way for this scenario is just to call Invoke when the item is picked up.

1 Like

Ok here is what I’ve tried…
I have a capsule tagged as Player. I have the prefabs tagged as Pickup.

In the Player script, I have the OnTriggerEnter method where the prefab is picked up by the player. I have the coroutine following this where the prefab should reappear after 3 seconds.

I can get the prefab to be picked up by the player but it doesn’t reappear after 3 seconds. I’ve tried using the coroutine in both the player script and outside the player as a respawn script placed on an empty game object. Neither seem to be able to work.

Thanks for the suggestion of using Invoke der_r but I have no idea how to set that up in my code even after reading the Unity doc. I may be over-thinking it a bit at this point.

Here’s my code - maybe there’s something I’m missing.

public class Player : MonoBehaviour
{
    public float movementSpeed = 5.0f;
    CharacterController character;


    public GameObject prefab;
    public int numberOfObjects = 1;
    public float radius = 5f;
   
    bool PickedUp = false;

    // Use this for initialization
    void Start ()
    {
  
    }
  
    // Update is called once per frame
    void Update ()
    {
        //Get the Character Controller//
        CharacterController character = GetComponent<CharacterController>();

        //Character Movement//
        float FBSpeed = Input.GetAxis("Vertical") * movementSpeed; //forward and back movement
        float LRSpeed = Input.GetAxis("Horizontal") * movementSpeed; //left and right movement

        Vector3 speed = new Vector3(LRSpeed, 0, FBSpeed); //get the Vector for the speed
        speed = transform.rotation * speed;  //storing the speed
        character.Move(speed * Time.deltaTime); //get the character movement speed

    }
   
    void OnTriggerEnter(Collider other)
    {
        if (other.gameObject.tag =="Pickup")
        {
            other.gameObject.SetActive(false);
            StartCoroutine(RespawnItem());
        }
    }
  
    IEnumerator RespawnItem ()
    {
        if(PickedUp)
        {
            int respawnTime = 3;
            yield return new WaitForSeconds(respawnTime);
            for (int i = 0; i < numberOfObjects; i++)
            {
                float angle = i * Mathf.PI * 2 / numberOfObjects;
                Vector3 pos = new Vector3(Mathf.Cos(angle), 0, Mathf.Sin(angle)) * radius;
                Instantiate(prefab, pos, Quaternion.identity);
            }
            Debug.Log ("Spawned!");
        }
        PickedUp = false;
    }
}

The Respawn script:

public class Respawn : MonoBehaviour
{
    public GameObject prefab;
    public int numberOfObjects = 1;
    public float radius = 5f;
    bool PickedUp = false;

    void OnTriggerEnter(Collider other)
    {
        if (other.gameObject.tag =="Pickup")
        {
            other.gameObject.SetActive(false);
            StartCoroutine(RespawnItem());
        }
    }

    IEnumerator RespawnItem ()
    {
        if(PickedUp)
        {
            int respawnTime = 3;
            yield return new WaitForSeconds(respawnTime);
            for (int i = 0; i < numberOfObjects; i++)
            {
                float angle = i * Mathf.PI * 2 / numberOfObjects;
                Vector3 pos = new Vector3(Mathf.Cos(angle), 0, Mathf.Sin(angle)) * radius;
                Instantiate(prefab, pos, Quaternion.identity);
            }
            Debug.Log ("Spawned!");
        }
      
        PickedUp = false;
    }
}

I never see you setting PickedUp to true.

This is interesting…

Thanks for the catch der_r on not setting PickedUp to true. That helped actually get the cube to appear again, but now it’s only showing 1 cube in 1 place. It looks like all the cubes are respawning in the same place instead of in another grid area.

I tried placing the Respawn script in an empty game object, duplicating, then placing in different areas but this did not change the behavior of the scene.

How would I make it so the cubes would show up in a separate grid area or randomly on the plane?

Any suggestions guys? Really stumped on this one. I have no idea why all of the cubes are respawning in one place.

In your for-loop where you are re-spawning the cubes, it says “for(int i =0; i < numberOfObjects; i++)”. But “numberOfObjects” is set to 1, which means the loop only gets 1 iteration.

That was one of the first things I tried. I changed numberOfObjects = 5 and it still produced the same result.
But I did see that as a possible cause to the problem right away - just wish it was the answer. Had a feeling this was going to be a tricky one.

Ok this is interesting. I went into my Player script and changed the number of objects to 5. I have it public anyway so it would be available to be changed in the inspector, but I wanted to satisfy my curiosity and changed the initial value.

When I run the scene, I can see the first set of cubes in the grid formation. When I start to pick them up, I’m able to see some of the cubes being instantiated again. So at least I know the loop is working properly.

But here’s the interesting part, there are only 5 cubes showing up in the scene. Each of these 5 cubes has 10 cubes stacked in the same place. When you pause the game and select the cube, you can move each individual cube to a place on the stage. But the cubes never form a grid pattern or show up randomly after returning to the game.

They just sit in stacks of 10 and only show 5 cubes in the scene.

Any idea on where to go from here?

Any ideas guys? Sadly haven’t been able to make any progress.

Can you give us a complete update on relevant code and scene setup?

Sure thing!

The scene is set up with a player capsule scripted to move on a plane. I have an empty game object holding 2 scripts: the Grid Instantiate script and the Respawn script. I have a cube prefab set up to be instantiated by the script.

When the scene plays, the cube shows up in a 5 x 5 grid and the cubes can be picked up by the player. Once they are picked up, I have the script set to spawn a new cube after 1 second. I was hoping to have the cube spawn in the same place it was in the grid, but it doesn’t.

The cubes spawn, but in 5 separate places with 10 cubes placed in one spot, making it look like there is only 1 cube in the scene. When you pick up this cube, it picks up all 10 cubes in the same place and respawns all 10 in the same place.

My goal is to get the cubes to either spawn back in the grid position or to spawn in random places on the stage.

Here’s my most current code:
Player:

public class Player : MonoBehaviour
{
    public float movementSpeed = 5.0f;
    CharacterController character;


    public GameObject prefab;
    public int numberOfObjects = 5;
    public float radius = 5f;
   
    bool PickedUp = false;

    // Use this for initialization
    void Start ()
    {
  
    }
  
    // Update is called once per frame
    void Update ()
    {
        //Get the Character Controller//
        CharacterController character = GetComponent<CharacterController>();

        //Character Movement//
        float FBSpeed = Input.GetAxis("Vertical") * movementSpeed; //forward and back movement
        float LRSpeed = Input.GetAxis("Horizontal") * movementSpeed; //left and right movement

        Vector3 speed = new Vector3(LRSpeed, 0, FBSpeed); //get the Vector for the speed
        speed = transform.rotation * speed;  //storing the speed
        character.Move(speed * Time.deltaTime); //get the character movement speed

    }
   
    void OnTriggerEnter(Collider other)
    {
        if (other.gameObject.tag =="Pickup")
        {
            PickedUp = true;
            other.gameObject.SetActive(false);
            StartCoroutine(RespawnItem());
        }
    }
  
    IEnumerator RespawnItem ()
    {
        if(PickedUp)
        {
            PickedUp = true;
            int respawnTime = 1;
            yield return new WaitForSeconds(respawnTime);
            for (int i = 0; i < numberOfObjects; i++)
            {
                float angle = i * Mathf.PI * 2 / numberOfObjects;
                Vector3 pos = new Vector3(Mathf.Cos(angle), 0, Mathf.Sin(angle)) * radius;
                Instantiate(prefab, pos, Quaternion.identity);
            }
            Debug.Log ("Spawned!");
        }
        PickedUp = false;
    }
}

Pickup:

public class Pickup : MonoBehaviour
{

    void OnTriggerEnter(Collider other)
    {
        if(other.gameObject.tag =="Pickup")
        {
            Destroy(other);
        }
    }
}

Grid setup:

public class GridInstantiate : MonoBehaviour
{
    public GameObject prefab;
    public float gridX = 5f;
    public float gridY = 5f;
    public float spacing = 2f;
  
    void Start() {
        for (int y = 0; y < gridY; y++) {
            for (int x = 0; x < gridX; x++) {
                Vector3 pos = new Vector3(x, 0, y) * spacing;
                Instantiate(prefab, pos, Quaternion.identity);
            }
        }
    }
}

Circle setup (for testing to make sure I did the instantiate correctly)

public class CircleInstantiate : MonoBehaviour {
    public GameObject prefab;
    public int numberOfObjects = 20;
    public float radius = 5f;
  
    void Start() {
        for (int i = 0; i < numberOfObjects; i++) {
            float angle = i * Mathf.PI * 2 / numberOfObjects;
            Vector3 pos = new Vector3(Mathf.Cos(angle), 0, Mathf.Sin(angle)) * radius;
            Instantiate(prefab, pos, Quaternion.identity);
        }
    }
  
    // Update is called once per frame
    void Update () {
  
    }
}

Respawn:

public class Respawn : MonoBehaviour
{
    public GameObject prefab;
    public int numberOfObjects = 5;
    public float radius = 5f;
    bool PickedUp = false;

    void OnTriggerEnter(Collider other)
    {
        if (other.gameObject.tag =="Pickup")
        {
            other.gameObject.SetActive(false);
            StartCoroutine(RespawnItem());
        }
    }

    IEnumerator RespawnItem ()
    {
        if(PickedUp)
        {
            PickedUp = true;
            int respawnTime = 1;
            yield return new WaitForSeconds(respawnTime);
            for (int i = 0; i < numberOfObjects; i++)
            {
                float angle = i * Mathf.PI * 2 / numberOfObjects;
                Vector3 pos = new Vector3(Mathf.Cos(angle), 0, Mathf.Sin(angle)) * radius;
                Instantiate(prefab, pos, Quaternion.identity);
            }
            Debug.Log ("Spawned!");
        }
      
        PickedUp = false;
    }
}

I’m not sure I understand the purpose of the respawning code being there 2 times, once in the player script and once in the respawn script. They seem to be identical.

And can you upload a web player? It might help us visualize the problem better. I’m lost right now. :smile:

No problem! Sorry this is so confusing. I think I’ve been looking at this code for so long it’s just melded together into one giant mess. Here’s a link to the web player of the current build. Hopefully this will help visualize what I’m talking about. The cubes do generate all 10 in one place after they spawn. Really have no idea why that is. I make the strangest bugs occur in my games.

https://db.tt/mpQ5fOBn

Got some extra help from der_r (thank you!) and was able to get things working! Here’s the code that works in case anyone else runs into this problem. Thank you everyone for your help! I really appreciate it! :slight_smile:

Player:

public class Player : MonoBehaviour
{
    public float movementSpeed = 5.0f;
    CharacterController character;


    public GameObject prefab;
    public float positionX = 3f;
    public float positionY = 3f;
    
    bool PickedUp = false;
   
    // Update is called once per frame
    void Update ()
    {
        //Get the Character Controller//
        CharacterController character = GetComponent<CharacterController>();

        //Character Movement//
        float FBSpeed = Input.GetAxis("Vertical") * movementSpeed; //forward and back movement
        float LRSpeed = Input.GetAxis("Horizontal") * movementSpeed; //left and right movement

        Vector3 speed = new Vector3(LRSpeed, 0, FBSpeed); //get the Vector for the speed
        speed = transform.rotation * speed;  //storing the speed
        character.Move(speed * Time.deltaTime); //get the character movement speed

    }
    
    void OnTriggerEnter(Collider other)
    {
        if (other.gameObject.tag =="Pickup")
        {
            PickedUp = true;
            other.gameObject.SetActive(false);
            Invoke("RandomCube", 3);
        }
    }
   
    void RandomCube()
    {
        Vector3 position = new Vector3(Random.Range(-5.0F, 5.0F), 0, Random.Range(-5.0F, 5.0F));
        Instantiate(prefab, position, Quaternion.identity);
    }
}