Screen wrap code works for player but not all instantiated gameobjects.

I am making myself a very simple game as my first project in Unity and everything in the game is supposed to wrap from left to right and top to bottom (and vice versa). I am using the same code to wrap game objects for both the player and the baddy objects, but while the player wraps, only first and second generation baddies wrap.

To give a little background, the game starts with the player and one baddie. When the baddie is hit, it is destroyed and two more baddies are spawned. The initial baddie and the two baddies from the split WILL screen wrap. Any baddies beyond those two generations will NOT screen wrap.

Edit: I have just noticed the third generation + baddies also don’t rotate. It looks as though for some reason after the second generation the baddies stop using the Update function.

Edit 2: On testing it again this morning it’s not wrapping or rotating any of the baddie objects except the very first one. So none of the baddies instantiated as a result of a split are updating. I’m hugely confused. The edit I made yesterday was not incorrect. I tested it multiple times before making the edit.

using UnityEngine;
using System.Collections;

public class scriptBaddies : MonoBehaviour
{
	//inspector variables
	public GameObject goBaddies;
	public ParticleSystem explosion;
	
	//private variables
	private int pointValue;
	private float randSpinX;
	private float randSpinY;
	private float randSpinZ;
				
	
	// Use this for initialization
	void Start ()
	{

	}
	
	// Update is called once per frame
	void Update ()
	{
		ScreenWrap();
		Rotate();
	}
	
	void Awake()
	{
		//give our baddie a semi-random colour
		int randColour = Random.Range(0,10);
		
		switch(randColour)
		{
		case 0: renderer.material.color = Color.red; break;
		case 1: renderer.material.color = Color.red; break;
		case 2: renderer.material.color = Color.red; break;
		case 3: renderer.material.color = Color.red; break;
		case 4: renderer.material.color = Color.green; break;
		case 5: renderer.material.color = Color.green; break;
		case 6: renderer.material.color = Color.green; break;
		case 7: renderer.material.color = Color.blue; break;
		case 8: renderer.material.color = Color.blue; break;
		case 9: renderer.material.color = Color.yellow; break;
		}
		
		//give our baddie a point value based on its colour
		if(renderer.material.color == Color.red)
			pointValue = -10;
		
		if(renderer.material.color == Color.green)
			pointValue = 10;
		
		if(renderer.material.color == Color.blue)
			pointValue = 20;
		
		if(renderer.material.color == Color.yellow)
			pointValue = 30;
		
		
		//create random x/y coords
		float randPosX = Random.Range (-15.0f,15.0f);
		float randPosY = Random.Range (-10.0f,10.0f);
		
		//and make the baddie start at those coords
		transform.position = new Vector3(randPosX,randPosY,5);
		
		//create random values for initial push
		float randForceX = Random.Range (-50,50);
		float randForceY = Random.Range (-50,50);
		
		//give it a push
		rigidbody.AddForce(new Vector3(randForceX,randForceY,5));
		
		//create random values for spin
		randSpinX = Random.Range (-50,50);
		randSpinY = Random.Range (-50,50);
		randSpinZ = Random.Range (-50,50);
		
		//give it a spin
		transform.Rotate(randSpinX,randSpinY,randSpinZ);
	}
	
	void ScreenWrap()
	{
		if(transform.position.x < -15)
		{
			transform.position = new Vector3(15,transform.position.y,5);
		}
		if(transform.position.x > 15)
		{
			transform.position = new Vector3(-15,transform.position.y,5);
		}
		if(transform.position.y < -10)
		{
			transform.position = new Vector3(transform.position.x,10,5);
		}
		if(transform.position.y > 10)
		{
			transform.position = new Vector3(transform.position.x,-10,5);
		}
	}
	
	void Rotate()
	{
		transform.Rotate(randSpinX/10,randSpinY/10,randSpinZ/10);
	}
	
	void OnCollisionEnter(Collision collision)
	{
		if(collision.gameObject.tag == "player")
		{
			Destroy(gameObject);
			Instantiate(explosion, transform.position, transform.rotation);
			for(int i = 0; i < 2; i++)
			{
				Debug.Log ("Spawning new baddie.");
				Instantiate(goBaddies, new Vector3(16,11,5), transform.rotation);
			}
		}
	}
	
	public int GetMyPoints()
	{
		return pointValue;	
	}
}

using UnityEngine;
using System.Collections;

public class scriptPlayer : MonoBehaviour
{
	//inspector variables
	public int score;
	public AudioClip noise1;
	public AudioClip noise2;
	public AudioClip noise3;
	public scriptBaddies sBaddies;
	
	//private variables

	
	
	// Use this for initialization
	void Start ()
	{
		
	}
	
	// Update is called once per frame
	void Update ()
	{
		//call movement function
		Control();
		
		//call screen wrapping function
		ScreenWrap();
	}
	
	//function for moving the player via input
	void Control()
	{
		if(Input.GetKey(KeyCode.A))
		{
			rigidbody.AddForce(-3,0,0);
		}		
		if(Input.GetKey(KeyCode.D))
		{
			rigidbody.AddForce(3,0,0);
		}
		if(Input.GetKey(KeyCode.W))
		{
			rigidbody.AddForce(0,3,0);
		}
		if(Input.GetKey(KeyCode.S))
		{
			rigidbody.AddForce(0,-3,0);
		}
	}
	
	//function for wrapping player from left to right/top to bottom and vice versa
	void ScreenWrap()
	{
		if(transform.position.x < -15)
		{
			transform.position = new Vector3(15,transform.position.y,5);
		}
		if(transform.position.x > 15)
		{
			transform.position = new Vector3(-15,transform.position.y,5);
		}
		if(transform.position.y < -10)
		{
			transform.position = new Vector3(transform.position.x,10,5);
		}
		if(transform.position.y > 10)
		{
			transform.position = new Vector3(transform.position.x,-10,5);
		}
	}
	
	void OnCollisionEnter(Collision collision)
	{
		Debug.Log ("BANG!");
		sBaddies = collision.gameObject.GetComponent<scriptBaddies>();
		score += sBaddies.GetMyPoints();
		Debug.Log ("Gained: " +sBaddies.GetMyPoints());	//GetMyPoints is a function in scriptBaddies that returns the point value
		Debug.Log ("Total score: " + score);
	}
}

There are two things going on here to scupper you.

Firstly: there is an interesting “feature” of Unity when dealing with self referential prefabs. When instantiating a prefab that contains references to other gameObjects (including itself) within the same prefab hierarchy, Unity will cleverly update those references to point to the corresponding newly created scene instances during the instantiation process. This is incredibly useful when you are instantiating a complex prefab with child objects and so forth. However it is incredibly unhelpful when you want the property to stay pointing at the original prefab (as is the case in example). What is actually happening is that during the instantiate your Baddie object is having its goBaddies property (which originally pointed back at the prefab) updated to point to the newly created baddie in the scene. You can see this happening by naming the scene baddie and the prefab baddie different things, and then running the game and watching what happens to the goBaddie property on the scene baddies.

(If anyone knows a good workaround for this I’d desperately like to know. Ideally I’d like a [DontRemapValueDuringInstantiate] attribute that I could tag certain fields with and that Unity would honour, but I don’t think anything like this exists.)

Anyway, because of the above when you instantiate your two new baddies you are actually creating clones of the baddie in the scene rather than clones of the original prefab baddie, this brings us on to the second thing that is going wrong: You are calling Destroy(gameObject); on the current baddie BEFORE you are instantiating the two new ones. What I speculate is happening is that when you create the clones of the current baddie AFTER it has been destroyed whatever flag that marks that object as being destroyed is also being copied to the new baddies, and thus they don’t get their update called (because the engine erroneously thinks they are in the process of being destroyed).

The quick and easy fix is to not destroy the current gameObject until after you have created clones of it.

I’m afraid I don’t have a better fix for the inability to have a prefab reference itself and maintain the reference to the original prefab after it has been instantiated. That is something that only the Unity Devs could address.