Updated spawner script, now shooter is broke

Hi community,

I’ve been scratching my head on this issue for almost a week now, I’ve walked the code, and ran debugging to isolate the issue but now I need some Guidance:

Background: I followed @Stuart_Marsh suggestion on revamping the spawning script HERE. I got the attackers spawining properly in the correct spawner rows, but getting a error on my shooter script.

Here are the details in full for easy reference, let me know if more information nation is needed. I didn’t include the spawner script to keep this post shorter, but it can be seen at the link above. Thanks for your guidance in advanced, I love this community.

Error:

NullReferenceException: Object reference not set to an instance of an object
Shooter.IsAttackerAheadInLane () (at Assets/Scripts/Shooter.cs:55)
Shooter.Update () (at Assets/Scripts/Shooter.cs:25)

Full shooter Script (I left my commented out ‘SetMyLaneSpawner’ to show what I tried changing

> public class Shooter : MonoBehaviour {
> 	
> 	public GameObject projectile, gun;
> 	
> 	private GameObject projectileParent;
> 	private Animator anim;
> 	private Spawner myLaneSpawners;
> 	
> 	void Start() {
> 		projectileParent = GameObject.Find ("Projectiles");
> 		anim = GameObject.FindObjectOfType<Animator>();
> 		
> 		// Creates a parent if necessary
> 		if (!projectileParent) {
> 			projectileParent = new GameObject("Projectiles");
> 		}
> 		SetMyLaneSpawner();

> 	}
> 	
> 	void Update() {
> 		if (IsAttackerAheadInLane()) {
> 			anim.SetBool ("isAttacking", true);
> 		} else {
> 			anim.SetBool ("isAttacking", false);
> 		}
> 	}
> 	
> 	 //Look through all spawnwers and set myLaneSpawner if found
> 	void SetMyLaneSpawner () {
> 		Spawner[] spawnerArray = GameObject.FindObjectsOfType<Spawner>();
> 		
> 		foreach (Spawner spawner in spawnerArray) {
> 			if (spawner.transform.position.y == transform.position.y) {
> 				myLaneSpawners = spawner;
> 				return;
> 			}
> 		}		
> 	}
> //	void SetMyLaneSpawner () {
> //		Spawners[] spawnerArray = GameObject.FindObjectsOfType<Spawners>();
> //		
> //		foreach (Spawners spawner in spawnerArray) {
> //			if (spawner.transform.position.y == transform.position.y) {
> //				myLaneSpawners = spawner;
> //				return;
> //			}
> //		}		
> //	}	
> 	bool IsAttackerAheadInLane() {
> 		// Exit if no attackers in lane
> 		if (myLaneSpawners.transform.childCount <= 0) {
> 			return false;
> 		}
> 		// If there are attackers, are they ahead of the defender?
> 		foreach (Transform attacker in myLaneSpawners.transform) {
> 			if (attacker.transform.position.x > transform.position.x && attacker.transform.position.x < 10f) {
> 				return true;
> 			}
> 		}
> 		// Attacker in lane, but behind us
> 		return false;
> 	}
> 	
> 	private void Fire () {
> 		//GameObject newProjectile = Instantiate (projectile);
> 		GameObject newProjectile = Instantiate (projectile) as GameObject;
> 		newProjectile.transform.parent = projectileParent.transform;
> 		newProjectile.transform.position = gun.transform.position;
> 		
> 	}
> }

from my experience, NullReferenceException error usually generated when unity cant find the gameobject that you tell it to find or referenced to.

which line did Unity takes you when you double click it in the log?

While following the lesson, i named it “Spawners” by mistake but just left it and referenced it. In the new script, it’s called “Spawner”

The commented out code was the old code that works with the old script (Spawners). Remembering the lesson, the should be looking for the GameObject that has that in it, which would be the script name. Am i thinking of that incorrectly?

I meant to update this question this morning, but got busy at work. As of now, my error is in the SetMyLaneSpawner method.

> 	void SetMyLaneSpawner () {
> 		//Spawner[] spawnerArray = GameObject.FindObjectsOfType<Spawner>();
> 		Spawner[] spawnerArray = GameObject.FindObjectsOfType<Spawner>();

> 		foreach (Spawner spawner in spawnerArray) {
> 			if (spawner.transform.position.y == transform.position.y) {
> 				myLaneSpawners =  spawner;
> 				Debug.LogWarning("MyLaneSpawners is set to: " + myLaneSpawners);
> 				return;
> 			}
> 		}		
> 	}

I am still learning everything, so if you have a suggestion to do things a different way, I am more then ready to learn

Funny tidbit… I was typing this out while watching you update your comment :slight_smile:

i just realize that you are intended to use ‘spawner’ as name so i edited my post lol.

and yes, you right. it will try to find the game objects attached with a script with that name. you already attached the script right?

which line in the ‘SetMyLaneSpawner’ returns the error. from the error log it says line 55, but kinda hard to tell here.

myLaneSpawners = spawner;

Right now thorugh, it’s not throwing an error anymore

This script is attacked to “SpawnerScript” per the script instructions I followed in the link I originally posted

lol, did you do something?

so the code works now?

I was trying to follow the code path. Ok, here is where i’m standing right now, let’s see if I can be clear.

When I start the game, and place a defender, there is no error in the console. and the defenders don’t fire at all

When I debug the code from Mono, it seems in these 2 codes:

void SetMyLaneSpawner () {
	Spawner[] spawnerArray = GameObject.FindObjectsOfType<Spawner>();

	foreach (Spawner spawner in spawnerArray) {
		if (spawner.transform.position.y == transform.position.y) {
			myLaneSpawners =  spawner;
			return;
		}
	}		
}


bool IsAttackerAheadInLane() {
// Exit if no attackers in lane
if (myLaneSpawners.transform.childCount <= 0) {
	return false;
}
// If there are attackers, are they ahead of the defender?
	foreach (Transform attacker in myLaneSpawners.transform) {
	if (attacker.transform.position.x > transform.position.x && attacker.transform.position.x < 10f) {
		return true;
	}
}
// Attacker in lane, but behind us
return false;

}

  • When i watch “Spawner[]”, it can see in the drill down there are 5 children, so it’s seeing the 5 lanes.
  • So when It goes to the bool IsAttackerAheadInLane, it comes back true
  • Then in the foreach, it iterates once then stops so it never returns true

So it seems like that it’s just checking the parent, and not going through the lanes.

OK, that’s where I am now.

So here is what i’ve got from reading the spawner script that you linked up on the first post.

If i remember correctly, the original way (on the lecture) is to put spawner in each lane.

the shooter script (attached on defender object) will find which lane it was placed by scanning all the gameobject with spawner script attached on it, put it on an array, then compare the gameobject(with spawner script)'s y position one by one to it self (the defender) .

if it founds one that have exactly the same y position, then that was its (the defender) lane. this is what ‘SetMyLaneSpawner’ do.

after that, IsAttackerAheadInLane will return true if the lane (MyLaneSpawner gameobject) has an attacker (as child) which call the attack animation.

on the new spawner script, if i understand correctly, you remove all the spawner script from each lane and control the spawner from a single game object instead (lets call it a spawn generator).

could it be, the defender cannot determine which lane did he put into because the only gameobject with spawner script attached is only the spawn generator?

try this, create an empty (just create a c# script without editing anything inside it) script/class with use ‘Lane’ as name then attach it to the lanes like the old spawners are attached.

then change the spawnerArray = GameObject.FindObjectsOfType<Spawner>(); to spawnerArray = GameObject.FindObjectsOfType<Lane>();

and see if it works.

alternatively (which i think is a better way) is to let the defender access the Spawner array (Spawner[]) inside the spawn generator, which in this case is the spawnerscript gameobject, and do the scanning for y coordinate comparison there.

sorry for the late reply, its 3AM here so my brain is getting kind of slow reading codes. lol

No problem, I am glad you are helping out.

I did what you said and updated the shooter code so it now reads:

> 1 void SetMyLaneSpawner () {
> 2		Spawner[] spawnerArray = GameObject.FindObjectsOfType<Lane>();
> 3
> 4		foreach (Spawner spawner in spawnerArray) {
> 5			if (spawner.transform.position.y == transform.position.y) {
> 6				myLaneSpawners =  spawner;
> 7				return;
> 8			}
> 9		}		
> 10	}

when compiling, I am getting an error on line 2: Cannot implicitly convert type ‘Lane[]’ to ‘Spawner[]’

I am all for doing it a better way, just not sure how to do what you suggest, having the defenders access Spawner[].

sorry, you also need to change the rest of the code. so it should looks like this.

but dont forget on the upper side of the code, change the myLaneSpawners type to Lane. so it’ll become like this.

private Lane myLaneSpawners

or if you want to use the other way, let the defender find the public GameObject[] spawners; inside the spawner script (sorry, i’ve said its Spawner[]. but its actually GameObject[] spawners)

add this line instead

'GameObject[] spawnerArray = GameObject.FindObjectsOfType<Spawner>().spawners;

and edit the loop so it’ll check for the y axis of each gameobject contained in the array. so, the code should looks like this:

 void SetMyLaneSpawner () {

// access the spawner[] in side the spawnerscript (which has 'Spawner' component attached)
   GameObject[] spawnerArray =  GameObject.FindObjectsOfType<Spawner>().spawners;

     // the loop it for each of the spawner[] content. remember, array start from 0 but spawner.Length will start counting from 1. so we use 'less than'.
	for  (int i = 0; i < spawners.Length; i++) {
     
        // if it find a game object from the array which have the same y position
		if (spawner[i].transform.position.y == transform.position.y) {

       //set that gameobject as myLaneSpawners
			myLaneSpawners =  spawner[i];
			return;
		}
	}		
}

and dont forget to change the myLaneSpawners type to GameObject, as the array it self is an array of gameobjects.

private GameObject myLaneSpawners

Hiya @zimethsuki, I just tried the first way and the results are interesting. They are firing now, but it’s random and some rows are stopping even when an attacker is on the map in their lane.

I’m going to try to implement your second (preferred) way and see if I can get that working…

No luck, will post latest next

I converted to the GameObject method, and it’s fighting back at me that it can’t find the .spawners extension

On this line:
> GameObject[] spawnerArray = GameObject.FindObjectsOfType<Spawner>().spawners;

Error is:
> 'System.Array' does not contain a definition for 'spawners' and no extension method 'spawners' accepting a first argument of type 'System.Array' could be found (are you missing a using directive or an assembly reference?)

I think it might be related to this line:
> spawners = GameObject.FindObjectsOfType<Spawner>();

which is giving this error:

>Cannot implicitly convert type 'Spawner[]' to 'UnityEngine.GameObject[]'

Here is my full shooter.cs script at this point so you can see where it’s standing at this point:

using UnityEngine;
using System.Collections;

public class Shooter : MonoBehaviour {
	
	public GameObject projectile, gun;
	public GameObject[] spawners;
	
	private GameObject projectileParent;
	private Animator anim;
	private GameObject myLaneSpawners;

	void Start() {
		projectileParent = GameObject.Find ("Projectiles");
		anim = GameObject.FindObjectOfType<Animator>();
		spawners = GameObject.FindObjectsOfType<Spawner>();
		// Creates a parent if necessary
		if (!projectileParent) {
			projectileParent = new GameObject("Projectiles");
		}
		SetMyLaneSpawner();
	}
	
	void Update() {
		if (IsAttackerAheadInLane()) {
			anim.SetBool ("isAttacking", true);
		} else {
			anim.SetBool ("isAttacking", false);
		}
	}

	void SetMyLaneSpawner () {
		
		// access the spawner[] in side the spawnerscript (which has 'Spawner' component attached)
		GameObject[] spawnerArray =  GameObject.FindObjectsOfType<Spawner>().spawners;
		
		// the loop it for each of the spawner[] content. remember, array start from 0 but spawner.Length will start counting from 1. so we use 'less than'.
		for  (int i = 0; i < spawners.Length; i++) {
			
			// if it find a game object from the array which have the same y position
			if (spawner[i].transform.position.y == transform.position.y) {
				
				//set that gameobject as myLaneSpawners
				myLaneSpawners =  spawner[i];
				return;
			}
		}		
	}

	bool IsAttackerAheadInLane() {
	// Exit if no attackers in lane
	if (myLaneSpawners.transform.childCount <= 0) {
		return false;
	}
	// If there are attackers, are they ahead of the defender?
		foreach (Transform attacker in myLaneSpawners.transform) {
		if (attacker.transform.position.x > transform.position.x && attacker.transform.position.x < 10f) {
			return true;
		}
	}
	// Attacker in lane, but behind us
	return false;
}
	
	private void Fire () {
		//GameObject newProjectile = Instantiate (projectile);
		GameObject newProjectile = Instantiate (projectile) as GameObject;
		newProjectile.transform.parent = projectileParent.transform;
		newProjectile.transform.position = gun.transform.position;
		
	}
}

Ah, yeah. that was my bad.

it should be FindObjectOfType (without s).

GameObject[] spawnerArray = GameObject.FindObjectOfType<Spawner>().spawners;

or you can just find it with the gameobject name

GameObject[] spawnerArray = GameObject.Find("spawnerscript").GetComponent<Spawner>().spawners;

As for the second error, its really my bad. I mixedup between ‘spawners’ and ‘spawnerArray’

you can either

a. change

GameObject[] spawnerArray = GameObject.FindObjectsOfType<Spawner>().spawners; to spawners = GameObject.FindObjectsOfType<Spawner>().spawners;

or b. delete
public GameObject[] spawners; and spawners = GameObject.FindObjectsOfType<Spawner>(); and then change spawners to spawnerArray

	for  (int i = 0; i < spawnerArray.Length; i++) {
		
		// if it find a game object from the array which have the same y position
		if (spawnerArray[i].transform.position.y == transform.position.y) {
			
			//set that gameobject as myLaneSpawners
			myLaneSpawners =  spawnerArray[i];
			return;
		}

sorry, i’ve lost my old data (do to some hdd failure) so i cant test it myself.

:sweat::confounded:

@zimethsuki, I made the changes you gave me, and it’s back to square one, they are not firing at all.

I just synced all my latest files to my github: https://github.com/Wazaq/GardenGlitch if you can take a look. Maybe I inadvertently did something that blew it up.

Sorry, I’m currently out of town right now (in the middle of nowhere. cant even get decent internet signal here). Will check your github as soon as i be able to.

Thanks. Have a safe trip

I downloaded your project from github to take a look at your issues, and I found the mistakes.

First of all, as a general rule: your project is a bit of a mess, there’re redundancies and unnecessary scripts attached to game objects, which in your case caused the projectiles AND spawning bugs - and all of them are NOT related to actual code. Try to be a little bit tidier, it will be extremely useful in finding problems and understanding what’s happening wrong. :wink:

So, let’s get to the fixes:

  1. Copy the Spawner.cs script from the SpawnerScript game object to the Spawners (Lanes parent) game object.
  2. Delete the SpawnerScript game object.
  3. Select all the Lanes child game objects of the Spawners game object, and remove the script component Spawners.cs; you may as well delete the Spawners.cs from the assets (not SPAWNER.cs, just spawnerS.cs)
  4. Go in the Spawner game object and reassign the five Lanes child game objects to the Spawners array of the Spawner.cs script - you put there the Lanes from the prefab, you need to put instead the actual Lane objects from the hierarchy

That’s it, everything will work just fine.

4 Likes

Thank you @Galandil, between you and @zimethsuki, I have learned alot :slight_smile: On your comment about my project being a mess. Yes, I agree with that. When I started this project from the lesson, I imported the scripts from my previous project and I know there are some dud ones in there I need to get rid of.

I converted my project to Unity 5 and now I am working through a whole slew of other bugs with the upgrade. I need to work through them, but I will now work on cleaning up my dead files.

Next stop… why did my bottom buttons quit… :sweat:

Again, thank you!

1 Like

If you need any help regarding specific problems with Unity 5, feel free to ask, I started using it since Laser Defender. :wink:

Keep up the good work!

1 Like

Privacy & Terms