(C#)Tracking Instantiated Objects Globally

I think I am misunderstanding the difference/relationship between GameObject and Transform types.

Right now, I have a spawner prefab that uses the following code to spawn enemies:

	public void spawnEnemy()
	{
		var gameController = GameObject.FindWithTag ("GameController");
					
		if(cooldown < 0)
		{
			//generate a random enemy from the enemy List
			int rand = Random.Range(0,enemyList.Length);

			//spawn the enemy
			var enemy = Instantiate(enemyList[rand],transform.position, Quaternion.identity) as Transform;

			//add the enemy to the global spawned enemy list in GameScript.cs
			gameController.GetComponent<GameScript>().spawnedEnemies.Add(enemy);

			//get the associated cooldown
			cooldown = cooldownList[rand];
		}
		
		cooldown -= Time.deltaTime;

	}

Additionally, I have an invisible GameController that is tracking the spawned enemies (List spawnedEnemies).

Which brings me to my issue: I have a weapon in the game that is essentially a seeking missile. I call the following function:

	private void acquireTarget()
	{
		//find the game controller
		var gameController = GameObject.FindWithTag ("GameController");

		//if there are untargeted enemies
		if(!gameController.GetComponent<GameScript>().noTargets)
		{
			lockedTarget = gameController.GetComponent<GameScript>().getTarget;
		}
	}

getTarget basically builds a new List of all existing objects who have the bool isTargeted set to false (essentially populating the list with eligible targets) and then returns one at random.

I then call the following two lines of code at the end of my Update function to attempt to move the missile:

		transform.position = Vector3.MoveTowards (transform.position, lockedTarget.transform.position, .03f);
		transform.LookAt (lockedTarget.transform);

What actually happens is that the missile object stops drawing on screen, and I am thrown the following error in the console:

UnassignedReferenceException: The variable lockedTarget of ‘MissileBehavior’ has not been assigned.
You probably need to assign the lockedTarget variable of the MissileBehavior script in the inspector.
UnityEngine.Component.get_transform () (at C:/BuildAgent/work/d3d49558e4d408f4/artifacts/EditorGenerated/UnityEngineComponent.cs:19)
MissileBehavior.Update () (at Assets/Scripts/MissileBehavior.cs:41)

Line 41 is the Vector3.MoveTowards. The problem is, if I inspect the missile object, it shows as having Locked Target assigned as pinwheel_enemy(clone)(Transform). So I’m not sure what’s going on.

From what I can tell based off the code snippets - if you’re getting an UnassignedReferenceException but when you inspect the object you actually see an assigned reference, it seems reasonable to me to assume that you are assigning the reference a frame too late. Try replacing the 2 lines in your missile’s Update method with this:

if(lockedTarget != null)
{
    transform.position = Vector3.MoveTowards (transform.position, lockedTarget.transform.position, .03f);
    transform.LookAt (lockedTarget.transform);
}
else
{
    Debug.LogError("lockedTarget is null!");
}

And see if you get the error message logged to the console. If so, then you’ll have to go into more detail regarding when you call your acquireTarget() method and whatever else might actually be happening. Posting the entire missile MonoBehaviour would help.

acquireTarget() is not guaranteed to find a target:

private void acquireTarget() {
     //find the game controller
     var gameController = GameObject.FindWithTag ("GameController");
     //if there are untargeted enemies
     if(!gameController.GetComponent<GameScript>().noTargets) {
         lockedTarget = gameController.GetComponent<GameScript>().getTarget;
         hasTarget = true;
     }
}

If noTargets return true then lockedTarget will remain unchanged. You will need any code that follows your call to acquireTarget() to handle this situation gracefully.

On a more cosmetic note here a couple of changes that could be made to tighten up the typing:

// SpawnerScrpt, line 39 Instantiate has a generic form.
//var enemy = Instantiate(enemyList[rand],transform.position, Quaternion.identity) as Transform;
Transform enemy = Instantiate<Transform>(enemyList[rand],transform.position, Quaternion.identity);

// MissileBehavior, line 41 lockedTarget is already of type Transform
//transform.position = Vector3.MoveTowards (transform.position, lockedTarget.transform.position, .03f);
transform.position = Vector3.MoveTowards (transform.position, lockedTarget.position, .03f);

Thanks guys, this answered a ton of my questions, so going to chew on this a while and see if I can get it working (and mark this answered)