- Home /
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);
}
}
Answer by tmcsweeney · Apr 22, 2013 at 06:08 AM
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.
Thanks $$anonymous$$r Sweeney! Instantiating first and destroying second worked like a charm!!