Jess
Jess

Reputation: 123

Next Scene Not Loading

My problem is that when all the enemies are killed the scene that should be loaded is not loading. I did add the scene to the Build setting (it has an index of 3) but it is still not loading. The script I created is attached to an empty object and not directly to the sprite (is that okay?). Can someone tell me why the scene isn't loading? Thank you.

This image is for to show you the EnemySpawner empty object inspector enter image description here

EnemySpawner Script :

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

public class EnemySpawner : MonoBehaviour {

[SerializeField] GameObject EnemyPreFab;
[SerializeField] int MaxEnemies = 30;
[SerializeField] float EnemySpawnTime = 1.00001f;
[SerializeField] GameObject FirstWaypoint;
int CurrentNumOfEnemies = 0;
public LevelManager myLevelManager;
public int maximumnumberofhits = 0;
int timesEnemyHit;



IEnumerator SpawningEnemies()
{
    while(CurrentNumOfEnemies <= MaxEnemies)
    {
        GameObject Enemy = Instantiate(EnemyPreFab, this.transform.position, Quaternion.identity);
        CurrentNumOfEnemies++;
        yield return new WaitForSeconds(EnemySpawnTime);
    }
}

void Start()
{
    StartCoroutine(SpawningEnemies());
    timesEnemyHit = 0;
    if (this.gameObject.tag == "EnemyHit")
    {
        CurrentNumOfEnemies++;
    }


}

void OnCollisionEnter2D()
{
    timesEnemyHit++;
    if (timesEnemyHit == maximumnumberofhits)
    {
        CurrentNumOfEnemies--;
        Destroy(this.gameObject);
    }

    if (CurrentNumOfEnemies == 0)
    {
        myLevelManager.LoadLevel("NextLevelMenu");
        Debug.Log("LevelLoaded");
    }
   }

}

LevelManger script:

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

public class LevelManager : MonoBehaviour {
 public void LoadLevel(string name)
 {
    print("Level loading requested for" + name);
    SceneManager.LoadScene(name);
  }
}

EnemyShooting Script :

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

public class EnemyShooting : MonoBehaviour {


[SerializeField] float EnemyLaserSpeed = 10f;
[SerializeField] float EnemyLaserFireTime;
[SerializeField] GameObject LaserBulletEnemyPreFab;
[SerializeField] int MaxNumberOfHits = 1;
int CurrentNumberOfHits = 0;
Coroutine FireCoroutine;

void OnTriggerEnter2D(Collider2D collider)
{
    if(collider.gameObject.tag == "PlayerLaser")
    {
        if(CurrentNumberOfHits < MaxNumberOfHits)
        {
            CurrentNumberOfHits++;
            Destroy(collider.gameObject);
            Score.ScoreValue += 2;//The user will be rewarded 1 point
        }
    }
}



void DestroyEnemy()
{
    if(CurrentNumberOfHits >= MaxNumberOfHits)
    {
        Destroy(gameObject);
    }
}

private void Fire()
{
    FireCoroutine = StartCoroutine(ShootContinuously());
}

void BecomeVisible()
{
    Fire();
}

IEnumerator ShootContinuously()
{
    while (true)
    {
        GameObject LaserBulletEnemy = Instantiate(LaserBulletEnemyPreFab, this.transform.position, Quaternion.identity) as GameObject;
        LaserBulletEnemy.GetComponent<Rigidbody2D>().velocity = new Vector2(0, EnemyLaserSpeed);
        EnemyLaserFireTime = Random.Range(0.5f, 0.9f);
        yield return new WaitForSeconds(EnemyLaserFireTime);
    }
}
// Use this for initialization
void Start () {

    BecomeVisible();
}

// Update is called once per frame
void Update () {

    DestroyEnemy();

   }
}

EnemyPathing script:

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

public class EnemyPathing : MonoBehaviour {
[SerializeField] List<Transform> WayPoints;
[SerializeField] float EnemyMovingSpeed = 5f;
int WayPointIndex = 0; 

void EnemyMoving()
{
    if (WayPointIndex <= WayPoints.Count - 1)
    {
        var TargetedPosition = WayPoints[WayPointIndex].transform.position; //The position of where the enemy needs to go
        TargetedPosition.z = 0f;
        var MoveThisFrame = EnemyMovingSpeed * Time.deltaTime;
        transform.position = Vector2.MoveTowards(this.transform.position, TargetedPosition, MoveThisFrame);

        if(transform.position == TargetedPosition)
        {
            WayPointIndex++;
        }
    }

    else
    {
        Destroy(gameObject);
    }
}
// Use this for initialization
void Start () {

    transform.position = WayPoints[WayPointIndex].transform.position;

}

// Update is called once per frame
void Update () {

    EnemyMoving();

 }
}

Upvotes: 1

Views: 120

Answers (2)

Fredrik
Fredrik

Reputation: 5108

Problem

You're checking for collisions on the SPAWNER; when someone hits the Spawner it counts down enemies. But the Spawner doesn't have a collision box in the screenshot so it can never be hit. The Scene changing code can never be called.

So the game, based on the code, looks like this:

  1. Spawn X enemies,
  2. Hit the Spawner X times,
  3. (Removed: Destroy the Spawner,)
  4. Change scene.

I'm guessing this is conceptually incorrect and you actually want to check collisions on the spawned enemies, which will then count up the amount of destroyed enemies, and change the scene when they are all dead.


Solution

Conceptually, what you want is:

  1. Spawn X enemies
  2. Count up variable for every enemy
  3. On Enemy death, count it down
  4. When 0, change scene

So how do we code this?

Well, every enemy needs a reference to the object that holds the count. You can do this in several ways, when I personally do it I usually have just one spawner that is responsible for everyone so I make that one a Singleton, that can be references from anywhere:

EnemySpawner

public class EnemySpawner : MonoBehaviour 
{
    public static Spawner Instance = null;
    int CurrentNumOfEnemies = 0;
    // ... etc

    void Start() 
    {
        if (Instance == null)
             Instance = this;

        // Spawn enemies like you do already, CurrentNumOfEnemies++ for every spawned
    }

    public OnEnemyDeath() {
        CurrentNumOfEnemies--;
        if (CurrentNumOfEnemies < 1) 
        {
            // You killed everyone, change scene: 
            LevelManager.LoadLevel("Your Level");
        }
    }

}

Enemy script (I don't know how your current code looks, but here's a minimal solution based on how I THINK your code looks):

void OnDestroy() 
{
    // This will run automatically when you run Destroy() on this gameObject
    EnemySpawner.Instance.OnEnemyDeath(); // Tell the EnemySpawner that someone died
}

This will only work if you have exactly only ONE spawner. If you have multiple ones you will have to send a reference to the instance of its spawner to every spawned enemy. I can show you how to do ths too, if you wish.


Bonus content

LevelManager doesn't need to be on a GameObject, it can be static instead:

  1. Remove the LevelManager script from any GameObject
  2. Change your LevelManager code to this:
using System.Collections;
using System.Collections.Generic;
using UnityEngine;
using UnityEngine.SceneManagement;

public static class LevelManager 
{
    public static void LoadLevel(string name)
    {
        Debug.Log("Level loading requested for" + name);
        SceneManager.LoadScene(name);
    }
}

Now you can use it from ANYWHERE, without needing to initialize a reference to any script or GameObject:

LevelManager.LoadLevel("My Level");

Upvotes: 2

Andrea
Andrea

Reputation: 6125

myLevelManager.LoadLevel("NextLevelMenu"); is never executed, because you destroy the object in the if-test above.

Upvotes: 2

Related Questions