More of Unity 3.4's flaws...

Apparently Start() is no longer performed first…

In my main script I have this:

function ShowValidity()
{
	var targetArea		: Rect = GetGridArea();
	var i	 			: int = 0;

	Debug.Log("Showing Validity for " + targetArea );
	for (var x : int = targetArea.x; x <= targetArea.width; x++)
	for (var y : int = targetArea.y; y <= targetArea.height; y++)
	{
		var GB : GridBlock = grid.Grid[x,y].GetComponent(GridBlock);
		posMarkers[i++] = Instantiate(Marker, GB.transform.position+ Vector3(0,0.01,0), Quaternion.identity);
		posMarkers[i-1].transform.localScale = Vector3(grid.blockWidth, 1, grid.blockHeight);
		posMarkers[i-1].gameObject.SendMessage("SetTexOffset", validPlacement ? 2 : 3);
	}
}

In my prefab I have this:

function Start()
{
	var m : Material = cursor.renderer.material;
	m.mainTextureScale	= Vector2(0.5, 0.5);
	m.mainTexture		= cursorTex;
	if (tex == 0)
	{
	  cursor.renderer.material.mainTextureOffset = Vector2(0.0,0.5);
	  Debug.Log("offset set to " + cursor.renderer.material.mainTextureOffset + " During init");
	}
}

function SetTexOffset(to : int)
{
	switch (to)
	{
		case  1: cursor.renderer.material.mainTextureOffset = Vector2(0.5,0.5); break;
		case  2: cursor.renderer.material.mainTextureOffset = Vector2(0.0,0.0); break;
		case  3: cursor.renderer.material.mainTextureOffset = Vector2(0.5,0.0); break;
		default: cursor.renderer.material.mainTextureOffset = Vector2(0.0,0.5); break;
	}
	Debug.Log("offset set to " + cursor.renderer.material.mainTextureOffset + " thanks to option " + to);
}

Just check the screenshot for the result this produces… Seems SendMessage is executed before Start()…

This is of course problem 2 I am having with this particular cursor. The first being that if I Instantiate the mesh inside the prefab, only the mesh instantiates, not the entire Prefab! Since when is THIS the case that only a portion of a prefab is instantiated? Has this always been so and it only took me 5 years to run into this event?

The prefab was created by taking an empty game object and dropping a mesh into it. I then added a script to the gameObject and created the prefab from that. Now, if I drag the mesh to my other script and tell it to instantiate that, the parent with the behaviour script doesn’t get instantiated so the default texture assignment doesn’t happen. On the other hand, if I instantiate the parent object then I have to follow that up with a “find the child object inside the instantiated object” before I can continue but I don’t like hardcoding “Find” statements with names of objects. Components are okay but not child gameObjects… That feels like a hack to me plus if I want to create more prefabs like this I will have to adapt the code per object. So instead I just send a message to the parent object and trust the message to reach the intended object. This it does, but it does so before the Start() function is called…

Just tonight I had a problem where I ran a game in the editor and it worked just fine. Then I built the project and tried playing it and nothing appeared onscreen…

This after yesterday’s issue with a scene with no camera attached, just OnGUI calls resulting in fast moving animated coloured noise on every pixel not covered by an OnGUI call…

This followed by a recent discovery that the web player’s loading screen when running online, this works perfectly on Safari on my iMac but in Safari for Windows and IE for Windows both, instead of the loading graphic overlapping the prior image, instead it just scales the previous image down while the other one gets scaled up resulting in the black “Loading…” and the blue “Loading…” images appearing next to each other…

Oh I pray for 3.4.1 to be released soon as 3.4 is truly the first version of Unity that I have wanted to uninstall since 1.5!

686184--24675--$Screen Shot 2011-09-11 at 22.36.18.jpg

I’m pretty sure the Instantiate result has always been that way.

Instantiate works for all UnityEngine.Object inheritting classes (which is most things in the API), and not just for instantiating prefabs. If it instantiated the root object, or GameObject that owns it, it would break it for all Instantiates outside of prefabs, for example cloning a texture or mesh to make a slight modification of the original while preserving the original. Instantiate works on any reference and clones that reference specifically. Instantiate will create what you told it to create and no more, asking it to create a mesh and expecting a GameObject structure would be very difficult to work with, as you would have to do some prediction as to what type of object it was going to create (say 2 objects were sharing that mesh, or 15 chained objects in a hierarchy referencing to that mesh).

As for start not occurring immediately, it always occurs directly before that MonoBehaviours first Update call, which is after the end of the function call that creates it, and often in the next actual frame. Awake() is the immediate, constructor replacement. Whereas Start() allows you to communicate with objects being made on the same frame, without worrying that one has not been created yet (meaning it HAS to be end of that frames functions. I had seen that since Unity 2.6 unless I’m mistaken

Wow! Too late at night for me to follow all of that… :stuck_out_tongue:

I will have to read this again when I wake up to see how your explanation compares with the documentation

…in all other instances where I instantiated prefabs, this behaved like I expected, except with this prefab, now…

p.s. regarding breaking other objects, remember, I am not trying to instantiate some random mesh, I am trying to instantiate a specific prefab that happens to contain a particular mesh also. I would expect that if I Instantiate a prefab, the entire prefab is instantiated. Perhaps you are right and I have lived with a false idea in my head and just happened to do the right thing by chance for the past 5 years. I know that sounds sarcastic, but seriously, I suppose it is possible… But regarding commands being executed before the Start function runs…, just answer me this:

where exactly does SendMessage fit into the above ? The say I understand you is like so:
The current Update function is running and instantiates a prefab with a Start() function. All commands in the current frame’s Update functions (but I take it NOT the commands in the new prefab’s Update function) are performed first (and this includes the SendMessage command). At the end of the current frame, the new prefab’s Start function is called and THEN all Updates occur as expected…

Do I have it right? So because the new Start function is created DURING an Update, all actions performed on the new object is performed before the Start()? So by placing all my code in the Awake function, does this mean that the Update commands will stop first and let the Awake function complete before the rest of the commands in the Update take effect on the new prefab?

See, here’s the thing:
I am trying to create a prefab that gets instantiated once and just does some basic setup. Then whenever the user clicks on a spot on the terrain, the cursor moves to there. Nothing else. Now, should another object be spawned, that object should also create the same cursor but then the init should be a little more involved and the prefab starts getting some behaviour also. Thus, since the setup of the same prefab is not the same, based on why/when/how it is created, it means I can’t just place all my init code in Awake. I have to place some separately to be called only if required. What combination of options is the best way to make sure that my conditional init code is always executed AFTER the first init code keeping in mind that the prefab is being called during an Update frame… Perhaps not using Start or Awake at all and just having Init1() and Init2() functions?

Just had another idea, just place a yield for 1 frame right after the Instantiate… Lots of options. Thing that bothers me is that I always held the firm belief that when I create an object, Awake happens first if present, then Start, always. Then, updates and whatever else and whatnot. I never knew it was possible for anything to be run before Start (apart from Awake) so now I am worried that the code in the Update might run before the Awake code also… ARgh… too confusing… I think I’ll just skip using them both and stick to initialising my prefabs manually… Just safer that way…

And on a lighter note, I just discovered a minor thing not really worth lodging an error report for so if anyone from Unity is reading this, on this page:

…the link to the next page doesn’t work. I assume it might have something to do with this:

…notice the “:”:slight_smile:

Ok so on Execution time I was wrong.

Running some tests, it highly depends on when ShowValidity() is called within the sequence. The Instantiated objects will have their Start() called at the end of that particular stage. In your case it will be at the end of that ShowValidity function + any other calls in LateUpdate, Update, Start, Awake that ShowValidity was called in.

A solution for that predicament could be to just initialize it the first time it’s needed

public class MyBehaviour : MonoBehaviour 
{
    bool isInitialized;
    bool Init()
    {
        //Do Stuff that was in Start here
        isInitialized = true;
    }

    void SetTexOffset(int to)
    {
        if (!isInitialized)
        {
            Init();
        }
        //Do the old stuff here
    }
}

This way it will always be initialized the first time you need it, and unless you have 1 000 000+ instances of this thing a single boolean check isn’t gonna be felt in performance. It also means, as you want to reuse it, you could turn isInitialized to false to invalidate it and force a reload if it needs something like that.

And as for the Instantiate information, I think the reason for those effects are that when cloning you need to copy all attributes. Monobehaviours have a property that links to a GameObjects, Transform has a property that links to it’s children, and GameObjects has internal variables to link to it’s components. Copying the object forces it to copy dependencies on that object such as it’s properties or internal variables. Copy a MeshRenderer, it’ll copy the mesh, because the MeshRenderer knows about the mesh. Copy a Mesh it won’t copy the MeshRenderer, because the Mesh doesn’t know about the MeshRenderer.

A solution to Having to Instantiate an Object and then find a specified child, would be to have the Awake() of the Prefab have a script that gets all the necessary parts, through Finds and GetComponents, but in a single, easily manageable way. Then the actual user of the prefab just needs to call GetComponent(). to get all the different parts of that prefab.

There are more technical solutions to these as well, but unless you are making thousands of these constantly neither should be any sort of performance hitm, and these are simple to implement/customise.

Although one thing that gets me on these is that, with a possible exception of the bottom 2, I don’t think any of these are new to 3.4, though Update order did get changed; Even before 3.4, Start() was not an instantaneous call, and that was it’s whole purpose.