Home > Software design >  Unity 2d : Objects being reinstantiated on scene reload after being destroyed
Unity 2d : Objects being reinstantiated on scene reload after being destroyed

Time:09-22

GOAL
So I'm creating a top down arena battler type game, and I want you to be able to restart the game by pressing R.

PROBLEM
When I press R, the whole scene resets as it should, except all the enemies that were previously instantiated (and then destroyed) are spawned again, all at once.

CODE
This is the enemy spawning code :

using System.Collections.Generic;
using UnityEngine;

public class EnemySpawn : MonoBehaviour
{
    private float nextActionTime = 0.0f;
    public float period = 5f;

    public GameObject enemy;

    void Update()
    { 
        if (Time.time > nextActionTime ) {
            nextActionTime  = period;
            GameObject clone = Instantiate(enemy, new Vector3(-1, 3, 0), Quaternion.identity);
            clone.tag = "enemy";
        }  
    }
}

This is the player code, responsible for restarting the scene (I have marked what I belive to be the relevantant sections with dashes) :

using System.Collections;
using System.Collections.Generic;
using UnityEngine;
using UnityEngine.UI;
using UnityEngine.SceneManagement;

public class PlayerController : MonoBehaviour
{
    public Rigidbody2D rb;

    public GameObject Shield;
    public GameObject ShieldInstance;

    public float moveSpeed = 4.3f;
    public float sheildSpeed = 5f;
    
    Vector2 movement;

    AudioSource woop;
    AudioSource waa;

----------------------------

    GameObject[] enemies;

----------------------------

    bool isDead = false;

    void Start() {
        woop = GameObject.Find("Main Camera/ShieldSFX").GetComponent<AudioSource>();
        waa = GameObject.Find("Main Camera/DefeatSFX").GetComponent<AudioSource>();
    }

    void Update()
    {
--------------------------------------------------------------
        enemies = GameObject.FindGameObjectsWithTag("enemy");
--------------------------------------------------------------
        movement.x = Input.GetAxisRaw("Horizontal");
        movement.y = Input.GetAxisRaw("Vertical");

        Vector3 mouseScreen = Input.mousePosition;
        Vector3 mouse = Camera.main.ScreenToWorldPoint(mouseScreen);

        transform.rotation = Quaternion.Euler(0, 0, Mathf.Atan2(mouse.y - transform.position.y, mouse.x - transform.position.x) * Mathf.Rad2Deg - 90); 

        if (Input.GetMouseButtonDown(0))
        {
            if (ShieldInstance != null || transform.GetChild(0).GetComponent<SpriteRenderer>().enabled == false) { return; }
            woop.Play();
            ShieldInstance = Instantiate(Shield, transform.position   transform.forward   transform.up, transform.rotation);
            ShieldInstance.transform.parent = transform;
        }

        if (Input.GetMouseButtonUp(0))
        {
            if (ShieldInstance == null) { return; }
            ShieldInstance.transform.parent = null;
            ShieldInstance.GetComponent<ShieldController>().LaunchForward(sheildSpeed);
            Destroy(ShieldInstance, 2.3f);
        }
-------------------------------------------------------------------------------
        if (Input.GetKey("r")) {
            SceneManager.LoadScene(SceneManager.GetActiveScene().buildIndex);
            foreach (GameObject one in enemies) {
                Destroy(one);
            }
        }
-------------------------------------------------------------------------------
    }

    void FixedUpdate() {
        if (!isDead) {
            rb.MovePosition(rb.position   movement * moveSpeed * Time.fixedDeltaTime);
        }
    }

    void OnCollisionEnter2D(Collision2D other) {
        if (other.gameObject.tag == "enemy") {
            waa.Play();
            GameObject.Find("Canvas/gameover").GetComponent<Text>().enabled = true;
            transform.GetChild(0).GetComponent<SpriteRenderer>().enabled = false;
            GetComponent<PolygonCollider2D>().enabled = false;
        }
    }
}

And this is the enemy code :

using System;
using System.Collections;
using System.Collections.Generic;
using UnityEngine;

public class EnemyFollow : MonoBehaviour
{
    public float moveSpeed;
    public ParticleSystem explode;

    AudioSource boom;

    Vector2 movement;

    GameObject player;
    Rigidbody2D rb;

    SpriteRenderer sr;
    PolygonCollider2D pc;


    void Start() {
        rb = GetComponent<Rigidbody2D>();
        sr = transform.GetChild(0).GetComponent<SpriteRenderer>();
        pc = GetComponent<PolygonCollider2D>();
        player = GameObject.Find("Player");
        boom = GameObject.Find("Main Camera/ExplodeSFX").GetComponent<AudioSource>();
    }

    void Update()
    {
        Vector2 difference = (player.transform.position - new Vector3(2, .5f, 0)) - transform.position;

        if (difference.x > 0) {
            movement.x = 1;
        } else if (difference.x < 0){
            movement.x = -1;
        } else {
            movement.x = 0;
        }

        if (difference.y > 0) {
            movement.y = 1;
        } else if (difference.y < 0){
            movement.y = -1;
        } else {
            movement.y = 0;
        }

        rb.MovePosition(rb.position   movement * moveSpeed * Time.fixedDeltaTime);
    }

    void OnCollisionEnter2D(Collision2D other) {
        if (other.gameObject.tag == "shield") {
            StartCoroutine(ExplodeF());
        }
    }

    private IEnumerator ExplodeF() {
        explode.Play();
        boom.Play();
        sr.enabled = false;
        pc.enabled = false;
        yield return new WaitForSeconds(explode.main.startLifetime.constantMax);
        Destroy(gameObject);
    }
}

I would really appreciate any help! If you want / need more details, just leave a comment :)

CodePudding user response:

The problem is in Time.time, it is time since the start of the application, not since the start of the scene. So if you were in the game 30 secs, Time.time is 30 secs. If you reload the scene it is still 30 secs.

You have to count the time passed since entering the scene. Then it won't respawn all the enemies on scene reload.

CodePudding user response:

When you restart the scene, everything is being destroyed and reset back except for the time.

The problem in your code is in the enemy spawner. Time.time returns the time passed since you started the game (and not since the scene was loaded). So, after the restart the if condition is true and the enemies are spawned.

If you want to count the time (in seconds) since the scene was loaded, what you can do is to add a variable in the enemy spawner class that would count the time

using System.Collections.Generic;
using UnityEngine;

public class EnemySpawn : MonoBehaviour
{
    private float nextActionTime = 0.0f;
    private float timeSinceStart = 0;
    public float period = 5f;

    public GameObject enemy;

    void Update()
    { 
        if (timeSinceStart > nextActionTime ) {
            nextActionTime  = period;
            GameObject clone = Instantiate(enemy, new Vector3(-1, 3, 0), Quaternion.identity);
            clone.tag = "enemy";
        }  
        timeSinceStart  = Time.deltaTime;
    }
}

See Time.deltaTime

  • Related